Bug 1036981 - Update HarfBuzz to upstream commit d5e6147 (0.9.34). r=jfkthame

This commit is contained in:
Birunthan Mohanathas 2014-08-03 10:03:46 -07:00
parent 228d194059
commit a2cc85f89e
93 changed files with 5033 additions and 5601 deletions

View File

@ -0,0 +1,9 @@
Behdad Esfahbod
Simon Hausmann
Martin Hosken
Jonathan Kew
Lars Knoll
Werner Lemberg
Roozbeh Pournader
Owen Taylor
David Turner

View File

@ -1,11 +1,16 @@
HarfBuzz is licensed under the so-called "Old MIT" license. Details follow. HarfBuzz is licensed under the so-called "Old MIT" license. Details follow.
For parts of HarfBuzz that are licensed under different licenses see individual
files names COPYING in subdirectories where applicable.
Copyright © 2011 Codethink Limited Copyright © 2010,2011,2012 Google, Inc.
Copyright © 2010,2011 Google, Inc. Copyright © 2012 Mozilla Foundation
Copyright © 2006 Behdad Esfahbod Copyright © 2011 Codethink Limited
Copyright © 2008,2010 Nokia Corporation and/or its subsidiary(-ies)
Copyright © 2009 Keith Stribley Copyright © 2009 Keith Stribley
Copyright © 2009 Martin Hosken and SIL International Copyright © 2009 Martin Hosken and SIL International
Copyright © 2007 Chris Wilson Copyright © 2007 Chris Wilson
Copyright © 2006 Behdad Esfahbod
Copyright © 2005 David Turner
Copyright © 2004,2007,2008,2009,2010 Red Hat, Inc. Copyright © 2004,2007,2008,2009,2010 Red Hat, Inc.
Copyright © 1998-2004 David Turner and Werner Lemberg Copyright © 1998-2004 David Turner and Werner Lemberg

View File

@ -35,6 +35,7 @@ HBSOURCES = \
hb-object-private.hh \ hb-object-private.hh \
hb-open-file-private.hh \ hb-open-file-private.hh \
hb-open-type-private.hh \ hb-open-type-private.hh \
hb-ot-cmap-table.hh \
hb-ot-head-table.hh \ hb-ot-head-table.hh \
hb-ot-hhea-table.hh \ hb-ot-hhea-table.hh \
hb-ot-hmtx-table.hh \ hb-ot-hmtx-table.hh \
@ -51,7 +52,6 @@ HBSOURCES = \
hb-shaper-impl-private.hh \ hb-shaper-impl-private.hh \
hb-shaper-private.hh \ hb-shaper-private.hh \
hb-shaper.cc \ hb-shaper.cc \
hb-tt-font.cc \
hb-unicode-private.hh \ hb-unicode-private.hh \
hb-unicode.cc \ hb-unicode.cc \
hb-utf-private.hh \ hb-utf-private.hh \
@ -76,6 +76,7 @@ HBNODISTHEADERS = \
if HAVE_OT if HAVE_OT
HBSOURCES += \ HBSOURCES += \
hb-ot-font.cc \
hb-ot-layout.cc \ hb-ot-layout.cc \
hb-ot-layout-common-private.hh \ hb-ot-layout-common-private.hh \
hb-ot-layout-gdef-table.hh \ hb-ot-layout-gdef-table.hh \
@ -90,6 +91,7 @@ HBSOURCES += \
hb-ot-shape-complex-arabic.cc \ hb-ot-shape-complex-arabic.cc \
hb-ot-shape-complex-arabic-fallback.hh \ hb-ot-shape-complex-arabic-fallback.hh \
hb-ot-shape-complex-arabic-table.hh \ hb-ot-shape-complex-arabic-table.hh \
hb-ot-shape-complex-arabic-win1256.hh \
hb-ot-shape-complex-default.cc \ hb-ot-shape-complex-default.cc \
hb-ot-shape-complex-hangul.cc \ hb-ot-shape-complex-hangul.cc \
hb-ot-shape-complex-hebrew.cc \ hb-ot-shape-complex-hebrew.cc \
@ -112,6 +114,7 @@ HBSOURCES += \
$(NULL) $(NULL)
HBHEADERS += \ HBHEADERS += \
hb-ot.h \ hb-ot.h \
hb-ot-font.h \
hb-ot-layout.h \ hb-ot-layout.h \
hb-ot-shape.h \ hb-ot-shape.h \
hb-ot-tag.h \ hb-ot-tag.h \
@ -279,13 +282,14 @@ indic-table: gen-indic-table.py IndicSyllabicCategory.txt IndicMatraCategory.txt
mv hb-ot-shape-complex-indic-table.cc.tmp $(srcdir)/hb-ot-shape-complex-indic-table.cc || \ mv hb-ot-shape-complex-indic-table.cc.tmp $(srcdir)/hb-ot-shape-complex-indic-table.cc || \
($(RM) hb-ot-shape-complex-indic-table.cc.tmp; false) ($(RM) hb-ot-shape-complex-indic-table.cc.tmp; false)
arabic-table: gen-arabic-table.py ArabicShaping.txt UnicodeData.txt arabic-table: gen-arabic-table.py ArabicShaping.txt UnicodeData.txt Blocks.txt
$(AM_V_GEN) $(builddir)/$^ > hb-ot-shape-complex-arabic-table.hh.tmp && \ $(AM_V_GEN) $(builddir)/$^ > hb-ot-shape-complex-arabic-table.hh.tmp && \
mv hb-ot-shape-complex-arabic-table.hh.tmp $(srcdir)/hb-ot-shape-complex-arabic-table.hh || \ mv hb-ot-shape-complex-arabic-table.hh.tmp $(srcdir)/hb-ot-shape-complex-arabic-table.hh || \
($(RM) hb-ot-shape-complex-arabic-table.hh.tmp; false) ($(RM) hb-ot-shape-complex-arabic-table.hh.tmp; false)
built-sources: $(BUILT_SOURCES)
.PHONY: unicode-tables arabic-table indic-table .PHONY: unicode-tables arabic-table indic-table built-sources
BUILT_SOURCES += \ BUILT_SOURCES += \
hb-buffer-deserialize-json.hh \ hb-buffer-deserialize-json.hh \
@ -302,7 +306,7 @@ EXTRA_DIST += \
hb-ot-shape-complex-sea-machine.rl \ hb-ot-shape-complex-sea-machine.rl \
$(NULL) $(NULL)
.rl.hh: .rl.hh:
$(AM_V_GEN)$(top_srcdir)/missing --run ragel -e -F1 -o "$@.tmp" "$<" && \ $(AM_V_GEN)$(RAGEL) -e -F1 -o "$@.tmp" "$<" && \
mv "$@.tmp" "$@" || ( $(RM) "$@.tmp" && false ) mv "$@.tmp" "$@" || ( $(RM) "$@.tmp" && false )
noinst_PROGRAMS = \ noinst_PROGRAMS = \
@ -358,6 +362,7 @@ if HAVE_INTROSPECTION
INTROSPECTION_GIRS = HarfBuzz-$(HB_VERSION_MAJOR).0.gir # What does the 0 mean anyway?! INTROSPECTION_GIRS = HarfBuzz-$(HB_VERSION_MAJOR).0.gir # What does the 0 mean anyway?!
INTROSPECTION_SCANNER_ARGS = -I$(srcdir) -n hb --identifier-prefix=hb_ --warn-all INTROSPECTION_SCANNER_ARGS = -I$(srcdir) -n hb --identifier-prefix=hb_ --warn-all
INTROSPECTION_COMPILER_ARGS = --includedir=$(srcdir) INTROSPECTION_COMPILER_ARGS = --includedir=$(srcdir)
INTROSPECTION_SCANNER_ENV = CC="$(CC)"
HarfBuzz-0.0.gir: libharfbuzz.la libharfbuzz-gobject.la HarfBuzz-0.0.gir: libharfbuzz.la libharfbuzz-gobject.la
HarfBuzz_0_0_gir_INCLUDES = GObject-2.0 HarfBuzz_0_0_gir_INCLUDES = GObject-2.0

View File

@ -1,40 +0,0 @@
#!/bin/sh
LC_ALL=C
export LC_ALL
test -z "$srcdir" && srcdir=.
test -z "$MAKE" && MAKE=make
stat=0
if which nm 2>/dev/null >/dev/null; then
:
else
echo "check-exported-symbols.sh: 'nm' not found; skipping test"
exit 77
fi
defs="harfbuzz.def"
$MAKE $defs > /dev/null
tested=false
for def in $defs; do
lib=`echo "$def" | sed 's/[.]def$//;s@.*/@@'`
so=.libs/lib${lib}.so
if test -f "$so"; then
echo "Checking that $so has the same symbol list as $def"
{
echo EXPORTS
nm "$so" | grep ' [BCDGINRSTVW] ' | grep -v ' T _fini\>\| T _init\>\| __bss_start\>\| __bss_start__\>\| __bss_end__\>\| _edata\>\| _end\>\| _bss_end__\>\| __end__\>' | cut -d' ' -f3
stat=1
# cheat: copy the last line from the def file!
tail -n1 "$def"
} | diff "$def" - >&2 || stat=1
tested=true
fi
done
if ! $tested; then
echo "check-exported-symbols.sh: libharfbuzz shared library not found; skipping test"
exit 77
fi
exit $stat

View File

@ -27,7 +27,7 @@ echo 'Checking that source files #include "hb-*private.hh" first (or none)'
for x in $HBSOURCES; do for x in $HBSOURCES; do
test -f "$srcdir/$x" && x="$srcdir/$x" test -f "$srcdir/$x" && x="$srcdir/$x"
grep '#.*\<include\>' "$x" /dev/null | head -n 1 grep '#.*\<include\>' "$x" /dev/null | grep -v 'include _' | head -n 1
done | done |
grep -v '"hb-.*private[.]hh"' | grep -v '"hb-.*private[.]hh"' |
grep -v 'hb-private[.]hh:' | grep -v 'hb-private[.]hh:' |

View File

@ -1,34 +0,0 @@
#!/bin/sh
LC_ALL=C
export LC_ALL
test -z "$srcdir" && srcdir=.
stat=0
if which nm 2>/dev/null >/dev/null; then
:
else
echo "check-internal-symbols.sh: 'nm' not found; skipping test"
exit 77
fi
tested=false
for suffix in .so; do
so=`echo .libs/libharfbuzz$suffix`
if test -f "$so"; then
echo "Checking that we are not exposing internal symbols"
if nm "$so" | grep ' [BCDGINRSTVW] ' | grep -v ' T _fini\>\| T _init\>\| T hb_\| __bss_start\>\| __bss_start__\>\| __bss_end__\>\| _edata\>\| _end\>\| _bss_end__\>\| __end__\>'; then
echo "Ouch, internal symbols exposed"
stat=1
fi
tested=true
fi
done
if ! $tested; then
echo "check-internal-symbols.sh: libharfbuzz shared library not found; skipping test"
exit 77
fi
exit $stat

View File

@ -30,7 +30,7 @@ done
echo "Checking that no object file has lazy static C++ constructors/destructors or other such stuff" echo "Checking that no object file has lazy static C++ constructors/destructors or other such stuff"
for obj in $OBJS; do for obj in $OBJS; do
if objdump -t "$obj" | grep '__c'; then if objdump -t "$obj" | grep '__cxa_'; then
echo "Ouch, $obj has lazy static C++ constructors/destructors or other such stuff" echo "Ouch, $obj has lazy static C++ constructors/destructors or other such stuff"
stat=1 stat=1
fi fi

View File

@ -18,7 +18,7 @@ echo "Checking that we are not exposing internal symbols"
tested=false tested=false
for so in `ls .libs/lib*.so .libs/lib*.dylib 2>/dev/null` ; do for so in `ls .libs/lib*.so .libs/lib*.dylib 2>/dev/null` ; do
EXPORTED_SYMBOLS="`nm "$so" | grep ' [BCDGINRSTVW] ' | grep -v ' _fini\>\| _init\>\| _fdata\>\| _ftext\>\| __bss_start\>\| __bss_start__\>\| __bss_end__\>\| _edata\>\| _end\>\| _bss_end__\>\| __end__\>' | cut -d' ' -f3`" EXPORTED_SYMBOLS="`nm "$so" | grep ' [BCDGINRSTVW] ' | grep -v ' _fini\>\| _init\>\| _fdata\>\| _ftext\>\| _fbss\>\| __bss_start\>\| __bss_start__\>\| __bss_end__\>\| _edata\>\| _end\>\| _bss_end__\>\| __end__\>' | cut -d' ' -f3`"
prefix=`basename "$so" | sed 's/libharfbuzz/hb/; s/-/_/g; s/[.].*//'` prefix=`basename "$so" | sed 's/libharfbuzz/hb/; s/-/_/g; s/[.].*//'`
echo "Processing $so" echo "Processing $so"

View File

@ -3,34 +3,48 @@
import sys import sys
import os.path import os.path
if len (sys.argv) != 3: if len (sys.argv) != 4:
print >>sys.stderr, "usage: ./gen-arabic-table.py ArabicShaping.txt UnicodeData.txt" print >>sys.stderr, "usage: ./gen-arabic-table.py ArabicShaping.txt UnicodeData.txt Blocks.txt"
sys.exit (1) sys.exit (1)
files = [file (x) for x in sys.argv[1:]] files = [file (x) for x in sys.argv[1:]]
headers = [[files[0].readline (), files[0].readline ()]] headers = [[files[0].readline (), files[0].readline ()], [files[2].readline (), files[2].readline ()]]
headers.append (["UnicodeData.txt does not have a header."]) headers.append (["UnicodeData.txt does not have a header."])
while files[0].readline ().find ('##################') < 0: while files[0].readline ().find ('##################') < 0:
pass pass
blocks = {}
def read_blocks(f):
global blocks
for line in f:
j = line.find ('#')
if j >= 0:
line = line[:j]
fields = [x.strip () for x in line.split (';')]
if len (fields) == 1:
continue
uu = fields[0].split ('..')
start = int (uu[0], 16)
if len (uu) == 1:
end = start
else:
end = int (uu[1], 16)
t = fields[1]
for u in range (start, end + 1):
blocks[u] = t
def print_joining_table(f): def print_joining_table(f):
print values = {}
print "static const uint8_t joining_table[] ="
print "{"
min_u = 0x110000
max_u = 0
num = 0
last = -1
block = ''
for line in f: for line in f:
if line[0] == '#': if line[0] == '#':
if line.find (" characters"):
block = line[2:].strip ()
continue continue
fields = [x.strip () for x in line.split (';')] fields = [x.strip () for x in line.split (';')]
@ -38,43 +52,100 @@ def print_joining_table(f):
continue continue
u = int (fields[0], 16) u = int (fields[0], 16)
if u == 0x200C or u == 0x200D:
continue
if u < last:
raise Exception ("Input data character not sorted", u)
min_u = min (min_u, u)
max_u = max (max_u, u)
num += 1
if block:
print "\n /* %s */\n" % block
block = ''
if last != -1:
last += 1
while last < u:
print " JOINING_TYPE_X, /* %04X */" % last
last += 1
else:
last = u
if fields[3] in ["ALAPH", "DALATH RISH"]: if fields[3] in ["ALAPH", "DALATH RISH"]:
value = "JOINING_GROUP_" + fields[3].replace(' ', '_') value = "JOINING_GROUP_" + fields[3].replace(' ', '_')
else: else:
value = "JOINING_TYPE_" + fields[2] value = "JOINING_TYPE_" + fields[2]
print " %s, /* %s */" % (value, '; '.join(fields)) values[u] = value
short_value = {}
for value in set([v for v in values.values()] + ['JOINING_TYPE_X']):
short = ''.join(x[0] for x in value.split('_')[2:])
assert short not in short_value.values()
short_value[value] = short
print print
print "};" for value,short in short_value.items():
print "#define %s %s" % (short, value)
uu = sorted(values.keys())
num = len(values)
all_blocks = set([blocks[u] for u in uu])
last = -100000
ranges = []
for u in uu:
if u - last <= 1+16*5:
ranges[-1][-1] = u
else:
ranges.append([u,u])
last = u
print print
print "#define JOINING_TABLE_FIRST 0x%04X" % min_u print "static const uint8_t joining_table[] ="
print "#define JOINING_TABLE_LAST 0x%04X" % max_u print "{"
last_block = None
offset = 0
for start,end in ranges:
print
print "#define joining_offset_0x%04xu %d" % (start, offset)
for u in range(start, end+1):
block = blocks.get(u, last_block)
value = values.get(u, "JOINING_TYPE_X")
if block != last_block or u == start:
if u != start:
print
if block in all_blocks:
print "\n /* %s */" % block
else:
print "\n /* FILLER */"
last_block = block
if u % 32 != 0:
print
print " /* %04X */" % (u//32*32), " " * (u % 32),
if u % 32 == 0:
print
print " /* %04X */ " % u,
sys.stdout.write("%s," % short_value[value])
print
offset += end - start + 1
print
occupancy = num * 100. / offset
print "}; /* Table items: %d; occupancy: %d%% */" % (offset, occupancy)
print print
occupancy = num * 100 / (max_u - min_u + 1) page_bits = 12;
# Maintain at least 40% occupancy in the table */ print
if occupancy < 40: print "static unsigned int"
raise Exception ("Table too sparse, please investigate: ", occupancy) print "joining_type (hb_codepoint_t u)"
print "{"
print " switch (u >> %d)" % page_bits
print " {"
pages = set([u>>page_bits for u in [s for s,e in ranges]+[e for s,e in ranges]])
for p in sorted(pages):
print " case 0x%0Xu:" % p
for (start,end) in ranges:
if p not in [start>>page_bits, end>>page_bits]: continue
offset = "joining_offset_0x%04xu" % start
print " if (hb_in_range (u, 0x%04Xu, 0x%04Xu)) return joining_table[u - 0x%04Xu + %s];" % (start, end, start, offset)
print " break;"
print ""
print " default:"
print " break;"
print " }"
print " return X;"
print "}"
print
for value,short in short_value.items():
print "#undef %s" % (short)
print
def print_shaping_table(f): def print_shaping_table(f):
@ -124,13 +195,13 @@ def print_shaping_table(f):
for u in range (min_u, max_u + 1): for u in range (min_u, max_u + 1):
s = [shapes[u][shape] if u in shapes and shape in shapes[u] else 0 s = [shapes[u][shape] if u in shapes and shape in shapes[u] else 0
for shape in ['initial', 'medial', 'final', 'isolated']] for shape in ['initial', 'medial', 'final', 'isolated']]
value = ', '.join ("0x%04X" % c for c in s) value = ', '.join ("0x%04Xu" % c for c in s)
print " {%s}, /* U+%04X %s */" % (value, u, names[u] if u in names else "") print " {%s}, /* U+%04X %s */" % (value, u, names[u] if u in names else "")
print "};" print "};"
print print
print "#define SHAPING_TABLE_FIRST 0x%04X" % min_u print "#define SHAPING_TABLE_FIRST 0x%04Xu" % min_u
print "#define SHAPING_TABLE_LAST 0x%04X" % max_u print "#define SHAPING_TABLE_LAST 0x%04Xu" % max_u
print print
ligas = {} ligas = {}
@ -160,9 +231,9 @@ def print_shaping_table(f):
keys.sort () keys.sort ()
for first in keys: for first in keys:
print " { 0x%04X, {" % (first) print " { 0x%04Xu, {" % (first)
for liga in ligas[first]: for liga in ligas[first]:
print " { 0x%04X, 0x%04X }, /* %s */" % (liga[0], liga[1], names[liga[1]]) print " { 0x%04Xu, 0x%04Xu }, /* %s */" % (liga[0], liga[1], names[liga[1]])
print " }}," print " }},"
print "};" print "};"
@ -174,7 +245,7 @@ print "/* == Start of generated table == */"
print "/*" print "/*"
print " * The following table is generated by running:" print " * The following table is generated by running:"
print " *" print " *"
print " * ./gen-arabic-table.py ArabicShaping.txt UnicodeData.txt" print " * ./gen-arabic-table.py ArabicShaping.txt UnicodeData.txt Blocks.txt"
print " *" print " *"
print " * on files with these headers:" print " * on files with these headers:"
print " *" print " *"
@ -187,6 +258,7 @@ print "#ifndef HB_OT_SHAPE_COMPLEX_ARABIC_TABLE_HH"
print "#define HB_OT_SHAPE_COMPLEX_ARABIC_TABLE_HH" print "#define HB_OT_SHAPE_COMPLEX_ARABIC_TABLE_HH"
print print
read_blocks (files[2])
print_joining_table (files[0]) print_joining_table (files[0])
print_shaping_table (files[1]) print_shaping_table (files[1])

View File

@ -6,11 +6,12 @@ if len (sys.argv) != 4:
print >>sys.stderr, "usage: ./gen-indic-table.py IndicSyllabicCategory.txt IndicMatraCategory.txt Blocks.txt" print >>sys.stderr, "usage: ./gen-indic-table.py IndicSyllabicCategory.txt IndicMatraCategory.txt Blocks.txt"
sys.exit (1) sys.exit (1)
BLACKLISTED_BLOCKS = ["Thai", "Lao", "Tibetan"]
files = [file (x) for x in sys.argv[1:]] files = [file (x) for x in sys.argv[1:]]
headers = [[f.readline () for i in range (2)] for f in files] headers = [[f.readline () for i in range (2)] for f in files]
blocks = {}
data = [{} for f in files] data = [{} for f in files]
values = [{} for f in files] values = [{} for f in files]
for i, f in enumerate (files): for i, f in enumerate (files):
@ -35,10 +36,7 @@ for i, f in enumerate (files):
for u in range (start, end + 1): for u in range (start, end + 1):
data[i][u] = t data[i][u] = t
values[i][t] = values[i].get (t, 0) + 1 values[i][t] = values[i].get (t, 0) + end - start + 1
if i == 2:
blocks[t] = (start, end)
# Merge data into one dict: # Merge data into one dict:
defaults = ('Other', 'Not_Applicable', 'No_Block') defaults = ('Other', 'Not_Applicable', 'No_Block')
@ -52,10 +50,15 @@ for i,d in enumerate (data):
if not u in combined: if not u in combined:
combined[u] = list (defaults) combined[u] = list (defaults)
combined[u][i] = v combined[u][i] = v
combined = {k:v for k,v in combined.items() if v[2] not in BLACKLISTED_BLOCKS}
data = combined data = combined
del combined del combined
num = len (data) num = len (data)
for u in [0x17CD, 0x17CE, 0x17CF, 0x17D0, 0x17D3]:
if data[u][0] == 'Other':
data[u][0] = "Vowel_Dependent"
# Move the outliers NO-BREAK SPACE and DOTTED CIRCLE out # Move the outliers NO-BREAK SPACE and DOTTED CIRCLE out
singles = {} singles = {}
for u in [0x00A0, 0x25CC]: for u in [0x00A0, 0x25CC]:
@ -81,6 +84,10 @@ print
# Shorten values # Shorten values
short = [{ short = [{
"Bindu": 'Bi', "Bindu": 'Bi',
"Cantillation_Mark": 'Ca',
"Joiner": 'ZWJ',
"Non_Joiner": 'ZWNJ',
"Number": 'Nd',
"Visarga": 'Vs', "Visarga": 'Vs',
"Vowel": 'Vo', "Vowel": 'Vo',
"Vowel_Dependent": 'M', "Vowel_Dependent": 'M',
@ -88,14 +95,14 @@ short = [{
},{ },{
"Not_Applicable": 'x', "Not_Applicable": 'x',
}] }]
all_shorts = [[],[]] all_shorts = [{},{}]
# Add some of the values, to make them more readable, and to avoid duplicates # Add some of the values, to make them more readable, and to avoid duplicates
for i in range (2): for i in range (2):
for v,s in short[i].items (): for v,s in short[i].items ():
all_shorts[i].append (s) all_shorts[i][s] = v
what = ["INDIC_SYLLABIC_CATEGORY", "INDIC_MATRA_CATEGORY"] what = ["INDIC_SYLLABIC_CATEGORY", "INDIC_MATRA_CATEGORY"]
what_short = ["ISC", "IMC"] what_short = ["ISC", "IMC"]
@ -110,8 +117,8 @@ for i in range (2):
else: else:
s = ''.join ([c for c in v_no_and if ord ('A') <= ord (c) <= ord ('Z')]) s = ''.join ([c for c in v_no_and if ord ('A') <= ord (c) <= ord ('Z')])
if s in all_shorts[i]: if s in all_shorts[i]:
raise Exception ("Duplicate short value alias", v, s) raise Exception ("Duplicate short value alias", v, all_shorts[i][s])
all_shorts[i].append (s) all_shorts[i][s] = v
short[i][v] = s short[i][v] = s
print "#define %s_%s %s_%s %s/* %3d chars; %s */" % \ print "#define %s_%s %s_%s %s/* %3d chars; %s */" % \
(what_short[i], s, what[i], v.upper (), \ (what_short[i], s, what[i], v.upper (), \
@ -124,11 +131,16 @@ print
total = 0 total = 0
used = 0 used = 0
last_block = None
def print_block (block, start, end, data): def print_block (block, start, end, data):
print global total, used, last_block
print if block and block != last_block:
print " /* %s (%04X..%04X) */" % (block, start, end) print
print
print " /* %s */" % block
num = 0 num = 0
assert start % 8 == 0
assert (end+1) % 8 == 0
for u in range (start, end+1): for u in range (start, end+1):
if u % 8 == 0: if u % 8 == 0:
print print
@ -138,14 +150,15 @@ def print_block (block, start, end, data):
d = data.get (u, defaults) d = data.get (u, defaults)
sys.stdout.write ("%9s" % ("_(%s,%s)," % (short[0][d[0]], short[1][d[1]]))) sys.stdout.write ("%9s" % ("_(%s,%s)," % (short[0][d[0]], short[1][d[1]])))
global total, used
total += end - start + 1 total += end - start + 1
used += num used += num
if block:
last_block = block
uu = data.keys () uu = data.keys ()
uu.sort () uu.sort ()
last = -1 last = -100000
num = 0 num = 0
offset = 0 offset = 0
starts = [] starts = []
@ -155,11 +168,16 @@ for u in uu:
if u <= last: if u <= last:
continue continue
block = data[u][2] block = data[u][2]
(start, end) = blocks[block]
start = u//8*8
end = start+1
while end in uu and block == data[end][2]:
end += 1
end = (end-1)//8*8 + 7
if start != last + 1: if start != last + 1:
if start - last <= 33: if start - last <= 1+16*3:
print_block ("FILLER", last+1, start-1, data) print_block (None, last+1, start-1, data)
last = start-1 last = start-1
else: else:
if last >= 0: if last >= 0:
@ -167,7 +185,7 @@ for u in uu:
offset += ends[-1] - starts[-1] offset += ends[-1] - starts[-1]
print print
print print
print "#define indic_offset_0x%04x %d" % (start, offset) print "#define indic_offset_0x%04xu %d" % (start, offset)
starts.append (start) starts.append (start)
print_block (block, start, end, data) print_block (block, start, end, data)
@ -176,19 +194,30 @@ ends.append (last + 1)
offset += ends[-1] - starts[-1] offset += ends[-1] - starts[-1]
print print
print print
print "#define indic_offset_total %d" % offset
print
occupancy = used * 100. / total occupancy = used * 100. / total
print "}; /* Table occupancy: %d%% */" % occupancy page_bits = 12
print "}; /* Table items: %d; occupancy: %d%% */" % (offset, occupancy)
print print
print "INDIC_TABLE_ELEMENT_TYPE" print "INDIC_TABLE_ELEMENT_TYPE"
print "hb_indic_get_categories (hb_codepoint_t u)" print "hb_indic_get_categories (hb_codepoint_t u)"
print "{" print "{"
for (start,end) in zip (starts, ends): print " switch (u >> %d)" % page_bits
offset = "indic_offset_0x%04x" % start print " {"
print " if (0x%04X <= u && u <= 0x%04X) return indic_table[u - 0x%04X + %s];" % (start, end, start, offset) pages = set([u>>page_bits for u in starts+ends+singles.keys()])
for u,d in singles.items (): for p in sorted(pages):
print " if (unlikely (u == 0x%04X)) return _(%s,%s);" % (u, short[0][d[0]], short[1][d[1]]) print " case 0x%0Xu:" % p
for (start,end) in zip (starts, ends):
if p not in [start>>page_bits, end>>page_bits]: continue
offset = "indic_offset_0x%04xu" % start
print " if (hb_in_range (u, 0x%04Xu, 0x%04Xu)) return indic_table[u - 0x%04Xu + %s];" % (start, end, start, offset)
for u,d in singles.items ():
if p != u>>page_bits: continue
print " if (unlikely (u == 0x%04Xu)) return _(%s,%s);" % (u, short[0][d[0]], short[1][d[1]])
print " break;"
print ""
print " default:"
print " break;"
print " }"
print " return _(x,x);" print " return _(x,x);"
print "}" print "}"
print print

View File

@ -44,21 +44,24 @@
#elif !defined(HB_NO_MT) && (defined(_WIN32) || defined(__CYGWIN__)) #elif !defined(HB_NO_MT) && (defined(_WIN32) || defined(__CYGWIN__))
#define WIN32_LEAN_AND_MEAN
#include <windows.h> #include <windows.h>
#if defined(__MINGW32__) && !defined(MemoryBarrier) /* MinGW has a convoluted history of supporting MemoryBarrier
* properly. As such, define a function to wrap the whole
* thing. */
static inline void _HBMemoryBarrier (void) { static inline void _HBMemoryBarrier (void) {
#if !defined(MemoryBarrier)
long dummy = 0; long dummy = 0;
InterlockedExchange (&dummy, 1); InterlockedExchange (&dummy, 1);
} #else
# define MemoryBarrier _HBMemoryBarrier MemoryBarrier ();
#endif #endif
}
typedef LONG hb_atomic_int_t; typedef LONG hb_atomic_int_t;
#define hb_atomic_int_add(AI, V) InterlockedExchangeAdd (&(AI), (V)) #define hb_atomic_int_add(AI, V) InterlockedExchangeAdd (&(AI), (V))
#define hb_atomic_ptr_get(P) (MemoryBarrier (), (void *) *(P)) #define hb_atomic_ptr_get(P) (_HBMemoryBarrier (), (void *) *(P))
#define hb_atomic_ptr_cmpexch(P,O,N) (InterlockedCompareExchangePointer ((void **) (P), (void *) (N), (void *) (O)) == (void *) (O)) #define hb_atomic_ptr_cmpexch(P,O,N) (InterlockedCompareExchangePointer ((void **) (P), (void *) (N), (void *) (O)) == (void *) (O))
@ -78,7 +81,7 @@ typedef int32_t hb_atomic_int_t;
#if (MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_4 || __IPHONE_VERSION_MIN_REQUIRED >= 20100) #if (MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_4 || __IPHONE_VERSION_MIN_REQUIRED >= 20100)
#define hb_atomic_ptr_cmpexch(P,O,N) OSAtomicCompareAndSwapPtrBarrier ((void *) (O), (void *) (N), (void **) (P)) #define hb_atomic_ptr_cmpexch(P,O,N) OSAtomicCompareAndSwapPtrBarrier ((void *) (O), (void *) (N), (void **) (P))
#else #else
#if __ppc64__ || __x86_64__ || __arm64__ #if __ppc64__ || __x86_64__ || __aarch64__
#define hb_atomic_ptr_cmpexch(P,O,N) OSAtomicCompareAndSwap64Barrier ((int64_t) (O), (int64_t) (N), (int64_t*) (P)) #define hb_atomic_ptr_cmpexch(P,O,N) OSAtomicCompareAndSwap64Barrier ((int64_t) (O), (int64_t) (N), (int64_t*) (P))
#else #else
#define hb_atomic_ptr_cmpexch(P,O,N) OSAtomicCompareAndSwap32Barrier ((int32_t) (O), (int32_t) (N), (int32_t*) (P)) #define hb_atomic_ptr_cmpexch(P,O,N) OSAtomicCompareAndSwap32Barrier ((int32_t) (O), (int32_t) (N), (int32_t*) (P))

View File

@ -25,7 +25,9 @@
*/ */
/* http://www.oracle.com/technetwork/articles/servers-storage-dev/standardheaderfiles-453865.html */ /* http://www.oracle.com/technetwork/articles/servers-storage-dev/standardheaderfiles-453865.html */
#ifndef _POSIX_C_SOURCE
#define _POSIX_C_SOURCE 199309L #define _POSIX_C_SOURCE 199309L
#endif
#include "hb-private.hh" #include "hb-private.hh"

View File

@ -47,14 +47,13 @@ HB_BEGIN_DECLS
* - Use MODE_READONLY otherse, unless you really really * - Use MODE_READONLY otherse, unless you really really
* really know what you are doing, * really know what you are doing,
* *
* - MODE_WRITABLE is appropriate if you relaly made a * - MODE_WRITABLE is appropriate if you really made a
* copy of data solely for the purpose of passing to * copy of data solely for the purpose of passing to
* HarfBuzz and doing that just once (no reuse!), * HarfBuzz and doing that just once (no reuse!),
* *
* - If the font is mmap()ed, it's ok to use * - If the font is mmap()ed, it's ok to use
* READONLY_MAY_MAKE_WRITABLE, however, there were * READONLY_MAY_MAKE_WRITABLE, however, using that mode
* design problems with that mode, so HarfBuzz do not * correctly is very tricky. Use MODE_READONLY instead.
* really use it anymore. If not sure, use MODE_READONLY.
*/ */
typedef enum { typedef enum {
HB_MEMORY_MODE_DUPLICATE, HB_MEMORY_MODE_DUPLICATE,

View File

@ -52,6 +52,7 @@ struct hb_buffer_t {
hb_unicode_funcs_t *unicode; /* Unicode functions */ hb_unicode_funcs_t *unicode; /* Unicode functions */
hb_segment_properties_t props; /* Script, language, direction */ hb_segment_properties_t props; /* Script, language, direction */
hb_buffer_flags_t flags; /* BOT / EOT / etc. */ hb_buffer_flags_t flags; /* BOT / EOT / etc. */
hb_codepoint_t replacement; /* U+FFFD or something else. */
/* Buffer contents */ /* Buffer contents */

View File

@ -63,7 +63,7 @@ hb_buffer_serialize_format_t
hb_buffer_serialize_format_from_string (const char *str, int len) hb_buffer_serialize_format_from_string (const char *str, int len)
{ {
/* Upper-case it. */ /* Upper-case it. */
return (hb_buffer_serialize_format_t) (hb_tag_from_string (str, len) & ~0x20202020); return (hb_buffer_serialize_format_t) (hb_tag_from_string (str, len) & ~0x20202020u);
} }
/** /**

View File

@ -178,6 +178,7 @@ hb_buffer_t::reset (void)
hb_unicode_funcs_destroy (unicode); hb_unicode_funcs_destroy (unicode);
unicode = hb_unicode_funcs_get_default (); unicode = hb_unicode_funcs_get_default ();
replacement = HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT;
clear (); clear ();
} }
@ -500,6 +501,10 @@ void
hb_buffer_t::merge_clusters (unsigned int start, hb_buffer_t::merge_clusters (unsigned int start,
unsigned int end) unsigned int end)
{ {
#ifdef HB_NO_MERGE_CLUSTERS
return;
#endif
if (unlikely (end - start < 2)) if (unlikely (end - start < 2))
return; return;
@ -528,6 +533,10 @@ void
hb_buffer_t::merge_out_clusters (unsigned int start, hb_buffer_t::merge_out_clusters (unsigned int start,
unsigned int end) unsigned int end)
{ {
#ifdef HB_NO_MERGE_CLUSTERS
return;
#endif
if (unlikely (end - start < 2)) if (unlikely (end - start < 2))
return; return;
@ -695,6 +704,7 @@ hb_buffer_get_empty (void)
const_cast<hb_unicode_funcs_t *> (&_hb_unicode_funcs_nil), const_cast<hb_unicode_funcs_t *> (&_hb_unicode_funcs_nil),
HB_SEGMENT_PROPERTIES_DEFAULT, HB_SEGMENT_PROPERTIES_DEFAULT,
HB_BUFFER_FLAG_DEFAULT, HB_BUFFER_FLAG_DEFAULT,
HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT,
HB_BUFFER_CONTENT_TYPE_INVALID, HB_BUFFER_CONTENT_TYPE_INVALID,
true, /* in_error */ true, /* in_error */
@ -1039,6 +1049,42 @@ hb_buffer_get_flags (hb_buffer_t *buffer)
} }
/**
* hb_buffer_set_replacement_codepoint:
* @buffer: a buffer.
* @replacement:
*
*
*
* Since: 1.0
**/
void
hb_buffer_set_replacement_codepoint (hb_buffer_t *buffer,
hb_codepoint_t replacement)
{
if (unlikely (hb_object_is_inert (buffer)))
return;
buffer->replacement = replacement;
}
/**
* hb_buffer_get_replacement_codepoint:
* @buffer: a buffer.
*
*
*
* Return value:
*
* Since: 1.0
**/
hb_codepoint_t
hb_buffer_get_replacement_codepoint (hb_buffer_t *buffer)
{
return buffer->replacement;
}
/** /**
* hb_buffer_reset: * hb_buffer_reset:
* @buffer: a buffer. * @buffer: a buffer.
@ -1282,7 +1328,7 @@ hb_buffer_guess_segment_properties (hb_buffer_t *buffer)
buffer->guess_segment_properties (); buffer->guess_segment_properties ();
} }
template <typename T> template <bool validate, typename T>
static inline void static inline void
hb_buffer_add_utf (hb_buffer_t *buffer, hb_buffer_add_utf (hb_buffer_t *buffer,
const T *text, const T *text,
@ -1290,6 +1336,9 @@ hb_buffer_add_utf (hb_buffer_t *buffer,
unsigned int item_offset, unsigned int item_offset,
int item_length) int item_length)
{ {
typedef hb_utf_t<T, true> utf_t;
const hb_codepoint_t replacement = buffer->replacement;
assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE || assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE ||
(!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID)); (!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID));
@ -1297,7 +1346,7 @@ hb_buffer_add_utf (hb_buffer_t *buffer,
return; return;
if (text_length == -1) if (text_length == -1)
text_length = hb_utf_strlen (text); text_length = utf_t::strlen (text);
if (item_length == -1) if (item_length == -1)
item_length = text_length - item_offset; item_length = text_length - item_offset;
@ -1320,7 +1369,7 @@ hb_buffer_add_utf (hb_buffer_t *buffer,
while (start < prev && buffer->context_len[0] < buffer->CONTEXT_LENGTH) while (start < prev && buffer->context_len[0] < buffer->CONTEXT_LENGTH)
{ {
hb_codepoint_t u; hb_codepoint_t u;
prev = hb_utf_prev (prev, start, &u); prev = utf_t::prev (prev, start, &u, replacement);
buffer->context[0][buffer->context_len[0]++] = u; buffer->context[0][buffer->context_len[0]++] = u;
} }
} }
@ -1331,7 +1380,7 @@ hb_buffer_add_utf (hb_buffer_t *buffer,
{ {
hb_codepoint_t u; hb_codepoint_t u;
const T *old_next = next; const T *old_next = next;
next = hb_utf_next (next, end, &u); next = utf_t::next (next, end, &u, replacement);
buffer->add (u, old_next - (const T *) text); buffer->add (u, old_next - (const T *) text);
} }
@ -1341,7 +1390,7 @@ hb_buffer_add_utf (hb_buffer_t *buffer,
while (next < end && buffer->context_len[1] < buffer->CONTEXT_LENGTH) while (next < end && buffer->context_len[1] < buffer->CONTEXT_LENGTH)
{ {
hb_codepoint_t u; hb_codepoint_t u;
next = hb_utf_next (next, end, &u); next = utf_t::next (next, end, &u, replacement);
buffer->context[1][buffer->context_len[1]++] = u; buffer->context[1][buffer->context_len[1]++] = u;
} }
@ -1367,7 +1416,7 @@ hb_buffer_add_utf8 (hb_buffer_t *buffer,
unsigned int item_offset, unsigned int item_offset,
int item_length) int item_length)
{ {
hb_buffer_add_utf (buffer, (const uint8_t *) text, text_length, item_offset, item_length); hb_buffer_add_utf<true> (buffer, (const uint8_t *) text, text_length, item_offset, item_length);
} }
/** /**
@ -1389,7 +1438,7 @@ hb_buffer_add_utf16 (hb_buffer_t *buffer,
unsigned int item_offset, unsigned int item_offset,
int item_length) int item_length)
{ {
hb_buffer_add_utf (buffer, text, text_length, item_offset, item_length); hb_buffer_add_utf<true> (buffer, text, text_length, item_offset, item_length);
} }
/** /**
@ -1411,7 +1460,29 @@ hb_buffer_add_utf32 (hb_buffer_t *buffer,
unsigned int item_offset, unsigned int item_offset,
int item_length) int item_length)
{ {
hb_buffer_add_utf (buffer, text, text_length, item_offset, item_length); hb_buffer_add_utf<true> (buffer, text, text_length, item_offset, item_length);
}
/**
* hb_buffer_add_codepoints:
* @buffer: a buffer.
* @text: (array length=text_length):
* @text_length:
* @item_offset:
* @item_length:
*
*
*
* Since: 1.0
**/
void
hb_buffer_add_codepoints (hb_buffer_t *buffer,
const hb_codepoint_t *text,
int text_length,
unsigned int item_offset,
int item_length)
{
hb_buffer_add_utf<false> (buffer, text, text_length, item_offset, item_length);
} }

View File

@ -186,12 +186,25 @@ hb_buffer_flags_t
hb_buffer_get_flags (hb_buffer_t *buffer); hb_buffer_get_flags (hb_buffer_t *buffer);
#define HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT 0xFFFDu
/* Sets codepoint used to replace invalid UTF-8/16/32 entries.
* Default is 0xFFFDu. */
void
hb_buffer_set_replacement_codepoint (hb_buffer_t *buffer,
hb_codepoint_t replacement);
hb_codepoint_t
hb_buffer_get_replacement_codepoint (hb_buffer_t *buffer);
/* Resets the buffer. Afterwards it's as if it was just created, /* Resets the buffer. Afterwards it's as if it was just created,
* except that it has a larger buffer allocated perhaps... */ * except that it has a larger buffer allocated perhaps... */
void void
hb_buffer_reset (hb_buffer_t *buffer); hb_buffer_reset (hb_buffer_t *buffer);
/* Like reset, but does NOT clear unicode_funcs. */ /* Like reset, but does NOT clear unicode_funcs and replacement_codepoint. */
void void
hb_buffer_clear_contents (hb_buffer_t *buffer); hb_buffer_clear_contents (hb_buffer_t *buffer);
@ -240,6 +253,14 @@ hb_buffer_add_utf32 (hb_buffer_t *buffer,
unsigned int item_offset, unsigned int item_offset,
int item_length); int item_length);
/* Like add_utf32 but does NOT check for invalid Unicode codepoints. */
void
hb_buffer_add_codepoints (hb_buffer_t *buffer,
const hb_codepoint_t *text,
int text_length,
unsigned int item_offset,
int item_length);
/* Clears any new items added at the end */ /* Clears any new items added at the end */
hb_bool_t hb_bool_t

View File

@ -299,9 +299,11 @@ hb_language_from_string (const char *str, int len)
if (len >= 0) if (len >= 0)
{ {
/* NUL-terminate it. */
len = MIN (len, (int) sizeof (strbuf) - 1); len = MIN (len, (int) sizeof (strbuf) - 1);
str = (char *) memcpy (strbuf, str, len); memcpy (strbuf, str, len);
strbuf[len] = '\0'; strbuf[len] = '\0';
str = strbuf;
} }
hb_language_item_t *item = lang_find_or_insert (str); hb_language_item_t *item = lang_find_or_insert (str);
@ -369,7 +371,7 @@ hb_script_from_iso15924_tag (hb_tag_t tag)
return HB_SCRIPT_INVALID; return HB_SCRIPT_INVALID;
/* Be lenient, adjust case (one capital letter followed by three small letters) */ /* Be lenient, adjust case (one capital letter followed by three small letters) */
tag = (tag & 0xDFDFDFDF) | 0x00202020; tag = (tag & 0xDFDFDFDFu) | 0x00202020u;
switch (tag) { switch (tag) {
@ -389,7 +391,7 @@ hb_script_from_iso15924_tag (hb_tag_t tag)
} }
/* If it looks right, just use the tag as a script */ /* If it looks right, just use the tag as a script */
if (((uint32_t) tag & 0xE0E0E0E0) == 0x40606060) if (((uint32_t) tag & 0xE0E0E0E0u) == 0x40606060u)
return (hb_script_t) tag; return (hb_script_t) tag;
/* Otherwise, return unknown */ /* Otherwise, return unknown */
@ -482,6 +484,14 @@ hb_script_get_horizontal_direction (hb_script_t script)
case HB_SCRIPT_MEROITIC_CURSIVE: case HB_SCRIPT_MEROITIC_CURSIVE:
case HB_SCRIPT_MEROITIC_HIEROGLYPHS: case HB_SCRIPT_MEROITIC_HIEROGLYPHS:
/* Unicode-7.0 additions */
case HB_SCRIPT_MANICHAEAN:
case HB_SCRIPT_MENDE_KIKAKUI:
case HB_SCRIPT_NABATAEAN:
case HB_SCRIPT_OLD_NORTH_ARABIAN:
case HB_SCRIPT_PALMYRENE:
case HB_SCRIPT_PSALTER_PAHLAVI:
return HB_DIRECTION_RTL; return HB_DIRECTION_RTL;
} }
@ -559,7 +569,7 @@ hb_version_string (void)
} }
/** /**
* hb_version_check: * hb_version_atleast:
* @major: * @major:
* @minor: * @minor:
* @micro: * @micro:
@ -571,9 +581,9 @@ hb_version_string (void)
* Since: 1.0 * Since: 1.0
**/ **/
hb_bool_t hb_bool_t
hb_version_check (unsigned int major, hb_version_atleast (unsigned int major,
unsigned int minor, unsigned int minor,
unsigned int micro) unsigned int micro)
{ {
return HB_VERSION_CHECK (major, minor, micro); return HB_VERSION_ATLEAST (major, minor, micro);
} }

View File

@ -95,6 +95,7 @@ typedef uint32_t hb_tag_t;
#define HB_TAG_NONE HB_TAG(0,0,0,0) #define HB_TAG_NONE HB_TAG(0,0,0,0)
#define HB_TAG_MAX HB_TAG(0xff,0xff,0xff,0xff) #define HB_TAG_MAX HB_TAG(0xff,0xff,0xff,0xff)
#define HB_TAG_MAX_SIGNED HB_TAG(0x7f,0xff,0xff,0xff)
/* len=-1 means str is NUL-terminated. */ /* len=-1 means str is NUL-terminated. */
hb_tag_t hb_tag_t
@ -270,17 +271,6 @@ typedef enum
/*6.1*/ HB_SCRIPT_SORA_SOMPENG = HB_TAG ('S','o','r','a'), /*6.1*/ HB_SCRIPT_SORA_SOMPENG = HB_TAG ('S','o','r','a'),
/*6.1*/ HB_SCRIPT_TAKRI = HB_TAG ('T','a','k','r'), /*6.1*/ HB_SCRIPT_TAKRI = HB_TAG ('T','a','k','r'),
/* No script set. */
/*---*/ HB_SCRIPT_INVALID = HB_TAG_NONE,
/* Dummy value to ensure any hb_tag_t value can be passed/stored as hb_script_t
* without risking undefined behavior. */
/*---*/ _HB_SCRIPT_MAX_VALUE = HB_TAG_MAX
} hb_script_t;
/* These are moved out of hb_script_t because glib-mkenums chokes otherwise. */
#if 0
/*7.0*/ HB_SCRIPT_BASSA_VAH = HB_TAG ('B','a','s','s'), /*7.0*/ HB_SCRIPT_BASSA_VAH = HB_TAG ('B','a','s','s'),
/*7.0*/ HB_SCRIPT_CAUCASIAN_ALBANIAN = HB_TAG ('A','g','h','b'), /*7.0*/ HB_SCRIPT_CAUCASIAN_ALBANIAN = HB_TAG ('A','g','h','b'),
/*7.0*/ HB_SCRIPT_DUPLOYAN = HB_TAG ('D','u','p','l'), /*7.0*/ HB_SCRIPT_DUPLOYAN = HB_TAG ('D','u','p','l'),
@ -292,19 +282,33 @@ typedef enum
/*7.0*/ HB_SCRIPT_MAHAJANI = HB_TAG ('M','a','h','j'), /*7.0*/ HB_SCRIPT_MAHAJANI = HB_TAG ('M','a','h','j'),
/*7.0*/ HB_SCRIPT_MANICHAEAN = HB_TAG ('M','a','n','i'), /*7.0*/ HB_SCRIPT_MANICHAEAN = HB_TAG ('M','a','n','i'),
/*7.0*/ HB_SCRIPT_MENDE_KIKAKUI = HB_TAG ('M','e','n','d'), /*7.0*/ HB_SCRIPT_MENDE_KIKAKUI = HB_TAG ('M','e','n','d'),
/*7.0*/ HB_SCRIPT_MODI = ??? /*7.0*/ HB_SCRIPT_MODI = HB_TAG ('M','o','d','i'),
/*7.0*/ HB_SCRIPT_MRO = HB_TAG ('M','r','o','o'), /*7.0*/ HB_SCRIPT_MRO = HB_TAG ('M','r','o','o'),
/*7.0*/ HB_SCRIPT_NABATAEAN = HB_TAG ('N','b','a','t'), /*7.0*/ HB_SCRIPT_NABATAEAN = HB_TAG ('N','b','a','t'),
/*7.0*/ HB_SCRIPT_OLD_NORTH_ARABIAN = HB_TAG ('N','a','r','b'), /*7.0*/ HB_SCRIPT_OLD_NORTH_ARABIAN = HB_TAG ('N','a','r','b'),
/*7.0*/ HB_SCRIPT_OLD_PERMIC = HB_TAG ('P','e','r','m'), /*7.0*/ HB_SCRIPT_OLD_PERMIC = HB_TAG ('P','e','r','m'),
/*7.0*/ HB_SCRIPT_PAHAWH_HMONG = HB_TAG ('H','m','n','g'), /*7.0*/ HB_SCRIPT_PAHAWH_HMONG = HB_TAG ('H','m','n','g'),
/*7.0*/ HB_SCRIPT_PALMYRENE = HB_TAG ('P','a','l','m'), /*7.0*/ HB_SCRIPT_PALMYRENE = HB_TAG ('P','a','l','m'),
/*7.0*/ HB_SCRIPT_PAU_CIN_HAU = ??? /*7.0*/ HB_SCRIPT_PAU_CIN_HAU = HB_TAG ('P','a','u','c'),
/*7.0*/ HB_SCRIPT_PSALTER_PAHLAVI = HB_TAG ('P','h','l','p'), /*7.0*/ HB_SCRIPT_PSALTER_PAHLAVI = HB_TAG ('P','h','l','p'),
/*7.0*/ HB_SCRIPT_SIDDHAM = ??? /*7.0*/ HB_SCRIPT_SIDDHAM = HB_TAG ('S','i','d','d'),
/*7.0*/ HB_SCRIPT_TIRHUTA = HB_TAG ('T','i','r','h'), /*7.0*/ HB_SCRIPT_TIRHUTA = HB_TAG ('T','i','r','h'),
/*7.0*/ HB_SCRIPT_WARANG_CITI = HB_TAG ('W','a','r','a'), /*7.0*/ HB_SCRIPT_WARANG_CITI = HB_TAG ('W','a','r','a'),
#endif
/* No script set. */
HB_SCRIPT_INVALID = HB_TAG_NONE,
/* Dummy values to ensure any hb_tag_t value can be passed/stored as hb_script_t
* without risking undefined behavior. Include both a signed and unsigned max,
* since technically enums are int, and indeed, hb_script_t ends up being signed.
* See this thread for technicalities:
*
* http://lists.freedesktop.org/archives/harfbuzz/2014-March/004150.html
*/
_HB_SCRIPT_MAX_VALUE = HB_TAG_MAX, /*< skip >*/
_HB_SCRIPT_MAX_VALUE_SIGNED = HB_TAG_MAX_SIGNED /*< skip >*/
} hb_script_t;
/* Script functions */ /* Script functions */
@ -312,7 +316,7 @@ typedef enum
hb_script_t hb_script_t
hb_script_from_iso15924_tag (hb_tag_t tag); hb_script_from_iso15924_tag (hb_tag_t tag);
/* suger for tag_from_string() then script_from_iso15924_tag */ /* sugar for tag_from_string() then script_from_iso15924_tag */
/* len=-1 means s is NUL-terminated */ /* len=-1 means s is NUL-terminated */
hb_script_t hb_script_t
hb_script_from_string (const char *s, int len); hb_script_from_string (const char *s, int len);

View File

@ -37,6 +37,38 @@
#endif #endif
static void
release_table_data (void *user_data)
{
CFDataRef cf_data = reinterpret_cast<CFDataRef> (user_data);
CFRelease(cf_data);
}
static hb_blob_t *
reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
{
CGFontRef cg_font = reinterpret_cast<CGFontRef> (user_data);
CFDataRef cf_data = CGFontCopyTableForTag (cg_font, tag);
if (unlikely (!cf_data))
return NULL;
const char *data = reinterpret_cast<const char*> (CFDataGetBytePtr (cf_data));
const size_t length = CFDataGetLength (cf_data);
if (!data || !length)
return NULL;
return hb_blob_create (data, length, HB_MEMORY_MODE_READONLY,
reinterpret_cast<void *> (const_cast<__CFData *> (cf_data)),
release_table_data);
}
hb_face_t *
hb_coretext_face_create (CGFontRef cg_font)
{
return hb_face_create_for_tables (reference_table, CGFontRetain (cg_font), (hb_destroy_func_t) CGFontRelease);
}
HB_SHAPER_DATA_ENSURE_DECLARE(coretext, face) HB_SHAPER_DATA_ENSURE_DECLARE(coretext, face)
HB_SHAPER_DATA_ENSURE_DECLARE(coretext, font) HB_SHAPER_DATA_ENSURE_DECLARE(coretext, font)
@ -65,15 +97,22 @@ _hb_coretext_shaper_face_data_create (hb_face_t *face)
if (unlikely (!data)) if (unlikely (!data))
return NULL; return NULL;
hb_blob_t *blob = hb_face_reference_blob (face); if (face->destroy == (hb_destroy_func_t) CGFontRelease)
unsigned int blob_length; {
const char *blob_data = hb_blob_get_data (blob, &blob_length); data->cg_font = CGFontRetain ((CGFontRef) face->user_data);
if (unlikely (!blob_length)) }
DEBUG_MSG (CORETEXT, face, "Face has empty blob"); else
{
hb_blob_t *blob = hb_face_reference_blob (face);
unsigned int blob_length;
const char *blob_data = hb_blob_get_data (blob, &blob_length);
if (unlikely (!blob_length))
DEBUG_MSG (CORETEXT, face, "Face has empty blob");
CGDataProviderRef provider = CGDataProviderCreateWithData (blob, blob_data, blob_length, &release_data); CGDataProviderRef provider = CGDataProviderCreateWithData (blob, blob_data, blob_length, &release_data);
data->cg_font = CGFontCreateWithDataProvider (provider); data->cg_font = CGFontCreateWithDataProvider (provider);
CGDataProviderRelease (provider); CGDataProviderRelease (provider);
}
if (unlikely (!data->cg_font)) { if (unlikely (!data->cg_font)) {
DEBUG_MSG (CORETEXT, face, "Face CGFontCreateWithDataProvider() failed"); DEBUG_MSG (CORETEXT, face, "Face CGFontCreateWithDataProvider() failed");
@ -438,7 +477,7 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan,
event->start = false; event->start = false;
event->feature = feature; event->feature = feature;
} }
feature_events.sort (); feature_events.qsort ();
/* Add a strategic final event. */ /* Add a strategic final event. */
{ {
active_feature_t feature; active_feature_t feature;
@ -468,14 +507,12 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan,
if (unlikely (!range)) if (unlikely (!range))
goto fail_features; goto fail_features;
unsigned int offset = feature_records.len;
if (active_features.len) if (active_features.len)
{ {
CFMutableArrayRef features_array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); CFMutableArrayRef features_array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
/* TODO sort and resolve conflicting features? */ /* TODO sort and resolve conflicting features? */
/* active_features.sort (); */ /* active_features.qsort (); */
for (unsigned int j = 0; j < active_features.len; j++) for (unsigned int j = 0; j < active_features.len; j++)
{ {
CFStringRef keys[2] = { CFStringRef keys[2] = {
@ -573,13 +610,13 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan,
for (unsigned int i = 0; i < buffer->len; i++) { for (unsigned int i = 0; i < buffer->len; i++) {
hb_codepoint_t c = buffer->info[i].codepoint; hb_codepoint_t c = buffer->info[i].codepoint;
buffer->info[i].utf16_index() = chars_len; buffer->info[i].utf16_index() = chars_len;
if (likely (c < 0x10000)) if (likely (c <= 0xFFFFu))
pchars[chars_len++] = c; pchars[chars_len++] = c;
else if (unlikely (c >= 0x110000)) else if (unlikely (c > 0x10FFFFu))
pchars[chars_len++] = 0xFFFD; pchars[chars_len++] = 0xFFFDu;
else { else {
pchars[chars_len++] = 0xD800 + ((c - 0x10000) >> 10); pchars[chars_len++] = 0xD800u + ((c - 0x10000u) >> 10);
pchars[chars_len++] = 0xDC00 + ((c - 0x10000) & ((1 << 10) - 1)); pchars[chars_len++] = 0xDC00u + ((c - 0x10000u) & ((1 << 10) - 1));
} }
} }
@ -605,7 +642,7 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan,
hb_codepoint_t c = buffer->info[i].codepoint; hb_codepoint_t c = buffer->info[i].codepoint;
unsigned int cluster = buffer->info[i].cluster; unsigned int cluster = buffer->info[i].cluster;
log_clusters[chars_len++] = cluster; log_clusters[chars_len++] = cluster;
if (c >= 0x10000 && c < 0x110000) if (hb_in_range (c, 0x10000u, 0x10FFFFu))
log_clusters[chars_len++] = cluster; /* Surrogates. */ log_clusters[chars_len++] = cluster; /* Surrogates. */
} }
@ -677,10 +714,10 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan,
for (CFIndex j = range.location; j < range.location + range.length; j++) for (CFIndex j = range.location; j < range.location + range.length; j++)
{ {
UniChar ch = CFStringGetCharacterAtIndex (string_ref, j); UniChar ch = CFStringGetCharacterAtIndex (string_ref, j);
if (hb_in_range<UniChar> (ch, 0xDC00, 0xDFFF) && range.location < j) if (hb_in_range<UniChar> (ch, 0xDC00u, 0xDFFFu) && range.location < j)
{ {
ch = CFStringGetCharacterAtIndex (string_ref, j - 1); ch = CFStringGetCharacterAtIndex (string_ref, j - 1);
if (hb_in_range<UniChar> (ch, 0xD800, 0xDBFF)) if (hb_in_range<UniChar> (ch, 0xD800u, 0xDBFFu))
/* This is the second of a surrogate pair. Don't need .notdef /* This is the second of a surrogate pair. Don't need .notdef
* for this one. */ * for this one. */
continue; continue;
@ -810,3 +847,97 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan,
return true; return true;
} }
/*
* AAT shaper
*/
HB_SHAPER_DATA_ENSURE_DECLARE(coretext_aat, face)
HB_SHAPER_DATA_ENSURE_DECLARE(coretext_aat, font)
/*
* shaper face data
*/
struct hb_coretext_aat_shaper_face_data_t {};
hb_coretext_aat_shaper_face_data_t *
_hb_coretext_aat_shaper_face_data_create (hb_face_t *face)
{
hb_blob_t *mort_blob = face->reference_table (HB_CORETEXT_TAG_MORT);
/* Umm, we just reference the table to check whether it exists.
* Maybe add better API for this? */
if (!hb_blob_get_length (mort_blob))
{
hb_blob_destroy (mort_blob);
mort_blob = face->reference_table (HB_CORETEXT_TAG_MORX);
if (!hb_blob_get_length (mort_blob))
{
hb_blob_destroy (mort_blob);
return NULL;
}
}
hb_blob_destroy (mort_blob);
return hb_coretext_shaper_face_data_ensure (face) ? (hb_coretext_aat_shaper_face_data_t *) HB_SHAPER_DATA_SUCCEEDED : NULL;
}
void
_hb_coretext_aat_shaper_face_data_destroy (hb_coretext_aat_shaper_face_data_t *data HB_UNUSED)
{
}
/*
* shaper font data
*/
struct hb_coretext_aat_shaper_font_data_t {};
hb_coretext_aat_shaper_font_data_t *
_hb_coretext_aat_shaper_font_data_create (hb_font_t *font)
{
return hb_coretext_shaper_font_data_ensure (font) ? (hb_coretext_aat_shaper_font_data_t *) HB_SHAPER_DATA_SUCCEEDED : NULL;
}
void
_hb_coretext_aat_shaper_font_data_destroy (hb_coretext_aat_shaper_font_data_t *data HB_UNUSED)
{
}
/*
* shaper shape_plan data
*/
struct hb_coretext_aat_shaper_shape_plan_data_t {};
hb_coretext_aat_shaper_shape_plan_data_t *
_hb_coretext_aat_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan HB_UNUSED,
const hb_feature_t *user_features HB_UNUSED,
unsigned int num_user_features HB_UNUSED)
{
return (hb_coretext_aat_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
}
void
_hb_coretext_aat_shaper_shape_plan_data_destroy (hb_coretext_aat_shaper_shape_plan_data_t *data HB_UNUSED)
{
}
/*
* shaper
*/
hb_bool_t
_hb_coretext_aat_shape (hb_shape_plan_t *shape_plan,
hb_font_t *font,
hb_buffer_t *buffer,
const hb_feature_t *features,
unsigned int num_features)
{
return _hb_coretext_shape (shape_plan, font, buffer, features, num_features);
}

View File

@ -29,11 +29,25 @@
#include "hb.h" #include "hb.h"
#include <ApplicationServices/ApplicationServices.h> #include <TargetConditionals.h>
#if TARGET_OS_IPHONE
# include <CoreText/CoreText.h>
# include <CoreGraphics/CoreGraphics.h>
#else
# include <ApplicationServices/ApplicationServices.h>
#endif
HB_BEGIN_DECLS HB_BEGIN_DECLS
#define HB_CORETEXT_TAG_MORT HB_TAG('m','o','r','t')
#define HB_CORETEXT_TAG_MORX HB_TAG('m','o','r','x')
hb_face_t *
hb_coretext_face_create (CGFontRef cg_font);
CGFontRef CGFontRef
hb_coretext_face_get_cg_font (hb_face_t *face); hb_coretext_face_get_cg_font (hb_face_t *face);

View File

@ -298,7 +298,7 @@ hb_face_get_user_data (hb_face_t *face,
void void
hb_face_make_immutable (hb_face_t *face) hb_face_make_immutable (hb_face_t *face)
{ {
if (hb_object_is_inert (face)) if (unlikely (hb_object_is_inert (face)))
return; return;
face->immutable = true; face->immutable = true;
@ -368,7 +368,7 @@ void
hb_face_set_index (hb_face_t *face, hb_face_set_index (hb_face_t *face,
unsigned int index) unsigned int index)
{ {
if (hb_object_is_inert (face)) if (face->immutable)
return; return;
face->index = index; face->index = index;
@ -403,7 +403,7 @@ void
hb_face_set_upem (hb_face_t *face, hb_face_set_upem (hb_face_t *face,
unsigned int upem) unsigned int upem)
{ {
if (hb_object_is_inert (face)) if (face->immutable)
return; return;
face->upem = upem; face->upem = upem;
@ -447,7 +447,7 @@ void
hb_face_set_glyph_count (hb_face_t *face, hb_face_set_glyph_count (hb_face_t *face,
unsigned int glyph_count) unsigned int glyph_count)
{ {
if (hb_object_is_inert (face)) if (face->immutable)
return; return;
face->num_glyphs = glyph_count; face->num_glyphs = glyph_count;

View File

@ -105,34 +105,36 @@ _hb_fallback_shape (hb_shape_plan_t *shape_plan HB_UNUSED,
* shaper which many people unfortunately still request. * shaper which many people unfortunately still request.
*/ */
bool has_space;
hb_codepoint_t space; hb_codepoint_t space;
has_space = font->get_glyph (' ', 0, &space); bool has_space = font->get_glyph (' ', 0, &space);
buffer->clear_positions (); buffer->clear_positions ();
hb_direction_t direction = buffer->props.direction;
hb_unicode_funcs_t *unicode = buffer->unicode;
unsigned int count = buffer->len; unsigned int count = buffer->len;
hb_glyph_info_t *info = buffer->info;
hb_glyph_position_t *pos = buffer->pos;
for (unsigned int i = 0; i < count; i++) for (unsigned int i = 0; i < count; i++)
{ {
if (has_space && buffer->unicode->is_default_ignorable (buffer->info[i].codepoint)) { if (has_space && unicode->is_default_ignorable (info[i].codepoint)) {
buffer->info[i].codepoint = space; info[i].codepoint = space;
buffer->pos[i].x_advance = 0; pos[i].x_advance = 0;
buffer->pos[i].y_advance = 0; pos[i].y_advance = 0;
continue; continue;
} }
font->get_glyph (buffer->info[i].codepoint, 0, &buffer->info[i].codepoint); font->get_glyph (info[i].codepoint, 0, &info[i].codepoint);
font->get_glyph_advance_for_direction (buffer->info[i].codepoint, font->get_glyph_advance_for_direction (info[i].codepoint,
buffer->props.direction, direction,
&buffer->pos[i].x_advance, &pos[i].x_advance,
&buffer->pos[i].y_advance); &pos[i].y_advance);
font->subtract_glyph_origin_for_direction (buffer->info[i].codepoint, font->subtract_glyph_origin_for_direction (info[i].codepoint,
buffer->props.direction, direction,
&buffer->pos[i].x_offset, &pos[i].x_offset,
&buffer->pos[i].y_offset); &pos[i].y_offset);
} }
if (HB_DIRECTION_IS_BACKWARD (buffer->props.direction)) if (HB_DIRECTION_IS_BACKWARD (direction))
hb_buffer_reverse (buffer); hb_buffer_reverse (buffer);
return true; return true;

View File

@ -357,7 +357,7 @@ hb_font_funcs_get_user_data (hb_font_funcs_t *ffuncs,
void void
hb_font_funcs_make_immutable (hb_font_funcs_t *ffuncs) hb_font_funcs_make_immutable (hb_font_funcs_t *ffuncs)
{ {
if (hb_object_is_inert (ffuncs)) if (unlikely (hb_object_is_inert (ffuncs)))
return; return;
ffuncs->immutable = true; ffuncs->immutable = true;
@ -1034,7 +1034,7 @@ hb_font_get_user_data (hb_font_t *font,
void void
hb_font_make_immutable (hb_font_t *font) hb_font_make_immutable (hb_font_t *font)
{ {
if (hb_object_is_inert (font)) if (unlikely (hb_object_is_inert (font)))
return; return;
font->immutable = true; font->immutable = true;

View File

@ -340,7 +340,7 @@ hb_glib_unicode_decompose_compatibility (hb_unicode_funcs_t *ufuncs HB_UNUSED,
void *user_data HB_UNUSED) void *user_data HB_UNUSED)
{ {
#if GLIB_CHECK_VERSION(2,29,12) #if GLIB_CHECK_VERSION(2,29,12)
return g_unichar_fully_decompose (u, TRUE, decomposed, HB_UNICODE_MAX_DECOMPOSITION_LEN); return g_unichar_fully_decompose (u, true, decomposed, HB_UNICODE_MAX_DECOMPOSITION_LEN);
#endif #endif
/* If the user doesn't have GLib >= 2.29.12 we have to perform /* If the user doesn't have GLib >= 2.29.12 we have to perform

View File

@ -1,343 +0,0 @@
/* Generated data (by glib-mkenums) */
/*
* Copyright © 2011 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Behdad Esfahbod
*/
#include "hb-private.hh"
/* g++ didn't like older gtype.h gcc-only code path. */
#include <glib.h>
#if !GLIB_CHECK_VERSION(2,29,16)
#undef __GNUC__
#undef __GNUC_MINOR__
#define __GNUC__ 2
#define __GNUC_MINOR__ 6
#endif
#include "hb-gobject.h"
/* enumerations from "hb-blob.h" */
inline static /* TODO(behdad) disable these for now until we fix them... */
GType
hb_memory_mode_t_hb_memory_mode_t_get_type (void)
{
static volatile gsize g_define_type_id__volatile = 0;
if (g_once_init_enter (&g_define_type_id__volatile))
{
static const GEnumValue values[] = {
{ HB_MEMORY_MODE_DUPLICATE, "HB_MEMORY_MODE_DUPLICATE", "duplicate" },
{ HB_MEMORY_MODE_READONLY, "HB_MEMORY_MODE_READONLY", "readonly" },
{ HB_MEMORY_MODE_WRITABLE, "HB_MEMORY_MODE_WRITABLE", "writable" },
{ HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE, "HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE", "readonly-may-make-writable" },
{ 0, NULL, NULL }
};
GType g_define_type_id =
g_enum_register_static (g_intern_static_string ("hb_memory_mode_t"), values);
g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
}
return g_define_type_id__volatile;
}
/* enumerations from "hb-common.h" */
inline static /* TODO(behdad) disable these for now until we fix them... */
GType
hb_direction_t_hb_direction_t_get_type (void)
{
static volatile gsize g_define_type_id__volatile = 0;
if (g_once_init_enter (&g_define_type_id__volatile))
{
static const GEnumValue values[] = {
{ HB_DIRECTION_INVALID, "HB_DIRECTION_INVALID", "invalid" },
{ HB_DIRECTION_LTR, "HB_DIRECTION_LTR", "ltr" },
{ HB_DIRECTION_RTL, "HB_DIRECTION_RTL", "rtl" },
{ HB_DIRECTION_TTB, "HB_DIRECTION_TTB", "ttb" },
{ HB_DIRECTION_BTT, "HB_DIRECTION_BTT", "btt" },
{ 0, NULL, NULL }
};
GType g_define_type_id =
g_enum_register_static (g_intern_static_string ("hb_direction_t"), values);
g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
}
return g_define_type_id__volatile;
}
inline static /* TODO(behdad) disable these for now until we fix them... */
GType
hb_script_t_hb_script_t_get_type (void)
{
static volatile gsize g_define_type_id__volatile = 0;
if (g_once_init_enter (&g_define_type_id__volatile))
{
static const GEnumValue values[] = {
{ HB_SCRIPT_COMMON, "HB_SCRIPT_COMMON", "common" },
{ HB_SCRIPT_ARABIC, "HB_SCRIPT_ARABIC", "arabic" },
{ HB_SCRIPT_ARMENIAN, "HB_SCRIPT_ARMENIAN", "armenian" },
{ HB_SCRIPT_BENGALI, "HB_SCRIPT_BENGALI", "bengali" },
{ HB_SCRIPT_BOPOMOFO, "HB_SCRIPT_BOPOMOFO", "bopomofo" },
{ HB_SCRIPT_CANADIAN_ABORIGINAL, "HB_SCRIPT_CANADIAN_ABORIGINAL", "canadian-aboriginal" },
{ HB_SCRIPT_CHEROKEE, "HB_SCRIPT_CHEROKEE", "cherokee" },
{ HB_SCRIPT_COPTIC, "HB_SCRIPT_COPTIC", "coptic" },
{ HB_SCRIPT_CYRILLIC, "HB_SCRIPT_CYRILLIC", "cyrillic" },
{ HB_SCRIPT_DEVANAGARI, "HB_SCRIPT_DEVANAGARI", "devanagari" },
{ HB_SCRIPT_GEORGIAN, "HB_SCRIPT_GEORGIAN", "georgian" },
{ HB_SCRIPT_GREEK, "HB_SCRIPT_GREEK", "greek" },
{ HB_SCRIPT_GUJARATI, "HB_SCRIPT_GUJARATI", "gujarati" },
{ HB_SCRIPT_GURMUKHI, "HB_SCRIPT_GURMUKHI", "gurmukhi" },
{ HB_SCRIPT_HANGUL, "HB_SCRIPT_HANGUL", "hangul" },
{ HB_SCRIPT_HAN, "HB_SCRIPT_HAN", "han" },
{ HB_SCRIPT_HEBREW, "HB_SCRIPT_HEBREW", "hebrew" },
{ HB_SCRIPT_HIRAGANA, "HB_SCRIPT_HIRAGANA", "hiragana" },
{ HB_SCRIPT_INHERITED, "HB_SCRIPT_INHERITED", "inherited" },
{ HB_SCRIPT_KANNADA, "HB_SCRIPT_KANNADA", "kannada" },
{ HB_SCRIPT_KATAKANA, "HB_SCRIPT_KATAKANA", "katakana" },
{ HB_SCRIPT_LAO, "HB_SCRIPT_LAO", "lao" },
{ HB_SCRIPT_LATIN, "HB_SCRIPT_LATIN", "latin" },
{ HB_SCRIPT_MALAYALAM, "HB_SCRIPT_MALAYALAM", "malayalam" },
{ HB_SCRIPT_MONGOLIAN, "HB_SCRIPT_MONGOLIAN", "mongolian" },
{ HB_SCRIPT_OGHAM, "HB_SCRIPT_OGHAM", "ogham" },
{ HB_SCRIPT_ORIYA, "HB_SCRIPT_ORIYA", "oriya" },
{ HB_SCRIPT_RUNIC, "HB_SCRIPT_RUNIC", "runic" },
{ HB_SCRIPT_SYRIAC, "HB_SCRIPT_SYRIAC", "syriac" },
{ HB_SCRIPT_TAMIL, "HB_SCRIPT_TAMIL", "tamil" },
{ HB_SCRIPT_TELUGU, "HB_SCRIPT_TELUGU", "telugu" },
{ HB_SCRIPT_THAI, "HB_SCRIPT_THAI", "thai" },
{ HB_SCRIPT_YI, "HB_SCRIPT_YI", "yi" },
{ HB_SCRIPT_TIBETAN, "HB_SCRIPT_TIBETAN", "tibetan" },
{ HB_SCRIPT_ETHIOPIC, "HB_SCRIPT_ETHIOPIC", "ethiopic" },
{ HB_SCRIPT_KHMER, "HB_SCRIPT_KHMER", "khmer" },
{ HB_SCRIPT_MYANMAR, "HB_SCRIPT_MYANMAR", "myanmar" },
{ HB_SCRIPT_SINHALA, "HB_SCRIPT_SINHALA", "sinhala" },
{ HB_SCRIPT_THAANA, "HB_SCRIPT_THAANA", "thaana" },
{ HB_SCRIPT_DESERET, "HB_SCRIPT_DESERET", "deseret" },
{ HB_SCRIPT_GOTHIC, "HB_SCRIPT_GOTHIC", "gothic" },
{ HB_SCRIPT_OLD_ITALIC, "HB_SCRIPT_OLD_ITALIC", "old-italic" },
{ HB_SCRIPT_BUHID, "HB_SCRIPT_BUHID", "buhid" },
{ HB_SCRIPT_HANUNOO, "HB_SCRIPT_HANUNOO", "hanunoo" },
{ HB_SCRIPT_TAGALOG, "HB_SCRIPT_TAGALOG", "tagalog" },
{ HB_SCRIPT_TAGBANWA, "HB_SCRIPT_TAGBANWA", "tagbanwa" },
{ HB_SCRIPT_BRAILLE, "HB_SCRIPT_BRAILLE", "braille" },
{ HB_SCRIPT_CYPRIOT, "HB_SCRIPT_CYPRIOT", "cypriot" },
{ HB_SCRIPT_LIMBU, "HB_SCRIPT_LIMBU", "limbu" },
{ HB_SCRIPT_LINEAR_B, "HB_SCRIPT_LINEAR_B", "linear-b" },
{ HB_SCRIPT_OSMANYA, "HB_SCRIPT_OSMANYA", "osmanya" },
{ HB_SCRIPT_SHAVIAN, "HB_SCRIPT_SHAVIAN", "shavian" },
{ HB_SCRIPT_TAI_LE, "HB_SCRIPT_TAI_LE", "tai-le" },
{ HB_SCRIPT_UGARITIC, "HB_SCRIPT_UGARITIC", "ugaritic" },
{ HB_SCRIPT_BUGINESE, "HB_SCRIPT_BUGINESE", "buginese" },
{ HB_SCRIPT_GLAGOLITIC, "HB_SCRIPT_GLAGOLITIC", "glagolitic" },
{ HB_SCRIPT_KHAROSHTHI, "HB_SCRIPT_KHAROSHTHI", "kharoshthi" },
{ HB_SCRIPT_NEW_TAI_LUE, "HB_SCRIPT_NEW_TAI_LUE", "new-tai-lue" },
{ HB_SCRIPT_OLD_PERSIAN, "HB_SCRIPT_OLD_PERSIAN", "old-persian" },
{ HB_SCRIPT_SYLOTI_NAGRI, "HB_SCRIPT_SYLOTI_NAGRI", "syloti-nagri" },
{ HB_SCRIPT_TIFINAGH, "HB_SCRIPT_TIFINAGH", "tifinagh" },
{ HB_SCRIPT_BALINESE, "HB_SCRIPT_BALINESE", "balinese" },
{ HB_SCRIPT_CUNEIFORM, "HB_SCRIPT_CUNEIFORM", "cuneiform" },
{ HB_SCRIPT_NKO, "HB_SCRIPT_NKO", "nko" },
{ HB_SCRIPT_PHAGS_PA, "HB_SCRIPT_PHAGS_PA", "phags-pa" },
{ HB_SCRIPT_PHOENICIAN, "HB_SCRIPT_PHOENICIAN", "phoenician" },
{ HB_SCRIPT_UNKNOWN, "HB_SCRIPT_UNKNOWN", "unknown" },
{ HB_SCRIPT_CARIAN, "HB_SCRIPT_CARIAN", "carian" },
{ HB_SCRIPT_CHAM, "HB_SCRIPT_CHAM", "cham" },
{ HB_SCRIPT_KAYAH_LI, "HB_SCRIPT_KAYAH_LI", "kayah-li" },
{ HB_SCRIPT_LEPCHA, "HB_SCRIPT_LEPCHA", "lepcha" },
{ HB_SCRIPT_LYCIAN, "HB_SCRIPT_LYCIAN", "lycian" },
{ HB_SCRIPT_LYDIAN, "HB_SCRIPT_LYDIAN", "lydian" },
{ HB_SCRIPT_OL_CHIKI, "HB_SCRIPT_OL_CHIKI", "ol-chiki" },
{ HB_SCRIPT_REJANG, "HB_SCRIPT_REJANG", "rejang" },
{ HB_SCRIPT_SAURASHTRA, "HB_SCRIPT_SAURASHTRA", "saurashtra" },
{ HB_SCRIPT_SUNDANESE, "HB_SCRIPT_SUNDANESE", "sundanese" },
{ HB_SCRIPT_VAI, "HB_SCRIPT_VAI", "vai" },
{ HB_SCRIPT_AVESTAN, "HB_SCRIPT_AVESTAN", "avestan" },
{ HB_SCRIPT_BAMUM, "HB_SCRIPT_BAMUM", "bamum" },
{ HB_SCRIPT_EGYPTIAN_HIEROGLYPHS, "HB_SCRIPT_EGYPTIAN_HIEROGLYPHS", "egyptian-hieroglyphs" },
{ HB_SCRIPT_IMPERIAL_ARAMAIC, "HB_SCRIPT_IMPERIAL_ARAMAIC", "imperial-aramaic" },
{ HB_SCRIPT_INSCRIPTIONAL_PAHLAVI, "HB_SCRIPT_INSCRIPTIONAL_PAHLAVI", "inscriptional-pahlavi" },
{ HB_SCRIPT_INSCRIPTIONAL_PARTHIAN, "HB_SCRIPT_INSCRIPTIONAL_PARTHIAN", "inscriptional-parthian" },
{ HB_SCRIPT_JAVANESE, "HB_SCRIPT_JAVANESE", "javanese" },
{ HB_SCRIPT_KAITHI, "HB_SCRIPT_KAITHI", "kaithi" },
{ HB_SCRIPT_LISU, "HB_SCRIPT_LISU", "lisu" },
{ HB_SCRIPT_MEETEI_MAYEK, "HB_SCRIPT_MEETEI_MAYEK", "meetei-mayek" },
{ HB_SCRIPT_OLD_SOUTH_ARABIAN, "HB_SCRIPT_OLD_SOUTH_ARABIAN", "old-south-arabian" },
{ HB_SCRIPT_OLD_TURKIC, "HB_SCRIPT_OLD_TURKIC", "old-turkic" },
{ HB_SCRIPT_SAMARITAN, "HB_SCRIPT_SAMARITAN", "samaritan" },
{ HB_SCRIPT_TAI_THAM, "HB_SCRIPT_TAI_THAM", "tai-tham" },
{ HB_SCRIPT_TAI_VIET, "HB_SCRIPT_TAI_VIET", "tai-viet" },
{ HB_SCRIPT_BATAK, "HB_SCRIPT_BATAK", "batak" },
{ HB_SCRIPT_BRAHMI, "HB_SCRIPT_BRAHMI", "brahmi" },
{ HB_SCRIPT_MANDAIC, "HB_SCRIPT_MANDAIC", "mandaic" },
{ HB_SCRIPT_CHAKMA, "HB_SCRIPT_CHAKMA", "chakma" },
{ HB_SCRIPT_MEROITIC_CURSIVE, "HB_SCRIPT_MEROITIC_CURSIVE", "meroitic-cursive" },
{ HB_SCRIPT_MEROITIC_HIEROGLYPHS, "HB_SCRIPT_MEROITIC_HIEROGLYPHS", "meroitic-hieroglyphs" },
{ HB_SCRIPT_MIAO, "HB_SCRIPT_MIAO", "miao" },
{ HB_SCRIPT_SHARADA, "HB_SCRIPT_SHARADA", "sharada" },
{ HB_SCRIPT_SORA_SOMPENG, "HB_SCRIPT_SORA_SOMPENG", "sora-sompeng" },
{ HB_SCRIPT_TAKRI, "HB_SCRIPT_TAKRI", "takri" },
{ HB_SCRIPT_INVALID, "HB_SCRIPT_INVALID", "invalid" },
{ 0, NULL, NULL }
};
GType g_define_type_id =
g_enum_register_static (g_intern_static_string ("hb_script_t"), values);
g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
}
return g_define_type_id__volatile;
}
/* enumerations from "hb-unicode.h" */
inline static /* TODO(behdad) disable these for now until we fix them... */
GType
hb_unicode_general_category_t_hb_unicode_general_category_t_get_type (void)
{
static volatile gsize g_define_type_id__volatile = 0;
if (g_once_init_enter (&g_define_type_id__volatile))
{
static const GEnumValue values[] = {
{ HB_UNICODE_GENERAL_CATEGORY_CONTROL, "HB_UNICODE_GENERAL_CATEGORY_CONTROL", "control" },
{ HB_UNICODE_GENERAL_CATEGORY_FORMAT, "HB_UNICODE_GENERAL_CATEGORY_FORMAT", "format" },
{ HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED, "HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED", "unassigned" },
{ HB_UNICODE_GENERAL_CATEGORY_PRIVATE_USE, "HB_UNICODE_GENERAL_CATEGORY_PRIVATE_USE", "private-use" },
{ HB_UNICODE_GENERAL_CATEGORY_SURROGATE, "HB_UNICODE_GENERAL_CATEGORY_SURROGATE", "surrogate" },
{ HB_UNICODE_GENERAL_CATEGORY_LOWERCASE_LETTER, "HB_UNICODE_GENERAL_CATEGORY_LOWERCASE_LETTER", "lowercase-letter" },
{ HB_UNICODE_GENERAL_CATEGORY_MODIFIER_LETTER, "HB_UNICODE_GENERAL_CATEGORY_MODIFIER_LETTER", "modifier-letter" },
{ HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER, "HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER", "other-letter" },
{ HB_UNICODE_GENERAL_CATEGORY_TITLECASE_LETTER, "HB_UNICODE_GENERAL_CATEGORY_TITLECASE_LETTER", "titlecase-letter" },
{ HB_UNICODE_GENERAL_CATEGORY_UPPERCASE_LETTER, "HB_UNICODE_GENERAL_CATEGORY_UPPERCASE_LETTER", "uppercase-letter" },
{ HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK, "HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK", "spacing-mark" },
{ HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK, "HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK", "enclosing-mark" },
{ HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK, "HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK", "non-spacing-mark" },
{ HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER, "HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER", "decimal-number" },
{ HB_UNICODE_GENERAL_CATEGORY_LETTER_NUMBER, "HB_UNICODE_GENERAL_CATEGORY_LETTER_NUMBER", "letter-number" },
{ HB_UNICODE_GENERAL_CATEGORY_OTHER_NUMBER, "HB_UNICODE_GENERAL_CATEGORY_OTHER_NUMBER", "other-number" },
{ HB_UNICODE_GENERAL_CATEGORY_CONNECT_PUNCTUATION, "HB_UNICODE_GENERAL_CATEGORY_CONNECT_PUNCTUATION", "connect-punctuation" },
{ HB_UNICODE_GENERAL_CATEGORY_DASH_PUNCTUATION, "HB_UNICODE_GENERAL_CATEGORY_DASH_PUNCTUATION", "dash-punctuation" },
{ HB_UNICODE_GENERAL_CATEGORY_CLOSE_PUNCTUATION, "HB_UNICODE_GENERAL_CATEGORY_CLOSE_PUNCTUATION", "close-punctuation" },
{ HB_UNICODE_GENERAL_CATEGORY_FINAL_PUNCTUATION, "HB_UNICODE_GENERAL_CATEGORY_FINAL_PUNCTUATION", "final-punctuation" },
{ HB_UNICODE_GENERAL_CATEGORY_INITIAL_PUNCTUATION, "HB_UNICODE_GENERAL_CATEGORY_INITIAL_PUNCTUATION", "initial-punctuation" },
{ HB_UNICODE_GENERAL_CATEGORY_OTHER_PUNCTUATION, "HB_UNICODE_GENERAL_CATEGORY_OTHER_PUNCTUATION", "other-punctuation" },
{ HB_UNICODE_GENERAL_CATEGORY_OPEN_PUNCTUATION, "HB_UNICODE_GENERAL_CATEGORY_OPEN_PUNCTUATION", "open-punctuation" },
{ HB_UNICODE_GENERAL_CATEGORY_CURRENCY_SYMBOL, "HB_UNICODE_GENERAL_CATEGORY_CURRENCY_SYMBOL", "currency-symbol" },
{ HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL, "HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL", "modifier-symbol" },
{ HB_UNICODE_GENERAL_CATEGORY_MATH_SYMBOL, "HB_UNICODE_GENERAL_CATEGORY_MATH_SYMBOL", "math-symbol" },
{ HB_UNICODE_GENERAL_CATEGORY_OTHER_SYMBOL, "HB_UNICODE_GENERAL_CATEGORY_OTHER_SYMBOL", "other-symbol" },
{ HB_UNICODE_GENERAL_CATEGORY_LINE_SEPARATOR, "HB_UNICODE_GENERAL_CATEGORY_LINE_SEPARATOR", "line-separator" },
{ HB_UNICODE_GENERAL_CATEGORY_PARAGRAPH_SEPARATOR, "HB_UNICODE_GENERAL_CATEGORY_PARAGRAPH_SEPARATOR", "paragraph-separator" },
{ HB_UNICODE_GENERAL_CATEGORY_SPACE_SEPARATOR, "HB_UNICODE_GENERAL_CATEGORY_SPACE_SEPARATOR", "space-separator" },
{ 0, NULL, NULL }
};
GType g_define_type_id =
g_enum_register_static (g_intern_static_string ("hb_unicode_general_category_t"), values);
g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
}
return g_define_type_id__volatile;
}
inline static /* TODO(behdad) disable these for now until we fix them... */
GType
hb_unicode_combining_class_t_hb_unicode_combining_class_t_get_type (void)
{
static volatile gsize g_define_type_id__volatile = 0;
if (g_once_init_enter (&g_define_type_id__volatile))
{
static const GEnumValue values[] = {
{ HB_UNICODE_COMBINING_CLASS_NOT_REORDERED, "HB_UNICODE_COMBINING_CLASS_NOT_REORDERED", "not-reordered" },
{ HB_UNICODE_COMBINING_CLASS_OVERLAY, "HB_UNICODE_COMBINING_CLASS_OVERLAY", "overlay" },
{ HB_UNICODE_COMBINING_CLASS_NUKTA, "HB_UNICODE_COMBINING_CLASS_NUKTA", "nukta" },
{ HB_UNICODE_COMBINING_CLASS_KANA_VOICING, "HB_UNICODE_COMBINING_CLASS_KANA_VOICING", "kana-voicing" },
{ HB_UNICODE_COMBINING_CLASS_VIRAMA, "HB_UNICODE_COMBINING_CLASS_VIRAMA", "virama" },
{ HB_UNICODE_COMBINING_CLASS_CCC10, "HB_UNICODE_COMBINING_CLASS_CCC10", "ccc10" },
{ HB_UNICODE_COMBINING_CLASS_CCC11, "HB_UNICODE_COMBINING_CLASS_CCC11", "ccc11" },
{ HB_UNICODE_COMBINING_CLASS_CCC12, "HB_UNICODE_COMBINING_CLASS_CCC12", "ccc12" },
{ HB_UNICODE_COMBINING_CLASS_CCC13, "HB_UNICODE_COMBINING_CLASS_CCC13", "ccc13" },
{ HB_UNICODE_COMBINING_CLASS_CCC14, "HB_UNICODE_COMBINING_CLASS_CCC14", "ccc14" },
{ HB_UNICODE_COMBINING_CLASS_CCC15, "HB_UNICODE_COMBINING_CLASS_CCC15", "ccc15" },
{ HB_UNICODE_COMBINING_CLASS_CCC16, "HB_UNICODE_COMBINING_CLASS_CCC16", "ccc16" },
{ HB_UNICODE_COMBINING_CLASS_CCC17, "HB_UNICODE_COMBINING_CLASS_CCC17", "ccc17" },
{ HB_UNICODE_COMBINING_CLASS_CCC18, "HB_UNICODE_COMBINING_CLASS_CCC18", "ccc18" },
{ HB_UNICODE_COMBINING_CLASS_CCC19, "HB_UNICODE_COMBINING_CLASS_CCC19", "ccc19" },
{ HB_UNICODE_COMBINING_CLASS_CCC20, "HB_UNICODE_COMBINING_CLASS_CCC20", "ccc20" },
{ HB_UNICODE_COMBINING_CLASS_CCC21, "HB_UNICODE_COMBINING_CLASS_CCC21", "ccc21" },
{ HB_UNICODE_COMBINING_CLASS_CCC22, "HB_UNICODE_COMBINING_CLASS_CCC22", "ccc22" },
{ HB_UNICODE_COMBINING_CLASS_CCC23, "HB_UNICODE_COMBINING_CLASS_CCC23", "ccc23" },
{ HB_UNICODE_COMBINING_CLASS_CCC24, "HB_UNICODE_COMBINING_CLASS_CCC24", "ccc24" },
{ HB_UNICODE_COMBINING_CLASS_CCC25, "HB_UNICODE_COMBINING_CLASS_CCC25", "ccc25" },
{ HB_UNICODE_COMBINING_CLASS_CCC26, "HB_UNICODE_COMBINING_CLASS_CCC26", "ccc26" },
{ HB_UNICODE_COMBINING_CLASS_CCC27, "HB_UNICODE_COMBINING_CLASS_CCC27", "ccc27" },
{ HB_UNICODE_COMBINING_CLASS_CCC28, "HB_UNICODE_COMBINING_CLASS_CCC28", "ccc28" },
{ HB_UNICODE_COMBINING_CLASS_CCC29, "HB_UNICODE_COMBINING_CLASS_CCC29", "ccc29" },
{ HB_UNICODE_COMBINING_CLASS_CCC30, "HB_UNICODE_COMBINING_CLASS_CCC30", "ccc30" },
{ HB_UNICODE_COMBINING_CLASS_CCC31, "HB_UNICODE_COMBINING_CLASS_CCC31", "ccc31" },
{ HB_UNICODE_COMBINING_CLASS_CCC32, "HB_UNICODE_COMBINING_CLASS_CCC32", "ccc32" },
{ HB_UNICODE_COMBINING_CLASS_CCC33, "HB_UNICODE_COMBINING_CLASS_CCC33", "ccc33" },
{ HB_UNICODE_COMBINING_CLASS_CCC34, "HB_UNICODE_COMBINING_CLASS_CCC34", "ccc34" },
{ HB_UNICODE_COMBINING_CLASS_CCC35, "HB_UNICODE_COMBINING_CLASS_CCC35", "ccc35" },
{ HB_UNICODE_COMBINING_CLASS_CCC36, "HB_UNICODE_COMBINING_CLASS_CCC36", "ccc36" },
{ HB_UNICODE_COMBINING_CLASS_CCC84, "HB_UNICODE_COMBINING_CLASS_CCC84", "ccc84" },
{ HB_UNICODE_COMBINING_CLASS_CCC91, "HB_UNICODE_COMBINING_CLASS_CCC91", "ccc91" },
{ HB_UNICODE_COMBINING_CLASS_CCC103, "HB_UNICODE_COMBINING_CLASS_CCC103", "ccc103" },
{ HB_UNICODE_COMBINING_CLASS_CCC107, "HB_UNICODE_COMBINING_CLASS_CCC107", "ccc107" },
{ HB_UNICODE_COMBINING_CLASS_CCC118, "HB_UNICODE_COMBINING_CLASS_CCC118", "ccc118" },
{ HB_UNICODE_COMBINING_CLASS_CCC122, "HB_UNICODE_COMBINING_CLASS_CCC122", "ccc122" },
{ HB_UNICODE_COMBINING_CLASS_CCC129, "HB_UNICODE_COMBINING_CLASS_CCC129", "ccc129" },
{ HB_UNICODE_COMBINING_CLASS_CCC130, "HB_UNICODE_COMBINING_CLASS_CCC130", "ccc130" },
{ HB_UNICODE_COMBINING_CLASS_CCC133, "HB_UNICODE_COMBINING_CLASS_CCC133", "ccc133" },
{ HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW_LEFT, "HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW_LEFT", "attached-below-left" },
{ HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW, "HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW", "attached-below" },
{ HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE, "HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE", "attached-above" },
{ HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE_RIGHT, "HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE_RIGHT", "attached-above-right" },
{ HB_UNICODE_COMBINING_CLASS_BELOW_LEFT, "HB_UNICODE_COMBINING_CLASS_BELOW_LEFT", "below-left" },
{ HB_UNICODE_COMBINING_CLASS_BELOW, "HB_UNICODE_COMBINING_CLASS_BELOW", "below" },
{ HB_UNICODE_COMBINING_CLASS_BELOW_RIGHT, "HB_UNICODE_COMBINING_CLASS_BELOW_RIGHT", "below-right" },
{ HB_UNICODE_COMBINING_CLASS_LEFT, "HB_UNICODE_COMBINING_CLASS_LEFT", "left" },
{ HB_UNICODE_COMBINING_CLASS_RIGHT, "HB_UNICODE_COMBINING_CLASS_RIGHT", "right" },
{ HB_UNICODE_COMBINING_CLASS_ABOVE_LEFT, "HB_UNICODE_COMBINING_CLASS_ABOVE_LEFT", "above-left" },
{ HB_UNICODE_COMBINING_CLASS_ABOVE, "HB_UNICODE_COMBINING_CLASS_ABOVE", "above" },
{ HB_UNICODE_COMBINING_CLASS_ABOVE_RIGHT, "HB_UNICODE_COMBINING_CLASS_ABOVE_RIGHT", "above-right" },
{ HB_UNICODE_COMBINING_CLASS_DOUBLE_BELOW, "HB_UNICODE_COMBINING_CLASS_DOUBLE_BELOW", "double-below" },
{ HB_UNICODE_COMBINING_CLASS_DOUBLE_ABOVE, "HB_UNICODE_COMBINING_CLASS_DOUBLE_ABOVE", "double-above" },
{ HB_UNICODE_COMBINING_CLASS_IOTA_SUBSCRIPT, "HB_UNICODE_COMBINING_CLASS_IOTA_SUBSCRIPT", "iota-subscript" },
{ HB_UNICODE_COMBINING_CLASS_INVALID, "HB_UNICODE_COMBINING_CLASS_INVALID", "invalid" },
{ 0, NULL, NULL }
};
GType g_define_type_id =
g_enum_register_static (g_intern_static_string ("hb_unicode_combining_class_t"), values);
g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
}
return g_define_type_id__volatile;
}
/* Generated data ends here */

View File

@ -209,6 +209,7 @@ struct hb_graphite2_cluster_t {
unsigned int num_chars; unsigned int num_chars;
unsigned int base_glyph; unsigned int base_glyph;
unsigned int num_glyphs; unsigned int num_glyphs;
unsigned int cluster;
}; };
hb_bool_t hb_bool_t
@ -299,6 +300,7 @@ _hb_graphite2_shape (hb_shape_plan_t *shape_plan,
memset (clusters, 0, sizeof (clusters[0]) * buffer->len); memset (clusters, 0, sizeof (clusters[0]) * buffer->len);
hb_codepoint_t *pg = gids; hb_codepoint_t *pg = gids;
clusters[0].cluster = buffer->info[0].cluster;
for (is = gr_seg_first_slot (seg), ic = 0; is; is = gr_slot_next_in_segment (is), ic++) for (is = gr_seg_first_slot (seg), ic = 0; is; is = gr_slot_next_in_segment (is), ic++)
{ {
unsigned int before = gr_slot_before (is); unsigned int before = gr_slot_before (is);
@ -316,6 +318,7 @@ _hb_graphite2_shape (hb_shape_plan_t *shape_plan,
{ {
hb_graphite2_cluster_t *c = clusters + ci + 1; hb_graphite2_cluster_t *c = clusters + ci + 1;
c->base_char = clusters[ci].base_char + clusters[ci].num_chars; c->base_char = clusters[ci].base_char + clusters[ci].num_chars;
c->cluster = buffer->info[c->base_char].cluster;
c->num_chars = before - c->base_char; c->num_chars = before - c->base_char;
c->base_glyph = ic; c->base_glyph = ic;
c->num_glyphs = 0; c->num_glyphs = 0;
@ -335,7 +338,7 @@ _hb_graphite2_shape (hb_shape_plan_t *shape_plan,
{ {
hb_glyph_info_t *info = &buffer->info[clusters[i].base_glyph + j]; hb_glyph_info_t *info = &buffer->info[clusters[i].base_glyph + j];
info->codepoint = gids[clusters[i].base_glyph + j]; info->codepoint = gids[clusters[i].base_glyph + j];
info->cluster = gr_cinfo_base(gr_seg_cinfo(seg, clusters[i].base_char)); info->cluster = clusters[i].cluster;
} }
} }
buffer->len = glyph_count; buffer->len = glyph_count;

View File

@ -1,215 +0,0 @@
/*
* Copyright © 2012 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Behdad Esfahbod
*/
#define HB_SHAPER icu_le
#define hb_icu_le_shaper_font_data_t PortableFontInstance
#include "hb-shaper-impl-private.hh"
#include "hb-icu-le/PortableFontInstance.h"
#include "layout/loengine.h"
#include "unicode/unistr.h"
#include "hb-icu.h"
/*
* shaper face data
*/
struct hb_icu_le_shaper_face_data_t {};
hb_icu_le_shaper_face_data_t *
_hb_icu_le_shaper_face_data_create (hb_face_t *face HB_UNUSED)
{
return (hb_icu_le_shaper_face_data_t *) HB_SHAPER_DATA_SUCCEEDED;
}
void
_hb_icu_le_shaper_face_data_destroy (hb_icu_le_shaper_face_data_t *data HB_UNUSED)
{
}
/*
* shaper font data
*/
hb_icu_le_shaper_font_data_t *
_hb_icu_le_shaper_font_data_create (hb_font_t *font)
{
LEErrorCode status = LE_NO_ERROR;
hb_icu_le_shaper_font_data_t *data = new PortableFontInstance (font->face,
font->x_scale,
font->y_scale,
status);
if (status != LE_NO_ERROR) {
delete (data);
return NULL;
}
return data;
}
void
_hb_icu_le_shaper_font_data_destroy (hb_icu_le_shaper_font_data_t *data)
{
delete (data);
}
/*
* shaper shape_plan data
*/
struct hb_icu_le_shaper_shape_plan_data_t {};
hb_icu_le_shaper_shape_plan_data_t *
_hb_icu_le_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan HB_UNUSED,
const hb_feature_t *user_features,
unsigned int num_user_features)
{
return (hb_icu_le_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
}
void
_hb_icu_le_shaper_shape_plan_data_destroy (hb_icu_le_shaper_shape_plan_data_t *data)
{
}
/*
* shaper
*/
hb_bool_t
_hb_icu_le_shape (hb_shape_plan_t *shape_plan,
hb_font_t *font,
hb_buffer_t *buffer,
const hb_feature_t *features,
unsigned int num_features)
{
LEFontInstance *font_instance = HB_SHAPER_DATA_GET (font);
le_int32 script_code = hb_icu_script_from_script (shape_plan->props.script);
le_int32 language_code = -1 /* TODO */;
le_int32 typography_flags = 3; /* Needed for ligatures and kerning */
LEErrorCode status = LE_NO_ERROR;
le_engine *le = le_create ((const le_font *) font_instance,
script_code,
language_code,
typography_flags,
&status);
if (status != LE_NO_ERROR)
{ le_close (le); return false; }
retry:
unsigned int scratch_size;
char *scratch = (char *) buffer->get_scratch_buffer (&scratch_size);
#define ALLOCATE_ARRAY(Type, name, len) \
Type *name = (Type *) scratch; \
scratch += (len) * sizeof ((name)[0]); \
scratch_size -= (len) * sizeof ((name)[0]);
ALLOCATE_ARRAY (LEUnicode, chars, buffer->len);
ALLOCATE_ARRAY (unsigned int, clusters, buffer->len);
/* XXX Use UTF-16 decoder! */
for (unsigned int i = 0; i < buffer->len; i++) {
chars[i] = buffer->info[i].codepoint;
clusters[i] = buffer->info[i].cluster;
}
unsigned int glyph_count = le_layoutChars (le,
chars,
0,
buffer->len,
buffer->len,
HB_DIRECTION_IS_BACKWARD (buffer->props.direction),
0., 0.,
&status);
if (status != LE_NO_ERROR)
{ le_close (le); return false; }
unsigned int num_glyphs = scratch_size / (sizeof (LEGlyphID) +
sizeof (le_int32) +
sizeof (float) * 2);
if (unlikely (glyph_count >= num_glyphs || glyph_count > buffer->allocated)) {
buffer->ensure (buffer->allocated * 2);
if (buffer->in_error)
{ le_close (le); return false; }
goto retry;
}
ALLOCATE_ARRAY (LEGlyphID, glyphs, glyph_count);
ALLOCATE_ARRAY (le_int32, indices, glyph_count);
ALLOCATE_ARRAY (float, positions, glyph_count * 2 + 2);
le_getGlyphs (le, glyphs, &status);
le_getCharIndices (le, indices, &status);
le_getGlyphPositions (le, positions, &status);
#undef ALLOCATE_ARRAY
/* Ok, we've got everything we need, now compose output buffer,
* very, *very*, carefully! */
unsigned int j = 0;
hb_glyph_info_t *info = buffer->info;
for (unsigned int i = 0; i < glyph_count; i++)
{
if (glyphs[i] >= 0xFFFE)
continue;
info[j].codepoint = glyphs[i];
info[j].cluster = clusters[indices[i]];
/* icu-le doesn't seem to have separate advance values. */
info[j].mask = positions[2 * i + 2] - positions[2 * i];
info[j].var1.u32 = 0;
info[j].var2.u32 = -positions[2 * i + 1];
j++;
}
buffer->len = j;
buffer->clear_positions ();
for (unsigned int i = 0; i < buffer->len; i++) {
hb_glyph_info_t *info = &buffer->info[i];
hb_glyph_position_t *pos = &buffer->pos[i];
/* TODO vertical */
pos->x_advance = info->mask;
pos->x_offset = info->var1.u32;
pos->y_offset = info->var2.u32;
}
le_close (le);
return true;
}

View File

@ -323,7 +323,7 @@ hb_icu_unicode_decompose_compatibility (hb_unicode_funcs_t *ufuncs HB_UNUSED,
/* Copy @u into a UTF-16 array to be passed to ICU. */ /* Copy @u into a UTF-16 array to be passed to ICU. */
len = 0; len = 0;
err = FALSE; err = false;
U16_APPEND (utf16, len, ARRAY_LENGTH (utf16), u, err); U16_APPEND (utf16, len, ARRAY_LENGTH (utf16), u, err);
if (err) if (err)
return 0; return 0;

View File

@ -44,7 +44,6 @@
#elif !defined(HB_NO_MT) && (defined(_WIN32) || defined(__CYGWIN__)) #elif !defined(HB_NO_MT) && (defined(_WIN32) || defined(__CYGWIN__))
#define WIN32_LEAN_AND_MEAN
#include <windows.h> #include <windows.h>
typedef CRITICAL_SECTION hb_mutex_impl_t; typedef CRITICAL_SECTION hb_mutex_impl_t;
#define HB_MUTEX_IMPL_INIT { NULL, 0, 0, NULL, NULL, 0 } #define HB_MUTEX_IMPL_INIT { NULL, 0, 0, NULL, NULL, 0 }

View File

@ -1,410 +0,0 @@
/*
* Copyright © 2012 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Behdad Esfahbod
*/
#define HB_SHAPER old
#define hb_old_shaper_face_data_t HB_FaceRec_
#define hb_old_shaper_font_data_t HB_Font_
#include "hb-shaper-impl-private.hh"
#include <harfbuzz.h>
#ifndef HB_DEBUG_OLD
#define HB_DEBUG_OLD (HB_DEBUG+0)
#endif
static HB_Script
hb_old_script_from_script (hb_script_t script)
{
switch ((hb_tag_t) script)
{
default:
case HB_SCRIPT_COMMON: return HB_Script_Common;
case HB_SCRIPT_GREEK: return HB_Script_Greek;
case HB_SCRIPT_CYRILLIC: return HB_Script_Cyrillic;
case HB_SCRIPT_ARMENIAN: return HB_Script_Armenian;
case HB_SCRIPT_HEBREW: return HB_Script_Hebrew;
case HB_SCRIPT_ARABIC: return HB_Script_Arabic;
case HB_SCRIPT_SYRIAC: return HB_Script_Syriac;
case HB_SCRIPT_THAANA: return HB_Script_Thaana;
case HB_SCRIPT_DEVANAGARI: return HB_Script_Devanagari;
case HB_SCRIPT_BENGALI: return HB_Script_Bengali;
case HB_SCRIPT_GURMUKHI: return HB_Script_Gurmukhi;
case HB_SCRIPT_GUJARATI: return HB_Script_Gujarati;
case HB_SCRIPT_ORIYA: return HB_Script_Oriya;
case HB_SCRIPT_TAMIL: return HB_Script_Tamil;
case HB_SCRIPT_TELUGU: return HB_Script_Telugu;
case HB_SCRIPT_KANNADA: return HB_Script_Kannada;
case HB_SCRIPT_MALAYALAM: return HB_Script_Malayalam;
case HB_SCRIPT_SINHALA: return HB_Script_Sinhala;
case HB_SCRIPT_THAI: return HB_Script_Thai;
case HB_SCRIPT_LAO: return HB_Script_Lao;
case HB_SCRIPT_TIBETAN: return HB_Script_Tibetan;
case HB_SCRIPT_MYANMAR: return HB_Script_Myanmar;
case HB_SCRIPT_GEORGIAN: return HB_Script_Georgian;
case HB_SCRIPT_HANGUL: return HB_Script_Hangul;
case HB_SCRIPT_OGHAM: return HB_Script_Ogham;
case HB_SCRIPT_RUNIC: return HB_Script_Runic;
case HB_SCRIPT_KHMER: return HB_Script_Khmer;
case HB_SCRIPT_NKO: return HB_Script_Nko;
case HB_SCRIPT_INHERITED: return HB_Script_Inherited;
}
}
static HB_Bool
hb_old_convertStringToGlyphIndices (HB_Font old_font,
const HB_UChar16 *string,
hb_uint32 length,
HB_Glyph *glyphs,
hb_uint32 *numGlyphs,
HB_Bool rightToLeft)
{
hb_font_t *font = (hb_font_t *) old_font->userData;
for (unsigned int i = 0; i < length; i++)
{
hb_codepoint_t u;
/* XXX Handle UTF-16. Ugh */
u = string[i];
if (rightToLeft)
u = hb_unicode_funcs_get_default ()->mirroring (u);
font->get_glyph (u, 0, &u); /* TODO Variation selectors */
glyphs[i] = u;
}
*numGlyphs = length; /* XXX */
return true;
}
static void
hb_old_getGlyphAdvances (HB_Font old_font,
const HB_Glyph *glyphs,
hb_uint32 numGlyphs,
HB_Fixed *advances,
int flags /*HB_ShaperFlag*/ HB_UNUSED)
{
hb_font_t *font = (hb_font_t *) old_font->userData;
for (unsigned int i = 0; i < numGlyphs; i++)
advances[i] = font->get_glyph_h_advance (glyphs[i]);
}
static HB_Bool
hb_old_canRender (HB_Font old_font,
const HB_UChar16 *string,
hb_uint32 length)
{
return true; /* TODO */
}
static HB_Error
hb_old_getPointInOutline (HB_Font old_font,
HB_Glyph glyph,
int flags /*HB_ShaperFlag*/,
hb_uint32 point,
HB_Fixed *xpos,
HB_Fixed *ypos,
hb_uint32 *nPoints)
{
return HB_Err_Ok; /* TODO */
}
static void
hb_old_getGlyphMetrics (HB_Font old_font,
HB_Glyph glyph,
HB_GlyphMetrics *metrics)
{
hb_font_t *font = (hb_font_t *) old_font->userData;
hb_glyph_extents_t extents;
font->get_glyph_extents (glyph, &extents);
metrics->x = extents.x_bearing;
metrics->y = extents.y_bearing;
metrics->width = extents.width;
metrics->height = extents.height;
metrics->xOffset = font->get_glyph_h_advance (glyph);
metrics->yOffset = 0;
}
static HB_Fixed
hb_old_getFontMetric (HB_Font old_font,
HB_FontMetric metric)
{
hb_font_t *font = (hb_font_t *) old_font->userData;
switch (metric)
{
case HB_FontAscent:
return font->y_scale; /* XXX We don't have ascent data yet. */
default:
return 0;
}
}
static const HB_FontClass hb_old_font_class = {
hb_old_convertStringToGlyphIndices,
hb_old_getGlyphAdvances,
hb_old_canRender,
hb_old_getPointInOutline,
hb_old_getGlyphMetrics,
hb_old_getFontMetric
};
static HB_Error
table_func (void *font, HB_Tag tag, HB_Byte *buffer, HB_UInt *length)
{
hb_face_t *face = (hb_face_t *) font;
hb_blob_t *blob = face->reference_table ((hb_tag_t) tag);
unsigned int capacity = *length;
*length = hb_blob_get_length (blob);
memcpy (buffer, hb_blob_get_data (blob, NULL), MIN (capacity, *length));
hb_blob_destroy (blob);
return HB_Err_Ok;
}
/*
* shaper face data
*/
hb_old_shaper_face_data_t *
_hb_old_shaper_face_data_create (hb_face_t *face)
{
return HB_NewFace (face, table_func);
}
void
_hb_old_shaper_face_data_destroy (hb_old_shaper_face_data_t *data)
{
HB_FreeFace (data);
}
/*
* shaper font data
*/
hb_old_shaper_font_data_t *
_hb_old_shaper_font_data_create (hb_font_t *font)
{
HB_FontRec *data = (HB_FontRec *) calloc (1, sizeof (HB_FontRec));
if (unlikely (!data)) {
DEBUG_MSG (OLD, font, "malloc()ing HB_Font failed");
return NULL;
}
data->klass = &hb_old_font_class;
data->x_ppem = font->x_ppem;
data->y_ppem = font->y_ppem;
data->x_scale = font->x_scale; /* XXX */
data->y_scale = font->y_scale; /* XXX */
data->userData = font;
return data;
}
void
_hb_old_shaper_font_data_destroy (hb_old_shaper_font_data_t *data)
{
free (data);
}
/*
* shaper shape_plan data
*/
struct hb_old_shaper_shape_plan_data_t {};
hb_old_shaper_shape_plan_data_t *
_hb_old_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan HB_UNUSED,
const hb_feature_t *user_features HB_UNUSED,
unsigned int num_user_features HB_UNUSED)
{
return (hb_old_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
}
void
_hb_old_shaper_shape_plan_data_destroy (hb_old_shaper_shape_plan_data_t *data HB_UNUSED)
{
}
/*
* shaper
*/
hb_bool_t
_hb_old_shape (hb_shape_plan_t *shape_plan HB_UNUSED,
hb_font_t *font,
hb_buffer_t *buffer,
const hb_feature_t *features,
unsigned int num_features)
{
hb_face_t *face = font->face;
HB_Face old_face = HB_SHAPER_DATA_GET (face);
HB_Font old_font = HB_SHAPER_DATA_GET (font);
bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
retry:
unsigned int scratch_size;
char *scratch = (char *) buffer->get_scratch_buffer (&scratch_size);
#define utf16_index() var1.u32
HB_UChar16 *pchars = (HB_UChar16 *) scratch;
unsigned int chars_len = 0;
for (unsigned int i = 0; i < buffer->len; i++) {
hb_codepoint_t c = buffer->info[i].codepoint;
buffer->info[i].utf16_index() = chars_len;
if (likely (c < 0x10000))
pchars[chars_len++] = c;
else if (unlikely (c >= 0x110000))
pchars[chars_len++] = 0xFFFD;
else {
pchars[chars_len++] = 0xD800 + ((c - 0x10000) >> 10);
pchars[chars_len++] = 0xDC00 + ((c - 0x10000) & ((1 << 10) - 1));
}
}
#define ALLOCATE_ARRAY(Type, name, len) \
name = (Type *) scratch; \
scratch += (len) * sizeof ((name)[0]); \
scratch_size -= (len) * sizeof ((name)[0]);
HB_ShaperItem item = {0};
ALLOCATE_ARRAY (const HB_UChar16, item.string, chars_len);
ALLOCATE_ARRAY (unsigned short, item.log_clusters, chars_len + 2);
item.stringLength = chars_len;
item.item.pos = 0;
item.item.length = item.stringLength;
item.item.script = hb_old_script_from_script (buffer->props.script);
item.item.bidiLevel = backward ? 1 : 0;
item.font = old_font;
item.face = old_face;
item.shaperFlags = 0;
item.glyphIndicesPresent = false;
/* TODO Alignment. */
unsigned int num_glyphs = scratch_size / (sizeof (HB_Glyph) +
sizeof (HB_GlyphAttributes) +
sizeof (HB_Fixed) +
sizeof (HB_FixedPoint) +
sizeof (uint32_t));
item.num_glyphs = num_glyphs;
ALLOCATE_ARRAY (HB_Glyph, item.glyphs, num_glyphs);
ALLOCATE_ARRAY (HB_GlyphAttributes, item.attributes, num_glyphs);
ALLOCATE_ARRAY (HB_Fixed, item.advances, num_glyphs);
ALLOCATE_ARRAY (HB_FixedPoint, item.offsets, num_glyphs);
/* Apparently in some cases the offsets array will not be fully assigned to.
* Clear it. */
memset (item.offsets, 0, num_glyphs * sizeof (item.offsets[0]));
uint32_t *vis_clusters;
ALLOCATE_ARRAY (uint32_t, vis_clusters, num_glyphs);
#undef ALLOCATE_ARRAY
if (!HB_ShapeItem (&item))
{
if (unlikely (item.num_glyphs > num_glyphs))
{
buffer->ensure (buffer->allocated * 2);
if (buffer->in_error)
return false;
goto retry;
}
return false;
}
num_glyphs = item.num_glyphs;
/* Ok, we've got everything we need, now compose output buffer,
* very, *very*, carefully! */
/* Calculate visual-clusters. That's what we ship. */
for (unsigned int i = 0; i < num_glyphs; i++)
vis_clusters[i] = -1;
for (unsigned int i = 0; i < buffer->len; i++) {
uint32_t *p = &vis_clusters[item.log_clusters[buffer->info[i].utf16_index()]];
*p = MIN (*p, buffer->info[i].cluster);
}
for (unsigned int i = 1; i < num_glyphs; i++)
if (vis_clusters[i] == (uint32_t) -1)
vis_clusters[i] = vis_clusters[i - 1];
#undef utf16_index
buffer->ensure (num_glyphs);
if (buffer->in_error)
return false;
buffer->len = num_glyphs;
hb_glyph_info_t *info = buffer->info;
for (unsigned int i = 0; i < num_glyphs; i++)
{
info[i].codepoint = item.glyphs[i];
info[i].cluster = vis_clusters[i];
info[i].mask = item.advances[i];
info[i].var1.u32 = item.offsets[i].x;
info[i].var2.u32 = item.offsets[i].y;
}
buffer->clear_positions ();
for (unsigned int i = 0; i < num_glyphs; ++i) {
hb_glyph_info_t *info = &buffer->info[i];
hb_glyph_position_t *pos = &buffer->pos[i];
/* TODO vertical */
pos->x_advance = info->mask;
pos->x_offset = info->var1.u32;
pos->y_offset = info->var2.u32;
}
if (HB_DIRECTION_IS_BACKWARD (buffer->props.direction))
buffer->reverse ();
return true;
}

View File

@ -110,9 +110,9 @@ typedef struct OffsetTable
protected: protected:
Tag sfnt_version; /* '\0\001\0\00' if TrueType / 'OTTO' if CFF */ Tag sfnt_version; /* '\0\001\0\00' if TrueType / 'OTTO' if CFF */
USHORT numTables; /* Number of tables. */ USHORT numTables; /* Number of tables. */
USHORT searchRange; /* (Maximum power of 2 <= numTables) x 16 */ USHORT searchRangeZ; /* (Maximum power of 2 <= numTables) x 16 */
USHORT entrySelector; /* Log2(maximum power of 2 <= numTables). */ USHORT entrySelectorZ; /* Log2(maximum power of 2 <= numTables). */
USHORT rangeShift; /* NumTables x 16-searchRange. */ USHORT rangeShiftZ; /* NumTables x 16-searchRange. */
TableRecord tables[VAR]; /* TableRecord entries. numTables items */ TableRecord tables[VAR]; /* TableRecord entries. numTables items */
public: public:
DEFINE_SIZE_ARRAY (12, tables); DEFINE_SIZE_ARRAY (12, tables);
@ -138,8 +138,8 @@ struct TTCHeaderVersion1
protected: protected:
Tag ttcTag; /* TrueType Collection ID string: 'ttcf' */ Tag ttcTag; /* TrueType Collection ID string: 'ttcf' */
FixedVersion version; /* Version of the TTC Header (1.0), FixedVersion version; /* Version of the TTC Header (1.0),
* 0x00010000 */ * 0x00010000u */
LongOffsetLongArrayOf<OffsetTable> ArrayOf<OffsetTo<OffsetTable, ULONG>, ULONG>
table; /* Array of offsets to the OffsetTable for each font table; /* Array of offsets to the OffsetTable for each font
* from the beginning of the file */ * from the beginning of the file */
public: public:
@ -184,7 +184,7 @@ struct TTCHeader
struct { struct {
Tag ttcTag; /* TrueType Collection ID string: 'ttcf' */ Tag ttcTag; /* TrueType Collection ID string: 'ttcf' */
FixedVersion version; /* Version of the TTC Header (1.0 or 2.0), FixedVersion version; /* Version of the TTC Header (1.0 or 2.0),
* 0x00010000 or 0x00020000 */ * 0x00010000u or 0x00020000u */
} header; } header;
TTCHeaderVersion1 version1; TTCHeaderVersion1 version1;
} u; } u;

View File

@ -42,36 +42,36 @@ namespace OT {
/* Cast to struct T, reference to reference */ /* Cast to struct T, reference to reference */
template<typename Type, typename TObject> template<typename Type, typename TObject>
inline const Type& CastR(const TObject &X) static inline const Type& CastR(const TObject &X)
{ return reinterpret_cast<const Type&> (X); } { return reinterpret_cast<const Type&> (X); }
template<typename Type, typename TObject> template<typename Type, typename TObject>
inline Type& CastR(TObject &X) static inline Type& CastR(TObject &X)
{ return reinterpret_cast<Type&> (X); } { return reinterpret_cast<Type&> (X); }
/* Cast to struct T, pointer to pointer */ /* Cast to struct T, pointer to pointer */
template<typename Type, typename TObject> template<typename Type, typename TObject>
inline const Type* CastP(const TObject *X) static inline const Type* CastP(const TObject *X)
{ return reinterpret_cast<const Type*> (X); } { return reinterpret_cast<const Type*> (X); }
template<typename Type, typename TObject> template<typename Type, typename TObject>
inline Type* CastP(TObject *X) static inline Type* CastP(TObject *X)
{ return reinterpret_cast<Type*> (X); } { return reinterpret_cast<Type*> (X); }
/* StructAtOffset<T>(P,Ofs) returns the struct T& that is placed at memory /* StructAtOffset<T>(P,Ofs) returns the struct T& that is placed at memory
* location pointed to by P plus Ofs bytes. */ * location pointed to by P plus Ofs bytes. */
template<typename Type> template<typename Type>
inline const Type& StructAtOffset(const void *P, unsigned int offset) static inline const Type& StructAtOffset(const void *P, unsigned int offset)
{ return * reinterpret_cast<const Type*> ((const char *) P + offset); } { return * reinterpret_cast<const Type*> ((const char *) P + offset); }
template<typename Type> template<typename Type>
inline Type& StructAtOffset(void *P, unsigned int offset) static inline Type& StructAtOffset(void *P, unsigned int offset)
{ return * reinterpret_cast<Type*> ((char *) P + offset); } { return * reinterpret_cast<Type*> ((char *) P + offset); }
/* StructAfter<T>(X) returns the struct T& that is placed after X. /* StructAfter<T>(X) returns the struct T& that is placed after X.
* Works with X of variable size also. X must implement get_size() */ * Works with X of variable size also. X must implement get_size() */
template<typename Type, typename TObject> template<typename Type, typename TObject>
inline const Type& StructAfter(const TObject &X) static inline const Type& StructAfter(const TObject &X)
{ return StructAtOffset<Type>(&X, X.get_size()); } { return StructAtOffset<Type>(&X, X.get_size()); }
template<typename Type, typename TObject> template<typename Type, typename TObject>
inline Type& StructAfter(TObject &X) static inline Type& StructAfter(TObject &X)
{ return StructAtOffset<Type>(&X, X.get_size()); } { return StructAtOffset<Type>(&X, X.get_size()); }
@ -132,7 +132,7 @@ inline Type& StructAfter(TObject &X)
/* Global nul-content Null pool. Enlarge as necessary. */ /* Global nul-content Null pool. Enlarge as necessary. */
/* TODO This really should be a extern HB_INTERNAL and defined somewhere... */ /* TODO This really should be a extern HB_INTERNAL and defined somewhere... */
static const void *_NullPool[64 / sizeof (void *)]; static const void *_NullPool[(256+8) / sizeof (void *)];
/* Generic nul-content Null objects. */ /* Generic nul-content Null objects. */
template <typename Type> template <typename Type>
@ -145,7 +145,7 @@ static inline const Type& Null (void) {
#define DEFINE_NULL_DATA(Type, data) \ #define DEFINE_NULL_DATA(Type, data) \
static const char _Null##Type[sizeof (Type) + 1] = data; /* +1 is for nul-termination in data */ \ static const char _Null##Type[sizeof (Type) + 1] = data; /* +1 is for nul-termination in data */ \
template <> \ template <> \
inline const Type& Null<Type> (void) { \ /*static*/ inline const Type& Null<Type> (void) { \
return *CastP<Type> (_Null##Type); \ return *CastP<Type> (_Null##Type); \
} /* The following line really exists such that we end in a place needing semicolon */ \ } /* The following line really exists such that we end in a place needing semicolon */ \
ASSERT_STATIC (Type::min_size + 1 <= sizeof (_Null##Type)) ASSERT_STATIC (Type::min_size + 1 <= sizeof (_Null##Type))
@ -266,6 +266,15 @@ struct hb_sanitize_context_t
return TRACE_RETURN (this->writable); return TRACE_RETURN (this->writable);
} }
template <typename Type, typename ValueType>
inline bool try_set (Type *obj, const ValueType &v) {
if (this->may_edit (obj, obj->static_size)) {
obj->set (v);
return true;
}
return false;
}
mutable unsigned int debug_depth; mutable unsigned int debug_depth;
const char *start, *end; const char *start, *end;
bool writable; bool writable;
@ -280,7 +289,7 @@ template <typename Type>
struct Sanitizer struct Sanitizer
{ {
static hb_blob_t *sanitize (hb_blob_t *blob) { static hb_blob_t *sanitize (hb_blob_t *blob) {
hb_sanitize_context_t c[1] = {{0}}; hb_sanitize_context_t c[1] = {{0, NULL, NULL, false, 0, NULL}};
bool sane; bool sane;
/* TODO is_sane() stuff */ /* TODO is_sane() stuff */
@ -572,6 +581,7 @@ struct IntType
DEFINE_SIZE_STATIC (Size); DEFINE_SIZE_STATIC (Size);
}; };
typedef uint8_t BYTE; /* 8-bit unsigned integer. */
typedef IntType<uint16_t, 2> USHORT; /* 16-bit unsigned integer. */ typedef IntType<uint16_t, 2> USHORT; /* 16-bit unsigned integer. */
typedef IntType<int16_t, 2> SHORT; /* 16-bit signed integer. */ typedef IntType<int16_t, 2> SHORT; /* 16-bit signed integer. */
typedef IntType<uint32_t, 4> ULONG; /* 32-bit unsigned integer. */ typedef IntType<uint32_t, 4> ULONG; /* 32-bit unsigned integer. */
@ -616,24 +626,17 @@ typedef USHORT GlyphID;
/* Script/language-system/feature index */ /* Script/language-system/feature index */
struct Index : USHORT { struct Index : USHORT {
static const unsigned int NOT_FOUND_INDEX = 0xFFFF; static const unsigned int NOT_FOUND_INDEX = 0xFFFFu;
}; };
DEFINE_NULL_DATA (Index, "\xff\xff"); DEFINE_NULL_DATA (Index, "\xff\xff");
/* Offset to a table, same as uint16 (length = 16 bits), Null offset = 0x0000 */ /* Offset, Null offset = 0 */
struct Offset : USHORT template <typename Type=USHORT>
struct Offset : Type
{ {
inline bool is_null (void) const { return 0 == *this; } inline bool is_null (void) const { return 0 == *this; }
public: public:
DEFINE_SIZE_STATIC (2); DEFINE_SIZE_STATIC (sizeof(Type));
};
/* LongOffset to a table, same as uint32 (length = 32 bits), Null offset = 0x00000000 */
struct LongOffset : ULONG
{
inline bool is_null (void) const { return 0 == *this; }
public:
DEFINE_SIZE_STATIC (4);
}; };
@ -682,12 +685,12 @@ struct FixedVersion
/* /*
* Template subclasses of Offset and LongOffset that do the dereferencing. * Template subclasses of Offset that do the dereferencing.
* Use: (base+offset) * Use: (base+offset)
*/ */
template <typename OffsetType, typename Type> template <typename Type, typename OffsetType=USHORT>
struct GenericOffsetTo : OffsetType struct OffsetTo : Offset<OffsetType>
{ {
inline const Type& operator () (const void *base) const inline const Type& operator () (const void *base) const
{ {
@ -721,40 +724,25 @@ struct GenericOffsetTo : OffsetType
return TRACE_RETURN (likely (obj.sanitize (c, user_data)) || neuter (c)); return TRACE_RETURN (likely (obj.sanitize (c, user_data)) || neuter (c));
} }
inline bool try_set (hb_sanitize_context_t *c, const OffsetType &v) {
if (c->may_edit (this, this->static_size)) {
this->set (v);
return true;
}
return false;
}
/* Set the offset to Null */ /* Set the offset to Null */
inline bool neuter (hb_sanitize_context_t *c) { inline bool neuter (hb_sanitize_context_t *c) {
if (c->may_edit (this, this->static_size)) { return c->try_set (this, 0);
this->set (0); /* 0 is Null offset */
return true;
}
return false;
} }
DEFINE_SIZE_STATIC (sizeof(OffsetType));
}; };
template <typename Base, typename OffsetType, typename Type> template <typename Base, typename OffsetType, typename Type>
inline const Type& operator + (const Base &base, const GenericOffsetTo<OffsetType, Type> &offset) { return offset (base); } static inline const Type& operator + (const Base &base, const OffsetTo<Type, OffsetType> &offset) { return offset (base); }
template <typename Base, typename OffsetType, typename Type> template <typename Base, typename OffsetType, typename Type>
inline Type& operator + (Base &base, GenericOffsetTo<OffsetType, Type> &offset) { return offset (base); } static inline Type& operator + (Base &base, OffsetTo<Type, OffsetType> &offset) { return offset (base); }
template <typename Type>
struct OffsetTo : GenericOffsetTo<Offset, Type> {};
template <typename Type>
struct LongOffsetTo : GenericOffsetTo<LongOffset, Type> {};
/* /*
* Array Types * Array Types
*/ */
template <typename LenType, typename Type> /* An array with a number of elements. */
struct GenericArrayOf template <typename Type, typename LenType=USHORT>
struct ArrayOf
{ {
const Type *sub_array (unsigned int start_offset, unsigned int *pcount /* IN/OUT */) const const Type *sub_array (unsigned int start_offset, unsigned int *pcount /* IN/OUT */) const
{ {
@ -837,6 +825,16 @@ struct GenericArrayOf
return TRACE_RETURN (true); return TRACE_RETURN (true);
} }
template <typename SearchType>
inline int lsearch (const SearchType &x) const
{
unsigned int count = len;
for (unsigned int i = 0; i < count; i++)
if (!this->array[i].cmp (x))
return i;
return -1;
}
private: private:
inline bool sanitize_shallow (hb_sanitize_context_t *c) { inline bool sanitize_shallow (hb_sanitize_context_t *c) {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
@ -850,26 +848,10 @@ struct GenericArrayOf
DEFINE_SIZE_ARRAY (sizeof (LenType), array); DEFINE_SIZE_ARRAY (sizeof (LenType), array);
}; };
/* An array with a USHORT number of elements. */
template <typename Type>
struct ArrayOf : GenericArrayOf<USHORT, Type> {};
/* An array with a ULONG number of elements. */
template <typename Type>
struct LongArrayOf : GenericArrayOf<ULONG, Type> {};
/* Array of Offset's */ /* Array of Offset's */
template <typename Type> template <typename Type>
struct OffsetArrayOf : ArrayOf<OffsetTo<Type> > {}; struct OffsetArrayOf : ArrayOf<OffsetTo<Type> > {};
/* Array of LongOffset's */
template <typename Type>
struct LongOffsetArrayOf : ArrayOf<LongOffsetTo<Type> > {};
/* LongArray of LongOffset's */
template <typename Type>
struct LongOffsetLongArrayOf : LongArrayOf<LongOffsetTo<Type> > {};
/* Array of offsets relative to the beginning of the array itself. */ /* Array of offsets relative to the beginning of the array itself. */
template <typename Type> template <typename Type>
struct OffsetListOf : OffsetArrayOf<Type> struct OffsetListOf : OffsetArrayOf<Type>
@ -892,9 +874,8 @@ struct OffsetListOf : OffsetArrayOf<Type>
}; };
/* An array with a USHORT number of elements, /* An array starting at second element. */
* starting at second element. */ template <typename Type, typename LenType=USHORT>
template <typename Type>
struct HeadlessArrayOf struct HeadlessArrayOf
{ {
inline const Type& operator [] (unsigned int i) const inline const Type& operator [] (unsigned int i) const
@ -941,19 +922,19 @@ struct HeadlessArrayOf
return TRACE_RETURN (true); return TRACE_RETURN (true);
} }
USHORT len; LenType len;
Type array[VAR]; Type array[VAR];
public: public:
DEFINE_SIZE_ARRAY (sizeof (USHORT), array); DEFINE_SIZE_ARRAY (sizeof (LenType), array);
}; };
/* An array with sorted elements. Supports binary searching. */ /* An array with sorted elements. Supports binary searching. */
template <typename Type> template <typename Type, typename LenType=USHORT>
struct SortedArrayOf : ArrayOf<Type> { struct SortedArrayOf : ArrayOf<Type, LenType>
{
template <typename SearchType> template <typename SearchType>
inline int search (const SearchType &x) const inline int bsearch (const SearchType &x) const
{ {
/* Hand-coded bsearch here since this is in the hot inner loop. */ /* Hand-coded bsearch here since this is in the hot inner loop. */
int min = 0, max = (int) this->len - 1; int min = 0, max = (int) this->len - 1;

View File

@ -0,0 +1,517 @@
/*
* Copyright © 2014 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_OT_CMAP_TABLE_HH
#define HB_OT_CMAP_TABLE_HH
#include "hb-open-type-private.hh"
namespace OT {
/*
* cmap -- Character To Glyph Index Mapping Table
*/
#define HB_OT_TAG_cmap HB_TAG('c','m','a','p')
struct CmapSubtableFormat0
{
inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
{
hb_codepoint_t gid = codepoint < 256 ? glyphIdArray[codepoint] : 0;
if (!gid)
return false;
*glyph = gid;
return true;
}
inline bool sanitize (hb_sanitize_context_t *c) {
TRACE_SANITIZE (this);
return TRACE_RETURN (c->check_struct (this));
}
protected:
USHORT format; /* Format number is set to 0. */
USHORT lengthZ; /* Byte length of this subtable. */
USHORT languageZ; /* Ignore. */
BYTE glyphIdArray[256];/* An array that maps character
* code to glyph index values. */
public:
DEFINE_SIZE_STATIC (6 + 256);
};
struct CmapSubtableFormat4
{
inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
{
unsigned int segCount;
const USHORT *endCount;
const USHORT *startCount;
const USHORT *idDelta;
const USHORT *idRangeOffset;
const USHORT *glyphIdArray;
unsigned int glyphIdArrayLength;
segCount = this->segCountX2 / 2;
endCount = this->values;
startCount = endCount + segCount + 1;
idDelta = startCount + segCount;
idRangeOffset = idDelta + segCount;
glyphIdArray = idRangeOffset + segCount;
glyphIdArrayLength = (this->length - 16 - 8 * segCount) / 2;
/* Custom two-array bsearch. */
int min = 0, max = (int) segCount - 1;
unsigned int i;
while (min <= max)
{
int mid = (min + max) / 2;
if (codepoint < startCount[mid])
max = mid - 1;
else if (codepoint > endCount[mid])
min = mid + 1;
else
{
i = mid;
goto found;
}
}
return false;
found:
hb_codepoint_t gid;
unsigned int rangeOffset = idRangeOffset[i];
if (rangeOffset == 0)
gid = codepoint + idDelta[i];
else
{
/* Somebody has been smoking... */
unsigned int index = rangeOffset / 2 + (codepoint - startCount[i]) + i - segCount;
if (unlikely (index >= glyphIdArrayLength))
return false;
gid = glyphIdArray[index];
if (unlikely (!gid))
return false;
gid += idDelta[i];
}
*glyph = gid & 0xFFFFu;
return true;
}
inline bool sanitize (hb_sanitize_context_t *c)
{
TRACE_SANITIZE (this);
if (unlikely (!c->check_struct (this)))
return TRACE_RETURN (false);
if (unlikely (!c->check_range (this, length)))
{
/* Some broken fonts have too long of a "length" value.
* If that is the case, just change the value to truncate
* the subtable at the end of the blob. */
uint16_t new_length = (uint16_t) MIN ((uintptr_t) 65535,
(uintptr_t) (c->end -
(char *) this));
if (!c->try_set (&length, new_length))
return TRACE_RETURN (false);
}
return TRACE_RETURN (16 + 4 * (unsigned int) segCountX2 <= length);
}
protected:
USHORT format; /* Format number is set to 4. */
USHORT length; /* This is the length in bytes of the
* subtable. */
USHORT languageZ; /* Ignore. */
USHORT segCountX2; /* 2 x segCount. */
USHORT searchRangeZ; /* 2 * (2**floor(log2(segCount))) */
USHORT entrySelectorZ; /* log2(searchRange/2) */
USHORT rangeShiftZ; /* 2 x segCount - searchRange */
USHORT values[VAR];
#if 0
USHORT endCount[segCount]; /* End characterCode for each segment,
* last=0xFFFFu. */
USHORT reservedPad; /* Set to 0. */
USHORT startCount[segCount]; /* Start character code for each segment. */
SHORT idDelta[segCount]; /* Delta for all character codes in segment. */
USHORT idRangeOffset[segCount];/* Offsets into glyphIdArray or 0 */
USHORT glyphIdArray[VAR]; /* Glyph index array (arbitrary length) */
#endif
public:
DEFINE_SIZE_ARRAY (14, values);
};
struct CmapSubtableLongGroup
{
friend struct CmapSubtableFormat12;
friend struct CmapSubtableFormat13;
int cmp (hb_codepoint_t codepoint) const
{
if (codepoint < startCharCode) return -1;
if (codepoint > endCharCode) return +1;
return 0;
}
inline bool sanitize (hb_sanitize_context_t *c) {
TRACE_SANITIZE (this);
return TRACE_RETURN (c->check_struct (this));
}
private:
ULONG startCharCode; /* First character code in this group. */
ULONG endCharCode; /* Last character code in this group. */
ULONG glyphID; /* Glyph index; interpretation depends on
* subtable format. */
public:
DEFINE_SIZE_STATIC (12);
};
template <typename UINT>
struct CmapSubtableTrimmed
{
inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
{
/* Rely on our implicit array bound-checking. */
hb_codepoint_t gid = glyphIdArray[codepoint - startCharCode];
if (!gid)
return false;
*glyph = gid;
return true;
}
inline bool sanitize (hb_sanitize_context_t *c) {
TRACE_SANITIZE (this);
return TRACE_RETURN (c->check_struct (this) && glyphIdArray.sanitize (c));
}
protected:
UINT formatReserved; /* Subtable format and (maybe) padding. */
UINT lengthZ; /* Byte length of this subtable. */
UINT languageZ; /* Ignore. */
UINT startCharCode; /* First character code covered. */
ArrayOf<GlyphID, UINT>
glyphIdArray; /* Array of glyph index values for character
* codes in the range. */
public:
DEFINE_SIZE_ARRAY (5 * sizeof (UINT), glyphIdArray);
};
struct CmapSubtableFormat6 : CmapSubtableTrimmed<USHORT> {};
struct CmapSubtableFormat10 : CmapSubtableTrimmed<ULONG > {};
template <typename T>
struct CmapSubtableLongSegmented
{
inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
{
int i = groups.bsearch (codepoint);
if (i == -1)
return false;
*glyph = T::group_get_glyph (groups[i], codepoint);
return true;
}
inline bool sanitize (hb_sanitize_context_t *c) {
TRACE_SANITIZE (this);
return TRACE_RETURN (c->check_struct (this) && groups.sanitize (c));
}
protected:
USHORT format; /* Subtable format; set to 12. */
USHORT reservedZ; /* Reserved; set to 0. */
ULONG lengthZ; /* Byte length of this subtable. */
ULONG languageZ; /* Ignore. */
SortedArrayOf<CmapSubtableLongGroup, ULONG>
groups; /* Groupings. */
public:
DEFINE_SIZE_ARRAY (16, groups);
};
struct CmapSubtableFormat12 : CmapSubtableLongSegmented<CmapSubtableFormat12>
{
static inline hb_codepoint_t group_get_glyph (const CmapSubtableLongGroup &group,
hb_codepoint_t u)
{ return group.glyphID + (u - group.startCharCode); }
};
struct CmapSubtableFormat13 : CmapSubtableLongSegmented<CmapSubtableFormat13>
{
static inline hb_codepoint_t group_get_glyph (const CmapSubtableLongGroup &group,
hb_codepoint_t u HB_UNUSED)
{ return group.glyphID; }
};
typedef enum
{
GLYPH_VARIANT_NOT_FOUND = 0,
GLYPH_VARIANT_FOUND = 1,
GLYPH_VARIANT_USE_DEFAULT = 2
} glyph_variant_t;
struct UnicodeValueRange
{
inline int cmp (const hb_codepoint_t &codepoint) const
{
if (codepoint < startUnicodeValue) return -1;
if (codepoint > startUnicodeValue + additionalCount) return +1;
return 0;
}
inline bool sanitize (hb_sanitize_context_t *c) {
TRACE_SANITIZE (this);
return TRACE_RETURN (c->check_struct (this));
}
UINT24 startUnicodeValue; /* First value in this range. */
BYTE additionalCount; /* Number of additional values in this
* range. */
public:
DEFINE_SIZE_STATIC (4);
};
typedef SortedArrayOf<UnicodeValueRange, ULONG> DefaultUVS;
struct UVSMapping
{
inline int cmp (const hb_codepoint_t &codepoint) const
{
return unicodeValue.cmp (codepoint);
}
inline bool sanitize (hb_sanitize_context_t *c) {
TRACE_SANITIZE (this);
return TRACE_RETURN (c->check_struct (this));
}
UINT24 unicodeValue; /* Base Unicode value of the UVS */
GlyphID glyphID; /* Glyph ID of the UVS */
public:
DEFINE_SIZE_STATIC (5);
};
typedef SortedArrayOf<UVSMapping, ULONG> NonDefaultUVS;
struct VariationSelectorRecord
{
inline glyph_variant_t get_glyph (hb_codepoint_t codepoint,
hb_codepoint_t *glyph,
const void *base) const
{
int i;
const DefaultUVS &defaults = base+defaultUVS;
i = defaults.bsearch (codepoint);
if (i != -1)
return GLYPH_VARIANT_USE_DEFAULT;
const NonDefaultUVS &nonDefaults = base+nonDefaultUVS;
i = nonDefaults.bsearch (codepoint);
if (i != -1)
{
*glyph = nonDefaults[i].glyphID;
return GLYPH_VARIANT_FOUND;
}
return GLYPH_VARIANT_NOT_FOUND;
}
inline int cmp (const hb_codepoint_t &variation_selector) const
{
return varSelector.cmp (variation_selector);
}
inline bool sanitize (hb_sanitize_context_t *c, void *base) {
TRACE_SANITIZE (this);
return TRACE_RETURN (c->check_struct (this) &&
defaultUVS.sanitize (c, base) &&
nonDefaultUVS.sanitize (c, base));
}
UINT24 varSelector; /* Variation selector. */
OffsetTo<DefaultUVS, ULONG>
defaultUVS; /* Offset to Default UVS Table. May be 0. */
OffsetTo<NonDefaultUVS, ULONG>
nonDefaultUVS; /* Offset to Non-Default UVS Table. May be 0. */
public:
DEFINE_SIZE_STATIC (11);
};
struct CmapSubtableFormat14
{
inline glyph_variant_t get_glyph_variant (hb_codepoint_t codepoint,
hb_codepoint_t variation_selector,
hb_codepoint_t *glyph) const
{
return record[record.bsearch(variation_selector)].get_glyph (codepoint, glyph, this);
}
inline bool sanitize (hb_sanitize_context_t *c) {
TRACE_SANITIZE (this);
return TRACE_RETURN (c->check_struct (this) &&
record.sanitize (c, this));
}
protected:
USHORT format; /* Format number is set to 0. */
ULONG lengthZ; /* Byte length of this subtable. */
SortedArrayOf<VariationSelectorRecord, ULONG>
record; /* Variation selector records; sorted
* in increasing order of `varSelector'. */
public:
DEFINE_SIZE_ARRAY (10, record);
};
struct CmapSubtable
{
/* Note: We intentionally do NOT implement subtable formats 2 and 8. */
inline bool get_glyph (hb_codepoint_t codepoint,
hb_codepoint_t *glyph) const
{
switch (u.format) {
case 0: return u.format0 .get_glyph(codepoint, glyph);
case 4: return u.format4 .get_glyph(codepoint, glyph);
case 6: return u.format6 .get_glyph(codepoint, glyph);
case 10: return u.format10.get_glyph(codepoint, glyph);
case 12: return u.format12.get_glyph(codepoint, glyph);
case 13: return u.format13.get_glyph(codepoint, glyph);
case 14:
default: return false;
}
}
inline glyph_variant_t get_glyph_variant (hb_codepoint_t codepoint,
hb_codepoint_t variation_selector,
hb_codepoint_t *glyph) const
{
switch (u.format) {
case 14: return u.format14.get_glyph_variant(codepoint, variation_selector, glyph);
default: return GLYPH_VARIANT_NOT_FOUND;
}
}
inline bool sanitize (hb_sanitize_context_t *c) {
TRACE_SANITIZE (this);
if (!u.format.sanitize (c)) return TRACE_RETURN (false);
switch (u.format) {
case 0: return TRACE_RETURN (u.format0 .sanitize (c));
case 4: return TRACE_RETURN (u.format4 .sanitize (c));
case 6: return TRACE_RETURN (u.format6 .sanitize (c));
case 10: return TRACE_RETURN (u.format10.sanitize (c));
case 12: return TRACE_RETURN (u.format12.sanitize (c));
case 13: return TRACE_RETURN (u.format13.sanitize (c));
case 14: return TRACE_RETURN (u.format14.sanitize (c));
default:return TRACE_RETURN (true);
}
}
protected:
union {
USHORT format; /* Format identifier */
CmapSubtableFormat0 format0;
CmapSubtableFormat4 format4;
CmapSubtableFormat6 format6;
CmapSubtableFormat10 format10;
CmapSubtableFormat12 format12;
CmapSubtableFormat13 format13;
CmapSubtableFormat14 format14;
} u;
public:
DEFINE_SIZE_UNION (2, format);
};
struct EncodingRecord
{
inline int cmp (const EncodingRecord &other) const
{
int ret;
ret = platformID.cmp (other.platformID);
if (ret) return ret;
ret = encodingID.cmp (other.encodingID);
if (ret) return ret;
return 0;
}
inline bool sanitize (hb_sanitize_context_t *c, void *base) {
TRACE_SANITIZE (this);
return TRACE_RETURN (c->check_struct (this) &&
subtable.sanitize (c, base));
}
USHORT platformID; /* Platform ID. */
USHORT encodingID; /* Platform-specific encoding ID. */
OffsetTo<CmapSubtable, ULONG>
subtable; /* Byte offset from beginning of table to the subtable for this encoding. */
public:
DEFINE_SIZE_STATIC (8);
};
struct cmap
{
static const hb_tag_t tableTag = HB_OT_TAG_cmap;
inline const CmapSubtable *find_subtable (unsigned int platform_id,
unsigned int encoding_id) const
{
EncodingRecord key;
key.platformID.set (platform_id);
key.encodingID.set (encoding_id);
/* Note: We can use bsearch, but since it has no performance
* implications, we use lsearch and as such accept fonts with
* unsorted subtable list. */
int result = encodingRecord./*bsearch*/lsearch (key);
if (result == -1 || !encodingRecord[result].subtable)
return NULL;
return &(this+encodingRecord[result].subtable);
}
inline bool sanitize (hb_sanitize_context_t *c) {
TRACE_SANITIZE (this);
return TRACE_RETURN (c->check_struct (this) &&
likely (version == 0) &&
encodingRecord.sanitize (c, this));
}
USHORT version; /* Table version number (0). */
SortedArrayOf<EncodingRecord>
encodingRecord; /* Encoding tables. */
public:
DEFINE_SIZE_ARRAY (4, encodingRecord);
};
} /* namespace OT */
#endif /* HB_OT_CMAP_TABLE_HH */

View File

@ -0,0 +1,289 @@
/*
* Copyright © 2011,2014 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Behdad Esfahbod, Roozbeh Pournader
*/
#include "hb-private.hh"
#include "hb-ot.h"
#include "hb-font-private.hh"
#include "hb-ot-cmap-table.hh"
#include "hb-ot-hhea-table.hh"
#include "hb-ot-hmtx-table.hh"
struct hb_ot_font_t
{
unsigned int num_glyphs;
unsigned int num_hmetrics;
const OT::hmtx *hmtx;
hb_blob_t *hmtx_blob;
const OT::CmapSubtable *cmap;
const OT::CmapSubtable *cmap_uvs;
hb_blob_t *cmap_blob;
};
static hb_ot_font_t *
_hb_ot_font_create (hb_font_t *font)
{
hb_ot_font_t *ot_font = (hb_ot_font_t *) calloc (1, sizeof (hb_ot_font_t));
if (unlikely (!ot_font))
return NULL;
ot_font->num_glyphs = font->face->get_num_glyphs ();
{
hb_blob_t *hhea_blob = OT::Sanitizer<OT::hhea>::sanitize (font->face->reference_table (HB_OT_TAG_hhea));
const OT::hhea *hhea = OT::Sanitizer<OT::hhea>::lock_instance (hhea_blob);
ot_font->num_hmetrics = hhea->numberOfHMetrics;
hb_blob_destroy (hhea_blob);
}
ot_font->hmtx_blob = OT::Sanitizer<OT::hmtx>::sanitize (font->face->reference_table (HB_OT_TAG_hmtx));
if (unlikely (!ot_font->num_hmetrics ||
2 * (ot_font->num_hmetrics + ot_font->num_glyphs) < hb_blob_get_length (ot_font->hmtx_blob)))
{
hb_blob_destroy (ot_font->hmtx_blob);
free (ot_font);
return NULL;
}
ot_font->hmtx = OT::Sanitizer<OT::hmtx>::lock_instance (ot_font->hmtx_blob);
ot_font->cmap_blob = OT::Sanitizer<OT::cmap>::sanitize (font->face->reference_table (HB_OT_TAG_cmap));
const OT::cmap *cmap = OT::Sanitizer<OT::cmap>::lock_instance (ot_font->cmap_blob);
const OT::CmapSubtable *subtable = NULL;
const OT::CmapSubtable *subtable_uvs = NULL;
/* 32-bit subtables. */
if (!subtable) subtable = cmap->find_subtable (0, 6);
if (!subtable) subtable = cmap->find_subtable (0, 4);
if (!subtable) subtable = cmap->find_subtable (3, 10);
/* 16-bit subtables. */
if (!subtable) subtable = cmap->find_subtable (0, 3);
if (!subtable) subtable = cmap->find_subtable (3, 1);
/* Meh. */
if (!subtable) subtable = &OT::Null(OT::CmapSubtable);
/* UVS subtable. */
if (!subtable_uvs) subtable_uvs = cmap->find_subtable (0, 5);
/* Meh. */
if (!subtable_uvs) subtable_uvs = &OT::Null(OT::CmapSubtable);
ot_font->cmap = subtable;
ot_font->cmap_uvs = subtable_uvs;
return ot_font;
}
static void
_hb_ot_font_destroy (hb_ot_font_t *ot_font)
{
hb_blob_destroy (ot_font->cmap_blob);
hb_blob_destroy (ot_font->hmtx_blob);
free (ot_font);
}
static hb_bool_t
hb_ot_get_glyph (hb_font_t *font HB_UNUSED,
void *font_data,
hb_codepoint_t unicode,
hb_codepoint_t variation_selector,
hb_codepoint_t *glyph,
void *user_data HB_UNUSED)
{
const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
if (unlikely (variation_selector))
{
switch (ot_font->cmap_uvs->get_glyph_variant (unicode,
variation_selector,
glyph))
{
case OT::GLYPH_VARIANT_NOT_FOUND: return false;
case OT::GLYPH_VARIANT_FOUND: return true;
case OT::GLYPH_VARIANT_USE_DEFAULT: break;
}
}
return ot_font->cmap->get_glyph (unicode, glyph);
}
static hb_position_t
hb_ot_get_glyph_h_advance (hb_font_t *font HB_UNUSED,
void *font_data,
hb_codepoint_t glyph,
void *user_data HB_UNUSED)
{
const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
if (unlikely (glyph >= ot_font->num_glyphs))
return 0; /* Maybe better to return notdef's advance instead? */
if (glyph >= ot_font->num_hmetrics)
glyph = ot_font->num_hmetrics - 1;
return font->em_scale_x (ot_font->hmtx->longHorMetric[glyph].advanceWidth);
}
static hb_position_t
hb_ot_get_glyph_v_advance (hb_font_t *font HB_UNUSED,
void *font_data,
hb_codepoint_t glyph,
void *user_data HB_UNUSED)
{
/* TODO */
return 0;
}
static hb_bool_t
hb_ot_get_glyph_h_origin (hb_font_t *font HB_UNUSED,
void *font_data HB_UNUSED,
hb_codepoint_t glyph HB_UNUSED,
hb_position_t *x HB_UNUSED,
hb_position_t *y HB_UNUSED,
void *user_data HB_UNUSED)
{
/* We always work in the horizontal coordinates. */
return true;
}
static hb_bool_t
hb_ot_get_glyph_v_origin (hb_font_t *font HB_UNUSED,
void *font_data,
hb_codepoint_t glyph,
hb_position_t *x,
hb_position_t *y,
void *user_data HB_UNUSED)
{
/* TODO */
return false;
}
static hb_position_t
hb_ot_get_glyph_h_kerning (hb_font_t *font,
void *font_data,
hb_codepoint_t left_glyph,
hb_codepoint_t right_glyph,
void *user_data HB_UNUSED)
{
/* TODO */
return 0;
}
static hb_position_t
hb_ot_get_glyph_v_kerning (hb_font_t *font HB_UNUSED,
void *font_data HB_UNUSED,
hb_codepoint_t top_glyph HB_UNUSED,
hb_codepoint_t bottom_glyph HB_UNUSED,
void *user_data HB_UNUSED)
{
return 0;
}
static hb_bool_t
hb_ot_get_glyph_extents (hb_font_t *font HB_UNUSED,
void *font_data,
hb_codepoint_t glyph,
hb_glyph_extents_t *extents,
void *user_data HB_UNUSED)
{
/* TODO */
return false;
}
static hb_bool_t
hb_ot_get_glyph_contour_point (hb_font_t *font HB_UNUSED,
void *font_data,
hb_codepoint_t glyph,
unsigned int point_index,
hb_position_t *x,
hb_position_t *y,
void *user_data HB_UNUSED)
{
/* TODO */
return false;
}
static hb_bool_t
hb_ot_get_glyph_name (hb_font_t *font HB_UNUSED,
void *font_data,
hb_codepoint_t glyph,
char *name, unsigned int size,
void *user_data HB_UNUSED)
{
/* TODO */
return false;
}
static hb_bool_t
hb_ot_get_glyph_from_name (hb_font_t *font HB_UNUSED,
void *font_data,
const char *name, int len, /* -1 means nul-terminated */
hb_codepoint_t *glyph,
void *user_data HB_UNUSED)
{
/* TODO */
return false;
}
static hb_font_funcs_t *
_hb_ot_get_font_funcs (void)
{
static const hb_font_funcs_t ot_ffuncs = {
HB_OBJECT_HEADER_STATIC,
true, /* immutable */
{
#define HB_FONT_FUNC_IMPLEMENT(name) hb_ot_get_##name,
HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
#undef HB_FONT_FUNC_IMPLEMENT
}
};
return const_cast<hb_font_funcs_t *> (&ot_ffuncs);
}
void
hb_ot_font_set_funcs (hb_font_t *font)
{
hb_ot_font_t *ot_font = _hb_ot_font_create (font);
if (unlikely (!ot_font))
return;
hb_font_set_funcs (font,
_hb_ot_get_font_funcs (),
ot_font,
(hb_destroy_func_t) _hb_ot_font_destroy);
}

View File

@ -1,5 +1,5 @@
/* /*
* Copyright © 2012 Google, Inc. * Copyright © 2014 Google, Inc.
* *
* This is part of HarfBuzz, a text shaping library. * This is part of HarfBuzz, a text shaping library.
* *
@ -21,31 +21,21 @@
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
* *
* Google Author(s): Behdad Esfahbod * Google Author(s): Behdad Esfahbod, Roozbeh Pournader
*/ */
#include "hb-ot-shape-complex-indic-private.hh" #ifndef HB_OT_FONT_H
#define HB_OT_FONT_H
int #include "hb.h"
main (void)
{
hb_unicode_funcs_t *funcs = hb_unicode_funcs_get_default ();
printf ("There are split matras without a Unicode decomposition:\n"); HB_BEGIN_DECLS
for (hb_codepoint_t u = 0; u < 0x110000; u++)
{
unsigned int type = get_indic_categories (u);
unsigned int category = type & 0x0F;
unsigned int position = type >> 4;
hb_unicode_general_category_t cat = hb_unicode_general_category (funcs, u); void
unsigned int ccc = hb_unicode_combining_class (funcs, u); hb_ot_font_set_funcs (hb_font_t *font);
if (category == OT_M && ccc)
printf ("U+%04X %d\n", u, ccc);
// hb_codepoint_t a, b;
// if (!hb_unicode_decompose (funcs, u, &a, &b)) HB_END_DECLS
// printf ("U+%04X %x %x\n", u, category, position);
} #endif /* HB_OT_FONT_H */
}

View File

@ -58,12 +58,12 @@ struct head
protected: protected:
FixedVersion version; /* Version of the head table--currently FixedVersion version; /* Version of the head table--currently
* 0x00010000 for version 1.0. */ * 0x00010000u for version 1.0. */
FixedVersion fontRevision; /* Set by font manufacturer. */ FixedVersion fontRevision; /* Set by font manufacturer. */
ULONG checkSumAdjustment; /* To compute: set it to 0, sum the ULONG checkSumAdjustment; /* To compute: set it to 0, sum the
* entire font as ULONG, then store * entire font as ULONG, then store
* 0xB1B0AFBA - sum. */ * 0xB1B0AFBAu - sum. */
ULONG magicNumber; /* Set to 0x5F0F3CF5. */ ULONG magicNumber; /* Set to 0x5F0F3CF5u. */
USHORT flags; /* Bit 0: Baseline for font at y=0; USHORT flags; /* Bit 0: Baseline for font at y=0;
* Bit 1: Left sidebearing point at x=0; * Bit 1: Left sidebearing point at x=0;
* Bit 2: Instructions may depend on point size; * Bit 2: Instructions may depend on point size;

View File

@ -49,8 +49,8 @@ struct hhea
return TRACE_RETURN (c->check_struct (this) && likely (version.major == 1)); return TRACE_RETURN (c->check_struct (this) && likely (version.major == 1));
} }
protected: public:
FixedVersion version; /* 0x00010000 for version 1.0. */ FixedVersion version; /* 0x00010000u for version 1.0. */
FWORD ascender; /* Typographic ascent. <a FWORD ascender; /* Typographic ascent. <a
* href="http://developer.apple.com/fonts/TTRefMan/RM06/Chap6hhea.html"> * href="http://developer.apple.com/fonts/TTRefMan/RM06/Chap6hhea.html">
* (Distance from baseline of highest * (Distance from baseline of highest

View File

@ -59,7 +59,7 @@ struct hmtx
return TRACE_RETURN (true); return TRACE_RETURN (true);
} }
protected: public:
LongHorMetric longHorMetric[VAR]; /* Paired advance width and left side LongHorMetric longHorMetric[VAR]; /* Paired advance width and left side
* bearing values for each glyph. The * bearing values for each glyph. The
* value numOfHMetrics comes from * value numOfHMetrics comes from

View File

@ -103,7 +103,8 @@ struct RecordArrayOf : SortedArrayOf<Record<Type> > {
} }
inline bool find_index (hb_tag_t tag, unsigned int *index) const inline bool find_index (hb_tag_t tag, unsigned int *index) const
{ {
int i = this->search (tag); /* If we want to allow non-sorted data, we can lsearch(). */
int i = this->/*lsearch*/bsearch (tag);
if (i != -1) { if (i != -1) {
if (index) *index = i; if (index) *index = i;
return true; return true;
@ -189,10 +190,10 @@ struct LangSys
unsigned int *feature_indexes /* OUT */) const unsigned int *feature_indexes /* OUT */) const
{ return featureIndex.get_indexes (start_offset, feature_count, feature_indexes); } { return featureIndex.get_indexes (start_offset, feature_count, feature_indexes); }
inline bool has_required_feature (void) const { return reqFeatureIndex != 0xffff; } inline bool has_required_feature (void) const { return reqFeatureIndex != 0xFFFFu; }
inline unsigned int get_required_feature_index (void) const inline unsigned int get_required_feature_index (void) const
{ {
if (reqFeatureIndex == 0xffff) if (reqFeatureIndex == 0xFFFFu)
return Index::NOT_FOUND_INDEX; return Index::NOT_FOUND_INDEX;
return reqFeatureIndex;; return reqFeatureIndex;;
} }
@ -203,11 +204,11 @@ struct LangSys
return TRACE_RETURN (c->check_struct (this) && featureIndex.sanitize (c)); return TRACE_RETURN (c->check_struct (this) && featureIndex.sanitize (c));
} }
Offset lookupOrder; /* = Null (reserved for an offset to a Offset<> lookupOrderZ; /* = Null (reserved for an offset to a
* reordering table) */ * reordering table) */
USHORT reqFeatureIndex;/* Index of a feature required for this USHORT reqFeatureIndex;/* Index of a feature required for this
* language system--if no required features * language system--if no required features
* = 0xFFFF */ * = 0xFFFFu */
IndexArray featureIndex; /* Array of indices into the FeatureList */ IndexArray featureIndex; /* Array of indices into the FeatureList */
public: public:
DEFINE_SIZE_ARRAY (6, featureIndex); DEFINE_SIZE_ARRAY (6, featureIndex);
@ -447,9 +448,9 @@ struct FeatureParams
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
if (tag == HB_TAG ('s','i','z','e')) if (tag == HB_TAG ('s','i','z','e'))
return TRACE_RETURN (u.size.sanitize (c)); return TRACE_RETURN (u.size.sanitize (c));
if ((tag & 0xFFFF0000) == HB_TAG ('s','s','\0','\0')) /* ssXX */ if ((tag & 0xFFFF0000u) == HB_TAG ('s','s','\0','\0')) /* ssXX */
return TRACE_RETURN (u.stylisticSet.sanitize (c)); return TRACE_RETURN (u.stylisticSet.sanitize (c));
if ((tag & 0xFFFF0000) == HB_TAG ('c','v','\0','\0')) /* cvXX */ if ((tag & 0xFFFF0000u) == HB_TAG ('c','v','\0','\0')) /* cvXX */
return TRACE_RETURN (u.characterVariants.sanitize (c)); return TRACE_RETURN (u.characterVariants.sanitize (c));
return TRACE_RETURN (true); return TRACE_RETURN (true);
} }
@ -501,11 +502,11 @@ struct Feature
* Adobe tools, only the 'size' feature had FeatureParams defined. * Adobe tools, only the 'size' feature had FeatureParams defined.
*/ */
Offset orig_offset = featureParams; OffsetTo<FeatureParams> orig_offset = featureParams;
if (unlikely (!featureParams.sanitize (c, this, closure ? closure->tag : HB_TAG_NONE))) if (unlikely (!featureParams.sanitize (c, this, closure ? closure->tag : HB_TAG_NONE)))
return TRACE_RETURN (false); return TRACE_RETURN (false);
if (likely (!orig_offset)) if (likely (orig_offset.is_null ()))
return TRACE_RETURN (true); return TRACE_RETURN (true);
if (featureParams == 0 && closure && if (featureParams == 0 && closure &&
@ -513,13 +514,13 @@ struct Feature
closure->list_base && closure->list_base < this) closure->list_base && closure->list_base < this)
{ {
unsigned int new_offset_int = (unsigned int) orig_offset - unsigned int new_offset_int = (unsigned int) orig_offset -
((char *) this - (char *) closure->list_base); (((char *) this) - ((char *) closure->list_base));
Offset new_offset; OffsetTo<FeatureParams> new_offset;
/* Check that it did not overflow. */ /* Check that it did not overflow. */
new_offset.set (new_offset_int); new_offset.set (new_offset_int);
if (new_offset == new_offset_int && if (new_offset == new_offset_int &&
featureParams.try_set (c, new_offset) && c->try_set (&featureParams, new_offset) &&
!featureParams.sanitize (c, this, closure ? closure->tag : HB_TAG_NONE)) !featureParams.sanitize (c, this, closure ? closure->tag : HB_TAG_NONE))
return TRACE_RETURN (false); return TRACE_RETURN (false);
} }
@ -584,7 +585,7 @@ struct Lookup
TRACE_SERIALIZE (this); TRACE_SERIALIZE (this);
if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false); if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
lookupType.set (lookup_type); lookupType.set (lookup_type);
lookupFlag.set (lookup_props & 0xFFFF); lookupFlag.set (lookup_props & 0xFFFFu);
if (unlikely (!subTable.serialize (c, num_subtables))) return TRACE_RETURN (false); if (unlikely (!subTable.serialize (c, num_subtables))) return TRACE_RETURN (false);
if (lookupFlag & LookupFlag::UseMarkFilteringSet) if (lookupFlag & LookupFlag::UseMarkFilteringSet)
{ {
@ -608,7 +609,7 @@ struct Lookup
USHORT lookupType; /* Different enumerations for GSUB and GPOS */ USHORT lookupType; /* Different enumerations for GSUB and GPOS */
USHORT lookupFlag; /* Lookup qualifiers */ USHORT lookupFlag; /* Lookup qualifiers */
ArrayOf<Offset> ArrayOf<Offset<> >
subTable; /* Array of SubTables */ subTable; /* Array of SubTables */
USHORT markFilteringSetX[VAR]; /* Index (base 0) into GDEF mark glyph sets USHORT markFilteringSetX[VAR]; /* Index (base 0) into GDEF mark glyph sets
* structure. This field is only present if bit * structure. This field is only present if bit
@ -631,7 +632,7 @@ struct CoverageFormat1
private: private:
inline unsigned int get_coverage (hb_codepoint_t glyph_id) const inline unsigned int get_coverage (hb_codepoint_t glyph_id) const
{ {
int i = glyphArray.search (glyph_id); int i = glyphArray.bsearch (glyph_id);
ASSERT_STATIC (((unsigned int) -1) == NOT_COVERED); ASSERT_STATIC (((unsigned int) -1) == NOT_COVERED);
return i; return i;
} }
@ -696,7 +697,7 @@ struct CoverageFormat2
private: private:
inline unsigned int get_coverage (hb_codepoint_t glyph_id) const inline unsigned int get_coverage (hb_codepoint_t glyph_id) const
{ {
int i = rangeRecord.search (glyph_id); int i = rangeRecord.bsearch (glyph_id);
if (i != -1) { if (i != -1) {
const RangeRecord &range = rangeRecord[i]; const RangeRecord &range = rangeRecord[i];
return (unsigned int) range.value + (glyph_id - range.start); return (unsigned int) range.value + (glyph_id - range.start);
@ -992,7 +993,7 @@ struct ClassDefFormat2
private: private:
inline unsigned int get_class (hb_codepoint_t glyph_id) const inline unsigned int get_class (hb_codepoint_t glyph_id) const
{ {
int i = rangeRecord.search (glyph_id); int i = rangeRecord.bsearch (glyph_id);
if (i != -1) if (i != -1)
return rangeRecord[i].value; return rangeRecord[i].value;
return 0; return 0;
@ -1130,7 +1131,7 @@ struct Device
unsigned int byte = deltaValue[s >> (4 - f)]; unsigned int byte = deltaValue[s >> (4 - f)];
unsigned int bits = (byte >> (16 - (((s & ((1 << (4 - f)) - 1)) + 1) << f))); unsigned int bits = (byte >> (16 - (((s & ((1 << (4 - f)) - 1)) + 1) << f)));
unsigned int mask = (0xFFFF >> (16 - (1 << f))); unsigned int mask = (0xFFFFu >> (16 - (1 << f)));
int delta = bits & mask; int delta = bits & mask;

View File

@ -282,7 +282,7 @@ struct MarkGlyphSetsFormat1
protected: protected:
USHORT format; /* Format identifier--format = 1 */ USHORT format; /* Format identifier--format = 1 */
LongOffsetArrayOf<Coverage> ArrayOf<OffsetTo<Coverage, ULONG> >
coverage; /* Array of long offsets to mark set coverage; /* Array of long offsets to mark set
* coverage tables */ * coverage tables */
public: public:
@ -360,9 +360,9 @@ struct GDEF
hb_position_t *caret_array /* OUT */) const hb_position_t *caret_array /* OUT */) const
{ return (this+ligCaretList).get_lig_carets (font, direction, glyph_id, start_offset, caret_count, caret_array); } { return (this+ligCaretList).get_lig_carets (font, direction, glyph_id, start_offset, caret_count, caret_array); }
inline bool has_mark_sets (void) const { return version.to_int () >= 0x00010002 && markGlyphSetsDef[0] != 0; } inline bool has_mark_sets (void) const { return version.to_int () >= 0x00010002u && markGlyphSetsDef[0] != 0; }
inline bool mark_set_covers (unsigned int set_index, hb_codepoint_t glyph_id) const inline bool mark_set_covers (unsigned int set_index, hb_codepoint_t glyph_id) const
{ return version.to_int () >= 0x00010002 && (this+markGlyphSetsDef[0]).covers (set_index, glyph_id); } { return version.to_int () >= 0x00010002u && (this+markGlyphSetsDef[0]).covers (set_index, glyph_id); }
inline bool sanitize (hb_sanitize_context_t *c) { inline bool sanitize (hb_sanitize_context_t *c) {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
@ -372,7 +372,7 @@ struct GDEF
attachList.sanitize (c, this) && attachList.sanitize (c, this) &&
ligCaretList.sanitize (c, this) && ligCaretList.sanitize (c, this) &&
markAttachClassDef.sanitize (c, this) && markAttachClassDef.sanitize (c, this) &&
(version.to_int () < 0x00010002 || markGlyphSetsDef[0].sanitize (c, this))); (version.to_int () < 0x00010002u || markGlyphSetsDef[0].sanitize (c, this)));
} }
@ -400,7 +400,7 @@ struct GDEF
protected: protected:
FixedVersion version; /* Version of the GDEF table--currently FixedVersion version; /* Version of the GDEF table--currently
* 0x00010002 */ * 0x00010002u */
OffsetTo<ClassDef> OffsetTo<ClassDef>
glyphClassDef; /* Offset to class definition table glyphClassDef; /* Offset to class definition table
* for glyph type--from beginning of * for glyph type--from beginning of

View File

@ -49,18 +49,18 @@ typedef Value ValueRecord[VAR];
struct ValueFormat : USHORT struct ValueFormat : USHORT
{ {
enum Flags { enum Flags {
xPlacement = 0x0001, /* Includes horizontal adjustment for placement */ xPlacement = 0x0001u, /* Includes horizontal adjustment for placement */
yPlacement = 0x0002, /* Includes vertical adjustment for placement */ yPlacement = 0x0002u, /* Includes vertical adjustment for placement */
xAdvance = 0x0004, /* Includes horizontal adjustment for advance */ xAdvance = 0x0004u, /* Includes horizontal adjustment for advance */
yAdvance = 0x0008, /* Includes vertical adjustment for advance */ yAdvance = 0x0008u, /* Includes vertical adjustment for advance */
xPlaDevice = 0x0010, /* Includes horizontal Device table for placement */ xPlaDevice = 0x0010u, /* Includes horizontal Device table for placement */
yPlaDevice = 0x0020, /* Includes vertical Device table for placement */ yPlaDevice = 0x0020u, /* Includes vertical Device table for placement */
xAdvDevice = 0x0040, /* Includes horizontal Device table for advance */ xAdvDevice = 0x0040u, /* Includes horizontal Device table for advance */
yAdvDevice = 0x0080, /* Includes vertical Device table for advance */ yAdvDevice = 0x0080u, /* Includes vertical Device table for advance */
ignored = 0x0F00, /* Was used in TrueType Open for MM fonts */ ignored = 0x0F00u, /* Was used in TrueType Open for MM fonts */
reserved = 0xF000, /* For future use */ reserved = 0xF000u, /* For future use */
devices = 0x00F0 /* Mask for having any Device table */ devices = 0x00F0u /* Mask for having any Device table */
}; };
/* All fields are options. Only those available advance the value pointer. */ /* All fields are options. Only those available advance the value pointer. */
@ -1589,6 +1589,8 @@ GPOS::position_start (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
void void
GPOS::position_finish (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer) GPOS::position_finish (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
{ {
_hb_buffer_assert_gsubgpos_vars (buffer);
unsigned int len; unsigned int len;
hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, &len); hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, &len);
hb_direction_t direction = buffer->props.direction; hb_direction_t direction = buffer->props.direction;
@ -1600,22 +1602,20 @@ GPOS::position_finish (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
/* Handle attachments */ /* Handle attachments */
for (unsigned int i = 0; i < len; i++) for (unsigned int i = 0; i < len; i++)
fix_mark_attachment (pos, i, direction); fix_mark_attachment (pos, i, direction);
_hb_buffer_deallocate_gsubgpos_vars (buffer);
} }
/* Out-of-class implementation for methods recursing */ /* Out-of-class implementation for methods recursing */
template <typename context_t> template <typename context_t>
inline typename context_t::return_t PosLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index) /*static*/ inline typename context_t::return_t PosLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index)
{ {
const GPOS &gpos = *(hb_ot_layout_from_face (c->face)->gpos); const GPOS &gpos = *(hb_ot_layout_from_face (c->face)->gpos);
const PosLookup &l = gpos.get_lookup (lookup_index); const PosLookup &l = gpos.get_lookup (lookup_index);
return l.dispatch (c); return l.dispatch (c);
} }
inline bool PosLookup::apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index) /*static*/ inline bool PosLookup::apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index)
{ {
const GPOS &gpos = *(hb_ot_layout_from_face (c->face)->gpos); const GPOS &gpos = *(hb_ot_layout_from_face (c->face)->gpos);
const PosLookup &l = gpos.get_lookup (lookup_index); const PosLookup &l = gpos.get_lookup (lookup_index);

View File

@ -44,7 +44,7 @@ struct SingleSubstFormat1
for (iter.init (this+coverage); iter.more (); iter.next ()) { for (iter.init (this+coverage); iter.more (); iter.next ()) {
hb_codepoint_t glyph_id = iter.get_glyph (); hb_codepoint_t glyph_id = iter.get_glyph ();
if (c->glyphs->has (glyph_id)) if (c->glyphs->has (glyph_id))
c->glyphs->add ((glyph_id + deltaGlyphID) & 0xFFFF); c->glyphs->add ((glyph_id + deltaGlyphID) & 0xFFFFu);
} }
} }
@ -55,7 +55,7 @@ struct SingleSubstFormat1
for (iter.init (this+coverage); iter.more (); iter.next ()) { for (iter.init (this+coverage); iter.more (); iter.next ()) {
hb_codepoint_t glyph_id = iter.get_glyph (); hb_codepoint_t glyph_id = iter.get_glyph ();
c->input->add (glyph_id); c->input->add (glyph_id);
c->output->add ((glyph_id + deltaGlyphID) & 0xFFFF); c->output->add ((glyph_id + deltaGlyphID) & 0xFFFFu);
} }
} }
@ -79,7 +79,7 @@ struct SingleSubstFormat1
/* According to the Adobe Annotated OpenType Suite, result is always /* According to the Adobe Annotated OpenType Suite, result is always
* limited to 16bit. */ * limited to 16bit. */
glyph_id = (glyph_id + deltaGlyphID) & 0xFFFF; glyph_id = (glyph_id + deltaGlyphID) & 0xFFFFu;
c->replace_glyph (glyph_id); c->replace_glyph (glyph_id);
return TRACE_RETURN (true); return TRACE_RETURN (true);
@ -270,23 +270,34 @@ struct Sequence
inline bool apply (hb_apply_context_t *c) const inline bool apply (hb_apply_context_t *c) const
{ {
TRACE_APPLY (this); TRACE_APPLY (this);
if (unlikely (!substitute.len)) return TRACE_RETURN (false); unsigned int count = substitute.len;
/* TODO:
* Testing shows that Uniscribe actually allows zero-len susbstitute,
* which essentially deletes a glyph. We don't allow for now. It
* can be confusing to the client since the cluster from the deleted
* glyph won't be merged with any output cluster... Also, currently
* buffer->move_to() makes assumptions about this too. Perhaps fix
* in the future after figuring out what to do with the clusters.
*/
if (unlikely (!count)) return TRACE_RETURN (false);
/* Special-case to make it in-place and not consider this
* as a "multiplied" substitution. */
if (unlikely (count == 1))
{
c->replace_glyph (substitute.array[0]);
return TRACE_RETURN (true);
}
unsigned int klass = _hb_glyph_info_is_ligature (&c->buffer->cur()) ? unsigned int klass = _hb_glyph_info_is_ligature (&c->buffer->cur()) ?
HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH : 0; HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH : 0;
unsigned int count = substitute.len;
if (count == 1) /* Special-case to make it in-place. */ for (unsigned int i = 0; i < count; i++) {
{ _hb_glyph_info_set_lig_props_for_component (&c->buffer->cur(), i);
c->replace_glyph (substitute.array[0]); c->output_glyph_for_component (substitute.array[i], klass);
}
else
{
for (unsigned int i = 0; i < count; i++) {
_hb_glyph_info_set_lig_props_for_component (&c->buffer->cur(), i);
c->output_glyph (substitute.array[i], klass);
}
c->buffer->skip_glyph ();
} }
c->buffer->skip_glyph ();
return TRACE_RETURN (true); return TRACE_RETURN (true);
} }
@ -624,7 +635,16 @@ struct Ligature
{ {
TRACE_APPLY (this); TRACE_APPLY (this);
unsigned int count = component.len; unsigned int count = component.len;
if (unlikely (count < 1)) return TRACE_RETURN (false);
if (unlikely (!count)) return TRACE_RETURN (false);
/* Special-case to make it in-place and not consider this
* as a "ligated" substitution. */
if (unlikely (count == 1))
{
c->replace_glyph (ligGlyph);
return TRACE_RETURN (true);
}
bool is_mark_ligature = false; bool is_mark_ligature = false;
unsigned int total_component_count = 0; unsigned int total_component_count = 0;
@ -1318,7 +1338,7 @@ struct GSUB : GSUBGPOS
void void
GSUB::substitute_start (hb_font_t *font, hb_buffer_t *buffer) GSUB::substitute_start (hb_font_t *font, hb_buffer_t *buffer)
{ {
_hb_buffer_allocate_gsubgpos_vars (buffer); _hb_buffer_assert_gsubgpos_vars (buffer);
const GDEF &gdef = *hb_ot_layout_from_face (font->face)->gdef; const GDEF &gdef = *hb_ot_layout_from_face (font->face)->gdef;
unsigned int count = buffer->len; unsigned int count = buffer->len;
@ -1338,7 +1358,7 @@ GSUB::substitute_finish (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer HB_UNUSE
/* Out-of-class implementation for methods recursing */ /* Out-of-class implementation for methods recursing */
inline bool ExtensionSubst::is_reverse (void) const /*static*/ inline bool ExtensionSubst::is_reverse (void) const
{ {
unsigned int type = get_type (); unsigned int type = get_type ();
if (unlikely (type == SubstLookupSubTable::Extension)) if (unlikely (type == SubstLookupSubTable::Extension))
@ -1347,14 +1367,14 @@ inline bool ExtensionSubst::is_reverse (void) const
} }
template <typename context_t> template <typename context_t>
inline typename context_t::return_t SubstLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index) /*static*/ inline typename context_t::return_t SubstLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index)
{ {
const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub); const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub);
const SubstLookup &l = gsub.get_lookup (lookup_index); const SubstLookup &l = gsub.get_lookup (lookup_index);
return l.dispatch (c); return l.dispatch (c);
} }
inline bool SubstLookup::apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index) /*static*/ inline bool SubstLookup::apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index)
{ {
const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub); const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub);
const SubstLookup &l = gsub.get_lookup (lookup_index); const SubstLookup &l = gsub.get_lookup (lookup_index);

View File

@ -349,11 +349,7 @@ struct hb_apply_context_t
may_skip (const hb_apply_context_t *c, may_skip (const hb_apply_context_t *c,
const hb_glyph_info_t &info) const const hb_glyph_info_t &info) const
{ {
unsigned int property; if (!c->check_glyph_property (&info, lookup_props))
property = _hb_glyph_info_get_glyph_props (&info);
if (!c->match_properties (info.codepoint, property, lookup_props))
return SKIP_YES; return SKIP_YES;
if (unlikely (_hb_glyph_info_is_default_ignorable (&info) && if (unlikely (_hb_glyph_info_is_default_ignorable (&info) &&
@ -487,7 +483,6 @@ struct hb_apply_context_t
const hb_glyph_info_t &info = c->buffer->out_info[idx]; const hb_glyph_info_t &info = c->buffer->out_info[idx];
matcher_t::may_skip_t skip = matcher.may_skip (c, info); matcher_t::may_skip_t skip = matcher.may_skip (c, info);
if (unlikely (skip == matcher_t::SKIP_YES)) if (unlikely (skip == matcher_t::SKIP_YES))
continue; continue;
@ -538,10 +533,12 @@ struct hb_apply_context_t
} }
inline bool inline bool
match_properties (hb_codepoint_t glyph, check_glyph_property (const hb_glyph_info_t *info,
unsigned int glyph_props, unsigned int lookup_props) const
unsigned int lookup_props) const
{ {
hb_codepoint_t glyph = info->codepoint;
unsigned int glyph_props = _hb_glyph_info_get_glyph_props (info);
/* Not covered, if, for example, glyph class is ligature and /* Not covered, if, for example, glyph class is ligature and
* lookup_props includes LookupFlags::IgnoreLigatures * lookup_props includes LookupFlags::IgnoreLigatures
*/ */
@ -554,26 +551,27 @@ struct hb_apply_context_t
return true; return true;
} }
inline bool
check_glyph_property (hb_glyph_info_t *info,
unsigned int lookup_props) const
{
unsigned int property;
property = _hb_glyph_info_get_glyph_props (info);
return match_properties (info->codepoint, property, lookup_props);
}
inline void _set_glyph_props (hb_codepoint_t glyph_index, inline void _set_glyph_props (hb_codepoint_t glyph_index,
unsigned int class_guess = 0, unsigned int class_guess = 0,
bool ligature = false) const bool ligature = false,
bool component = false) const
{ {
unsigned int add_in = _hb_glyph_info_get_glyph_props (&buffer->cur()) & unsigned int add_in = _hb_glyph_info_get_glyph_props (&buffer->cur()) &
HB_OT_LAYOUT_GLYPH_PROPS_PRESERVE; HB_OT_LAYOUT_GLYPH_PROPS_PRESERVE;
add_in |= HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED; add_in |= HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED;
if (ligature) if (ligature)
{
add_in |= HB_OT_LAYOUT_GLYPH_PROPS_LIGATED; add_in |= HB_OT_LAYOUT_GLYPH_PROPS_LIGATED;
/* In the only place that the MULTIPLIED bit is used, Uniscribe
* seems to only care about the "last" transformation between
* Ligature and Multiple substitions. Ie. if you ligate, expand,
* and ligate again, it forgives the multiplication and acts as
* if only ligation happened. As such, clear MULTIPLIED bit.
*/
add_in &= ~HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED;
}
if (component)
add_in |= HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED;
if (likely (has_glyph_classes)) if (likely (has_glyph_classes))
_hb_glyph_info_set_glyph_props (&buffer->cur(), add_in | gdef.get_glyph_props (glyph_index)); _hb_glyph_info_set_glyph_props (&buffer->cur(), add_in | gdef.get_glyph_props (glyph_index));
else if (class_guess) else if (class_guess)
@ -596,10 +594,10 @@ struct hb_apply_context_t
_set_glyph_props (glyph_index, class_guess, true); _set_glyph_props (glyph_index, class_guess, true);
buffer->replace_glyph (glyph_index); buffer->replace_glyph (glyph_index);
} }
inline void output_glyph (hb_codepoint_t glyph_index, inline void output_glyph_for_component (hb_codepoint_t glyph_index,
unsigned int class_guess) const unsigned int class_guess) const
{ {
_set_glyph_props (glyph_index, class_guess); _set_glyph_props (glyph_index, class_guess, false, true);
buffer->output_glyph (glyph_index); buffer->output_glyph (glyph_index);
} }
}; };
@ -882,6 +880,7 @@ static inline void ligate_input (hb_apply_context_t *c,
break; break;
} }
} }
TRACE_RETURN (true);
} }
static inline bool match_backtrack (hb_apply_context_t *c, static inline bool match_backtrack (hb_apply_context_t *c,
@ -994,7 +993,9 @@ static inline bool apply_lookup (hb_apply_context_t *c,
/* Recursed lookup changed buffer len. Adjust. */ /* Recursed lookup changed buffer len. Adjust. */
/* end can't go back past the current match position. */ /* end can't go back past the current match position.
* Note: this is only true because we do NOT allow MultipleSubst
* with zero sequence len. */
end = MAX ((int) match_positions[idx] + 1, int (end) + delta); end = MAX ((int) match_positions[idx] + 1, int (end) + delta);
unsigned int next = idx + 1; /* next now is the position after the recursed lookup. */ unsigned int next = idx + 1; /* next now is the position after the recursed lookup. */
@ -2253,8 +2254,8 @@ struct GSUBGPOS
inline unsigned int get_feature_count (void) const inline unsigned int get_feature_count (void) const
{ return (this+featureList).len; } { return (this+featureList).len; }
inline const Tag& get_feature_tag (unsigned int i) const inline hb_tag_t get_feature_tag (unsigned int i) const
{ return (this+featureList).get_tag (i); } { return i == Index::NOT_FOUND_INDEX ? HB_TAG_NONE : (this+featureList).get_tag (i); }
inline unsigned int get_feature_tags (unsigned int start_offset, inline unsigned int get_feature_tags (unsigned int start_offset,
unsigned int *feature_count /* IN/OUT */, unsigned int *feature_count /* IN/OUT */,
hb_tag_t *feature_tags /* OUT */) const hb_tag_t *feature_tags /* OUT */) const
@ -2279,7 +2280,7 @@ struct GSUBGPOS
protected: protected:
FixedVersion version; /* Version of the GSUB/GPOS table--initially set FixedVersion version; /* Version of the GSUB/GPOS table--initially set
* to 0x00010000 */ * to 0x00010000u */
OffsetTo<ScriptList> OffsetTo<ScriptList>
scriptList; /* ScriptList table */ scriptList; /* ScriptList table */
OffsetTo<FeatureList> OffsetTo<FeatureList>

View File

@ -214,7 +214,7 @@ struct JSTF
protected: protected:
FixedVersion version; /* Version of the JSTF table--initially set FixedVersion version; /* Version of the JSTF table--initially set
* to 0x00010000 */ * to 0x00010000u */
RecordArrayOf<JstfScript> RecordArrayOf<JstfScript>
scriptList; /* Array of JstfScripts--listed scriptList; /* Array of JstfScripts--listed
* alphabetically by ScriptTag */ * alphabetically by ScriptTag */

View File

@ -50,9 +50,11 @@ typedef enum
/* The following are used internally; not derived from GDEF. */ /* The following are used internally; not derived from GDEF. */
HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED = 0x10u, HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED = 0x10u,
HB_OT_LAYOUT_GLYPH_PROPS_LIGATED = 0x20u, HB_OT_LAYOUT_GLYPH_PROPS_LIGATED = 0x20u,
HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED = 0x40u,
HB_OT_LAYOUT_GLYPH_PROPS_PRESERVE = HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED | HB_OT_LAYOUT_GLYPH_PROPS_PRESERVE = HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED |
HB_OT_LAYOUT_GLYPH_PROPS_LIGATED HB_OT_LAYOUT_GLYPH_PROPS_LIGATED |
HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED
} hb_ot_layout_glyph_class_mask_t; } hb_ot_layout_glyph_class_mask_t;
@ -125,7 +127,7 @@ struct hb_ot_layout_lookup_accelerator_t
} }
template <typename TLookup> template <typename TLookup>
inline void fini (const TLookup &lookup) inline void fini (const TLookup &lookup HB_UNUSED)
{ {
} }
@ -182,62 +184,62 @@ enum {
MASK0_GEN_CAT = 0x1Fu MASK0_GEN_CAT = 0x1Fu
}; };
inline void static inline void
_hb_glyph_info_set_unicode_props (hb_glyph_info_t *info, hb_unicode_funcs_t *unicode) _hb_glyph_info_set_unicode_props (hb_glyph_info_t *info, hb_unicode_funcs_t *unicode)
{ {
/* XXX This shouldn't be inlined, or at least not while is_default_ignorable() is inline. */ /* XXX This shouldn't be inlined, or at least not while is_default_ignorable() is inline. */
info->unicode_props0() = ((unsigned int) unicode->general_category (info->codepoint)) | info->unicode_props0() = ((unsigned int) unicode->general_category (info->codepoint)) |
(unicode->is_default_ignorable (info->codepoint) ? MASK0_IGNORABLE : 0) | (unicode->is_default_ignorable (info->codepoint) ? MASK0_IGNORABLE : 0) |
(info->codepoint == 0x200C ? MASK0_ZWNJ : 0) | (info->codepoint == 0x200Cu ? MASK0_ZWNJ : 0) |
(info->codepoint == 0x200D ? MASK0_ZWJ : 0); (info->codepoint == 0x200Du ? MASK0_ZWJ : 0);
info->unicode_props1() = unicode->modified_combining_class (info->codepoint); info->unicode_props1() = unicode->modified_combining_class (info->codepoint);
} }
inline void static inline void
_hb_glyph_info_set_general_category (hb_glyph_info_t *info, _hb_glyph_info_set_general_category (hb_glyph_info_t *info,
hb_unicode_general_category_t gen_cat) hb_unicode_general_category_t gen_cat)
{ {
info->unicode_props0() = (unsigned int) gen_cat | ((info->unicode_props0()) & ~MASK0_GEN_CAT); info->unicode_props0() = (unsigned int) gen_cat | ((info->unicode_props0()) & ~MASK0_GEN_CAT);
} }
inline hb_unicode_general_category_t static inline hb_unicode_general_category_t
_hb_glyph_info_get_general_category (const hb_glyph_info_t *info) _hb_glyph_info_get_general_category (const hb_glyph_info_t *info)
{ {
return (hb_unicode_general_category_t) (info->unicode_props0() & MASK0_GEN_CAT); return (hb_unicode_general_category_t) (info->unicode_props0() & MASK0_GEN_CAT);
} }
inline void static inline void
_hb_glyph_info_set_modified_combining_class (hb_glyph_info_t *info, _hb_glyph_info_set_modified_combining_class (hb_glyph_info_t *info,
unsigned int modified_class) unsigned int modified_class)
{ {
info->unicode_props1() = modified_class; info->unicode_props1() = modified_class;
} }
inline unsigned int static inline unsigned int
_hb_glyph_info_get_modified_combining_class (const hb_glyph_info_t *info) _hb_glyph_info_get_modified_combining_class (const hb_glyph_info_t *info)
{ {
return info->unicode_props1(); return info->unicode_props1();
} }
inline hb_bool_t static inline hb_bool_t
_hb_glyph_info_is_default_ignorable (const hb_glyph_info_t *info) _hb_glyph_info_is_default_ignorable (const hb_glyph_info_t *info)
{ {
return !!(info->unicode_props0() & MASK0_IGNORABLE); return !!(info->unicode_props0() & MASK0_IGNORABLE);
} }
inline hb_bool_t static inline hb_bool_t
_hb_glyph_info_is_zwnj (const hb_glyph_info_t *info) _hb_glyph_info_is_zwnj (const hb_glyph_info_t *info)
{ {
return !!(info->unicode_props0() & MASK0_ZWNJ); return !!(info->unicode_props0() & MASK0_ZWNJ);
} }
inline hb_bool_t static inline hb_bool_t
_hb_glyph_info_is_zwj (const hb_glyph_info_t *info) _hb_glyph_info_is_zwj (const hb_glyph_info_t *info)
{ {
return !!(info->unicode_props0() & MASK0_ZWJ); return !!(info->unicode_props0() & MASK0_ZWJ);
} }
inline void static inline void
_hb_glyph_info_flip_joiners (hb_glyph_info_t *info) _hb_glyph_info_flip_joiners (hb_glyph_info_t *info)
{ {
info->unicode_props0() ^= MASK0_ZWNJ | MASK0_ZWJ; info->unicode_props0() ^= MASK0_ZWNJ | MASK0_ZWJ;
@ -339,31 +341,31 @@ _hb_allocate_lig_id (hb_buffer_t *buffer) {
/* glyph_props: */ /* glyph_props: */
inline void static inline void
_hb_glyph_info_set_glyph_props (hb_glyph_info_t *info, unsigned int props) _hb_glyph_info_set_glyph_props (hb_glyph_info_t *info, unsigned int props)
{ {
info->glyph_props() = props; info->glyph_props() = props;
} }
inline unsigned int static inline unsigned int
_hb_glyph_info_get_glyph_props (const hb_glyph_info_t *info) _hb_glyph_info_get_glyph_props (const hb_glyph_info_t *info)
{ {
return info->glyph_props(); return info->glyph_props();
} }
inline bool static inline bool
_hb_glyph_info_is_base_glyph (const hb_glyph_info_t *info) _hb_glyph_info_is_base_glyph (const hb_glyph_info_t *info)
{ {
return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH); return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH);
} }
inline bool static inline bool
_hb_glyph_info_is_ligature (const hb_glyph_info_t *info) _hb_glyph_info_is_ligature (const hb_glyph_info_t *info)
{ {
return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE); return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE);
} }
inline bool static inline bool
_hb_glyph_info_is_mark (const hb_glyph_info_t *info) _hb_glyph_info_is_mark (const hb_glyph_info_t *info)
{ {
return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_MARK); return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_MARK);
@ -381,23 +383,50 @@ _hb_glyph_info_ligated (const hb_glyph_info_t *info)
return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_LIGATED); return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_LIGATED);
} }
static inline bool
_hb_glyph_info_multiplied (const hb_glyph_info_t *info)
{
return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED);
}
static inline bool
_hb_glyph_info_ligated_and_didnt_multiply (const hb_glyph_info_t *info)
{
return _hb_glyph_info_ligated (info) && !_hb_glyph_info_multiplied (info);
}
static inline void
_hb_glyph_info_clear_ligated_and_multiplied (hb_glyph_info_t *info)
{
info->glyph_props() &= ~(HB_OT_LAYOUT_GLYPH_PROPS_LIGATED |
HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED);
}
/* Allocation / deallocation. */ /* Allocation / deallocation. */
inline void static inline void
_hb_buffer_allocate_unicode_vars (hb_buffer_t *buffer) _hb_buffer_allocate_unicode_vars (hb_buffer_t *buffer)
{ {
HB_BUFFER_ALLOCATE_VAR (buffer, unicode_props0); HB_BUFFER_ALLOCATE_VAR (buffer, unicode_props0);
HB_BUFFER_ALLOCATE_VAR (buffer, unicode_props1); HB_BUFFER_ALLOCATE_VAR (buffer, unicode_props1);
} }
inline void static inline void
_hb_buffer_deallocate_unicode_vars (hb_buffer_t *buffer) _hb_buffer_deallocate_unicode_vars (hb_buffer_t *buffer)
{ {
HB_BUFFER_DEALLOCATE_VAR (buffer, unicode_props0); HB_BUFFER_DEALLOCATE_VAR (buffer, unicode_props0);
HB_BUFFER_DEALLOCATE_VAR (buffer, unicode_props1); HB_BUFFER_DEALLOCATE_VAR (buffer, unicode_props1);
} }
inline void static inline void
_hb_buffer_assert_unicode_vars (hb_buffer_t *buffer)
{
HB_BUFFER_ASSERT_VAR (buffer, unicode_props0);
HB_BUFFER_ASSERT_VAR (buffer, unicode_props1);
}
static inline void
_hb_buffer_allocate_gsubgpos_vars (hb_buffer_t *buffer) _hb_buffer_allocate_gsubgpos_vars (hb_buffer_t *buffer)
{ {
HB_BUFFER_ALLOCATE_VAR (buffer, glyph_props); HB_BUFFER_ALLOCATE_VAR (buffer, glyph_props);
@ -405,7 +434,7 @@ _hb_buffer_allocate_gsubgpos_vars (hb_buffer_t *buffer)
HB_BUFFER_ALLOCATE_VAR (buffer, syllable); HB_BUFFER_ALLOCATE_VAR (buffer, syllable);
} }
inline void static inline void
_hb_buffer_deallocate_gsubgpos_vars (hb_buffer_t *buffer) _hb_buffer_deallocate_gsubgpos_vars (hb_buffer_t *buffer)
{ {
HB_BUFFER_DEALLOCATE_VAR (buffer, syllable); HB_BUFFER_DEALLOCATE_VAR (buffer, syllable);
@ -413,6 +442,14 @@ _hb_buffer_deallocate_gsubgpos_vars (hb_buffer_t *buffer)
HB_BUFFER_DEALLOCATE_VAR (buffer, glyph_props); HB_BUFFER_DEALLOCATE_VAR (buffer, glyph_props);
} }
static inline void
_hb_buffer_assert_gsubgpos_vars (hb_buffer_t *buffer)
{
HB_BUFFER_ASSERT_VAR (buffer, glyph_props);
HB_BUFFER_ASSERT_VAR (buffer, lig_props);
HB_BUFFER_ASSERT_VAR (buffer, syllable);
}
/* Make sure no one directly touches our props... */ /* Make sure no one directly touches our props... */
#undef unicode_props0 #undef unicode_props0
#undef unicode_props1 #undef unicode_props1

View File

@ -327,9 +327,28 @@ hb_ot_layout_language_get_required_feature_index (hb_face_t *face,
unsigned int language_index, unsigned int language_index,
unsigned int *feature_index) unsigned int *feature_index)
{ {
const OT::LangSys &l = get_gsubgpos_table (face, table_tag).get_script (script_index).get_lang_sys (language_index); return hb_ot_layout_language_get_required_feature (face,
table_tag,
script_index,
language_index,
feature_index,
NULL);
}
if (feature_index) *feature_index = l.get_required_feature_index (); hb_bool_t
hb_ot_layout_language_get_required_feature (hb_face_t *face,
hb_tag_t table_tag,
unsigned int script_index,
unsigned int language_index,
unsigned int *feature_index,
hb_tag_t *feature_tag)
{
const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
unsigned int index = l.get_required_feature_index ();
if (feature_index) *feature_index = index;
if (feature_tag) *feature_tag = g.get_feature_tag (index);
return l.has_required_feature (); return l.has_required_feature ();
} }
@ -468,11 +487,12 @@ _hb_ot_layout_collect_lookups_features (hb_face_t *face,
if (!features) if (!features)
{ {
unsigned int required_feature_index; unsigned int required_feature_index;
if (hb_ot_layout_language_get_required_feature_index (face, if (hb_ot_layout_language_get_required_feature (face,
table_tag, table_tag,
script_index, script_index,
language_index, language_index,
&required_feature_index)) &required_feature_index,
NULL))
_hb_ot_layout_collect_lookups_lookups (face, _hb_ot_layout_collect_lookups_lookups (face,
table_tag, table_tag,
required_feature_index, required_feature_index,

View File

@ -92,9 +92,9 @@ hb_ot_layout_get_ligature_carets (hb_font_t *font,
* GSUB/GPOS feature query and enumeration interface * GSUB/GPOS feature query and enumeration interface
*/ */
#define HB_OT_LAYOUT_NO_SCRIPT_INDEX ((unsigned int) 0xFFFF) #define HB_OT_LAYOUT_NO_SCRIPT_INDEX 0xFFFFu
#define HB_OT_LAYOUT_NO_FEATURE_INDEX ((unsigned int) 0xFFFF) #define HB_OT_LAYOUT_NO_FEATURE_INDEX 0xFFFFu
#define HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX ((unsigned int) 0xFFFF) #define HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX 0xFFFFu
unsigned int unsigned int
hb_ot_layout_table_get_script_tags (hb_face_t *face, hb_ot_layout_table_get_script_tags (hb_face_t *face,
@ -146,6 +146,14 @@ hb_ot_layout_language_get_required_feature_index (hb_face_t *face,
unsigned int language_index, unsigned int language_index,
unsigned int *feature_index); unsigned int *feature_index);
hb_bool_t
hb_ot_layout_language_get_required_feature (hb_face_t *face,
hb_tag_t table_tag,
unsigned int script_index,
unsigned int language_index,
unsigned int *feature_index,
hb_tag_t *feature_tag);
unsigned int unsigned int
hb_ot_layout_language_get_feature_indexes (hb_face_t *face, hb_ot_layout_language_get_feature_indexes (hb_face_t *face,
hb_tag_t table_tag, hb_tag_t table_tag,

View File

@ -153,26 +153,26 @@ struct hb_ot_map_t
}; };
enum hb_ot_map_feature_flags_t { enum hb_ot_map_feature_flags_t {
F_NONE = 0x0000, F_NONE = 0x0000u,
F_GLOBAL = 0x0001, F_GLOBAL = 0x0001u,
F_HAS_FALLBACK = 0x0002, F_HAS_FALLBACK = 0x0002u,
F_MANUAL_ZWJ = 0x0004 F_MANUAL_ZWJ = 0x0004u
}; };
/* Macro version for where const is desired. */ /* Macro version for where const is desired. */
#define F_COMBINE(l,r) (hb_ot_map_feature_flags_t ((unsigned int) (l) | (unsigned int) (r))) #define F_COMBINE(l,r) (hb_ot_map_feature_flags_t ((unsigned int) (l) | (unsigned int) (r)))
inline hb_ot_map_feature_flags_t static inline hb_ot_map_feature_flags_t
operator | (hb_ot_map_feature_flags_t l, hb_ot_map_feature_flags_t r) operator | (hb_ot_map_feature_flags_t l, hb_ot_map_feature_flags_t r)
{ return hb_ot_map_feature_flags_t ((unsigned int) l | (unsigned int) r); } { return hb_ot_map_feature_flags_t ((unsigned int) l | (unsigned int) r); }
inline hb_ot_map_feature_flags_t static inline hb_ot_map_feature_flags_t
operator & (hb_ot_map_feature_flags_t l, hb_ot_map_feature_flags_t r) operator & (hb_ot_map_feature_flags_t l, hb_ot_map_feature_flags_t r)
{ return hb_ot_map_feature_flags_t ((unsigned int) l & (unsigned int) r); } { return hb_ot_map_feature_flags_t ((unsigned int) l & (unsigned int) r); }
inline hb_ot_map_feature_flags_t static inline hb_ot_map_feature_flags_t
operator ~ (hb_ot_map_feature_flags_t r) operator ~ (hb_ot_map_feature_flags_t r)
{ return hb_ot_map_feature_flags_t (~(unsigned int) r); } { return hb_ot_map_feature_flags_t (~(unsigned int) r); }
inline hb_ot_map_feature_flags_t& static inline hb_ot_map_feature_flags_t&
operator |= (hb_ot_map_feature_flags_t &l, hb_ot_map_feature_flags_t r) operator |= (hb_ot_map_feature_flags_t &l, hb_ot_map_feature_flags_t r)
{ l = l | r; return l; } { l = l | r; return l; }
inline hb_ot_map_feature_flags_t& static inline hb_ot_map_feature_flags_t&
operator &= (hb_ot_map_feature_flags_t& l, hb_ot_map_feature_flags_t r) operator &= (hb_ot_map_feature_flags_t& l, hb_ot_map_feature_flags_t r)
{ l = l & r; return l; } { l = l & r; return l; }

View File

@ -99,6 +99,7 @@ void hb_ot_map_builder_t::add_feature (hb_tag_t tag, unsigned int value,
{ {
feature_info_t *info = feature_infos.push(); feature_info_t *info = feature_infos.push();
if (unlikely (!info)) return; if (unlikely (!info)) return;
if (unlikely (!tag)) return;
info->tag = tag; info->tag = tag;
info->seq = feature_infos.len; info->seq = feature_infos.len;
info->max_value = value; info->max_value = value;
@ -131,9 +132,25 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m)
{ {
m.global_mask = 1; m.global_mask = 1;
for (unsigned int table_index = 0; table_index < 2; table_index++) { unsigned int required_feature_index[2];
hb_tag_t required_feature_tag[2];
/* We default to applying required feature in stage 0. If the required
* feature has a tag that is known to the shaper, we apply required feature
* in the stage for that tag.
*/
unsigned int required_feature_stage[2] = {0, 0};
for (unsigned int table_index = 0; table_index < 2; table_index++)
{
m.chosen_script[table_index] = chosen_script[table_index]; m.chosen_script[table_index] = chosen_script[table_index];
m.found_script[table_index] = found_script[table_index]; m.found_script[table_index] = found_script[table_index];
hb_ot_layout_language_get_required_feature (face,
table_tags[table_index],
script_index[table_index],
language_index[table_index],
&required_feature_index[table_index],
&required_feature_tag[table_index]);
} }
if (!feature_infos.len) if (!feature_infos.len)
@ -141,7 +158,7 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m)
/* Sort features and merge duplicates */ /* Sort features and merge duplicates */
{ {
feature_infos.sort (); feature_infos.qsort ();
unsigned int j = 0; unsigned int j = 0;
for (unsigned int i = 1; i < feature_infos.len; i++) for (unsigned int i = 1; i < feature_infos.len; i++)
if (feature_infos[i].tag != feature_infos[j].tag) if (feature_infos[i].tag != feature_infos[j].tag)
@ -166,7 +183,8 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m)
/* Allocate bits now */ /* Allocate bits now */
unsigned int next_bit = 1; unsigned int next_bit = 1;
for (unsigned int i = 0; i < feature_infos.len; i++) { for (unsigned int i = 0; i < feature_infos.len; i++)
{
const feature_info_t *info = &feature_infos[i]; const feature_info_t *info = &feature_infos[i];
unsigned int bits_needed; unsigned int bits_needed;
@ -184,12 +202,20 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m)
hb_bool_t found = false; hb_bool_t found = false;
unsigned int feature_index[2]; unsigned int feature_index[2];
for (unsigned int table_index = 0; table_index < 2; table_index++) for (unsigned int table_index = 0; table_index < 2; table_index++)
{
if (required_feature_tag[table_index] == info->tag)
{
required_feature_stage[table_index] = info->stage[table_index];
found = true;
continue;
}
found |= hb_ot_layout_language_find_feature (face, found |= hb_ot_layout_language_find_feature (face,
table_tags[table_index], table_tags[table_index],
script_index[table_index], script_index[table_index],
language_index[table_index], language_index[table_index],
info->tag, info->tag,
&feature_index[table_index]); &feature_index[table_index]);
}
if (!found && !(info->flags & F_HAS_FALLBACK)) if (!found && !(info->flags & F_HAS_FALLBACK))
continue; continue;
@ -224,23 +250,21 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m)
add_gsub_pause (NULL); add_gsub_pause (NULL);
add_gpos_pause (NULL); add_gpos_pause (NULL);
for (unsigned int table_index = 0; table_index < 2; table_index++) { for (unsigned int table_index = 0; table_index < 2; table_index++)
hb_tag_t table_tag = table_tags[table_index]; {
/* Collect lookup indices for features */ /* Collect lookup indices for features */
unsigned int required_feature_index;
if (hb_ot_layout_language_get_required_feature_index (face,
table_tag,
script_index[table_index],
language_index[table_index],
&required_feature_index))
m.add_lookups (face, table_index, required_feature_index, 1, true);
unsigned int stage_index = 0; unsigned int stage_index = 0;
unsigned int last_num_lookups = 0; unsigned int last_num_lookups = 0;
for (unsigned stage = 0; stage < current_stage[table_index]; stage++) for (unsigned stage = 0; stage < current_stage[table_index]; stage++)
{ {
if (required_feature_index[table_index] != HB_OT_LAYOUT_NO_FEATURE_INDEX &&
required_feature_stage[table_index] == stage)
m.add_lookups (face, table_index,
required_feature_index[table_index],
1 /* mask */,
true /* auto_zwj */);
for (unsigned i = 0; i < m.features.len; i++) for (unsigned i = 0; i < m.features.len; i++)
if (m.features[i].stage[table_index] == stage) if (m.features[i].stage[table_index] == stage)
m.add_lookups (face, table_index, m.add_lookups (face, table_index,
@ -251,7 +275,7 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m)
/* Sort lookups and merge duplicates */ /* Sort lookups and merge duplicates */
if (last_num_lookups < m.lookups[table_index].len) if (last_num_lookups < m.lookups[table_index].len)
{ {
m.lookups[table_index].sort (last_num_lookups, m.lookups[table_index].len); m.lookups[table_index].qsort (last_num_lookups, m.lookups[table_index].len);
unsigned int j = last_num_lookups; unsigned int j = last_num_lookups;
for (unsigned int i = j + 1; i < m.lookups[table_index].len; i++) for (unsigned int i = j + 1; i < m.lookups[table_index].len; i++)

View File

@ -50,13 +50,13 @@ struct maxp
inline bool sanitize (hb_sanitize_context_t *c) { inline bool sanitize (hb_sanitize_context_t *c) {
TRACE_SANITIZE (this); TRACE_SANITIZE (this);
return TRACE_RETURN (c->check_struct (this) && return TRACE_RETURN (c->check_struct (this) &&
likely (version.major == 1 || (version.major == 0 && version.minor == 0x5000))); likely (version.major == 1 || (version.major == 0 && version.minor == 0x5000u)));
} }
/* We only implement version 0.5 as none of the extra fields in version 1.0 are useful. */ /* We only implement version 0.5 as none of the extra fields in version 1.0 are useful. */
protected: protected:
FixedVersion version; /* Version of the maxp table (0.5 or 1.0), FixedVersion version; /* Version of the maxp table (0.5 or 1.0),
* 0x00005000 or 0x00010000. */ * 0x00005000u or 0x00010000u. */
USHORT numGlyphs; /* The number of glyphs in the font. */ USHORT numGlyphs; /* The number of glyphs in the font. */
public: public:
DEFINE_SIZE_STATIC (6); DEFINE_SIZE_STATIC (6);

View File

@ -121,7 +121,7 @@ struct name
/* We only implement format 0 for now. */ /* We only implement format 0 for now. */
USHORT format; /* Format selector (=0/1). */ USHORT format; /* Format selector (=0/1). */
USHORT count; /* Number of name records. */ USHORT count; /* Number of name records. */
Offset stringOffset; /* Offset to start of string storage (from start of table). */ Offset<> stringOffset; /* Offset to start of string storage (from start of table). */
NameRecord nameRecord[VAR]; /* The name records where count is the number of records. */ NameRecord nameRecord[VAR]; /* The name records where count is the number of records. */
public: public:
DEFINE_SIZE_ARRAY (6, nameRecord); DEFINE_SIZE_ARRAY (6, nameRecord);

View File

@ -33,6 +33,8 @@
#include "hb-ot-layout-gsub-table.hh" #include "hb-ot-layout-gsub-table.hh"
/* Features ordered the same as the entries in shaping_table rows,
* followed by rlig. Don't change. */
static const hb_tag_t arabic_fallback_features[] = static const hb_tag_t arabic_fallback_features[] =
{ {
HB_TAG('i','n','i','t'), HB_TAG('i','n','i','t'),
@ -42,16 +44,6 @@ static const hb_tag_t arabic_fallback_features[] =
HB_TAG('r','l','i','g'), HB_TAG('r','l','i','g'),
}; };
/* Same order as the fallback feature array */
enum {
FALLBACK_INIT,
FALLBACK_MEDI,
FALLBACK_FINA,
FALLBACK_ISOL,
FALLBACK_RLIG,
ARABIC_NUM_FALLBACK_FEATURES
};
static OT::SubstLookup * static OT::SubstLookup *
arabic_fallback_synthesize_lookup_single (const hb_ot_shape_plan_t *plan HB_UNUSED, arabic_fallback_synthesize_lookup_single (const hb_ot_shape_plan_t *plan HB_UNUSED,
hb_font_t *font, hb_font_t *font,
@ -71,7 +63,7 @@ arabic_fallback_synthesize_lookup_single (const hb_ot_shape_plan_t *plan HB_UNUS
!hb_font_get_glyph (font, u, 0, &u_glyph) || !hb_font_get_glyph (font, u, 0, &u_glyph) ||
!hb_font_get_glyph (font, s, 0, &s_glyph) || !hb_font_get_glyph (font, s, 0, &s_glyph) ||
u_glyph == s_glyph || u_glyph == s_glyph ||
u_glyph > 0xFFFF || s_glyph > 0xFFFF) u_glyph > 0xFFFFu || s_glyph > 0xFFFFu)
continue; continue;
glyphs[num_glyphs].set (u_glyph); glyphs[num_glyphs].set (u_glyph);
@ -80,6 +72,9 @@ arabic_fallback_synthesize_lookup_single (const hb_ot_shape_plan_t *plan HB_UNUS
num_glyphs++; num_glyphs++;
} }
if (!num_glyphs)
return NULL;
/* Bubble-sort! /* Bubble-sort!
* May not be good-enough for presidential candidate interviews, but good-enough for us... */ * May not be good-enough for presidential candidate interviews, but good-enough for us... */
hb_bubble_sort (&glyphs[0], num_glyphs, OT::GlyphID::cmp, &substitutes[0]); hb_bubble_sort (&glyphs[0], num_glyphs, OT::GlyphID::cmp, &substitutes[0]);
@ -157,6 +152,9 @@ arabic_fallback_synthesize_lookup_ligature (const hb_ot_shape_plan_t *plan HB_UN
} }
} }
if (!num_ligatures)
return NULL;
OT::Supplier<OT::GlyphID> first_glyphs_supplier (first_glyphs, num_first_glyphs); OT::Supplier<OT::GlyphID> first_glyphs_supplier (first_glyphs, num_first_glyphs);
OT::Supplier<unsigned int > ligature_per_first_glyph_count_supplier (ligature_per_first_glyph_count_list, num_first_glyphs); OT::Supplier<unsigned int > ligature_per_first_glyph_count_supplier (ligature_per_first_glyph_count_list, num_first_glyphs);
OT::Supplier<OT::GlyphID> ligatures_supplier (ligature_list, num_ligatures); OT::Supplier<OT::GlyphID> ligatures_supplier (ligature_list, num_ligatures);
@ -193,17 +191,108 @@ arabic_fallback_synthesize_lookup (const hb_ot_shape_plan_t *plan,
return arabic_fallback_synthesize_lookup_ligature (plan, font); return arabic_fallback_synthesize_lookup_ligature (plan, font);
} }
#define ARABIC_FALLBACK_MAX_LOOKUPS 5
struct arabic_fallback_plan_t struct arabic_fallback_plan_t
{ {
ASSERT_POD (); ASSERT_POD ();
hb_mask_t mask_array[ARABIC_NUM_FALLBACK_FEATURES]; unsigned int num_lookups;
OT::SubstLookup *lookup_array[ARABIC_NUM_FALLBACK_FEATURES]; bool free_lookups;
hb_ot_layout_lookup_accelerator_t accel_array[ARABIC_NUM_FALLBACK_FEATURES];
hb_mask_t mask_array[ARABIC_FALLBACK_MAX_LOOKUPS];
OT::SubstLookup *lookup_array[ARABIC_FALLBACK_MAX_LOOKUPS];
hb_ot_layout_lookup_accelerator_t accel_array[ARABIC_FALLBACK_MAX_LOOKUPS];
}; };
static const arabic_fallback_plan_t arabic_fallback_plan_nil = {}; static const arabic_fallback_plan_t arabic_fallback_plan_nil = {};
#if (defined(_WIN32) || defined(__CYGWIN__)) && !defined(HB_WITH_WIN1256)
#define HB_WITH_WIN1256
#endif
#ifdef HB_WITH_WIN1256
#include "hb-ot-shape-complex-arabic-win1256.hh"
#endif
struct ManifestLookup {
OT::Tag tag;
OT::OffsetTo<OT::SubstLookup> lookupOffset;
};
typedef OT::ArrayOf<ManifestLookup> Manifest;
static bool
arabic_fallback_plan_init_win1256 (arabic_fallback_plan_t *fallback_plan,
const hb_ot_shape_plan_t *plan,
hb_font_t *font)
{
#ifdef HB_WITH_WIN1256
/* Does this font look like it's Windows-1256-encoded? */
hb_codepoint_t g;
if (!(hb_font_get_glyph (font, 0x0627u, 0, &g) && g == 199 /* ALEF */ &&
hb_font_get_glyph (font, 0x0644u, 0, &g) && g == 225 /* LAM */ &&
hb_font_get_glyph (font, 0x0649u, 0, &g) && g == 236 /* ALEF MAKSURA */ &&
hb_font_get_glyph (font, 0x064Au, 0, &g) && g == 237 /* YEH */ &&
hb_font_get_glyph (font, 0x0652u, 0, &g) && g == 250 /* SUKUN */))
return false;
const Manifest &manifest = reinterpret_cast<const Manifest&> (arabic_win1256_gsub_lookups.manifest);
ASSERT_STATIC (sizeof (arabic_win1256_gsub_lookups.manifestData) / sizeof (ManifestLookup)
<= ARABIC_FALLBACK_MAX_LOOKUPS);
/* TODO sanitize the table? */
unsigned j = 0;
unsigned int count = manifest.len;
for (unsigned int i = 0; i < count; i++)
{
fallback_plan->mask_array[j] = plan->map.get_1_mask (manifest[i].tag);
if (fallback_plan->mask_array[j])
{
fallback_plan->lookup_array[j] = const_cast<OT::SubstLookup*> (&(&manifest+manifest[i].lookupOffset));
if (fallback_plan->lookup_array[j])
{
fallback_plan->accel_array[j].init (*fallback_plan->lookup_array[j]);
j++;
}
}
}
fallback_plan->num_lookups = j;
fallback_plan->free_lookups = false;
return j > 0;
#else
return false;
#endif
}
static bool
arabic_fallback_plan_init_unicode (arabic_fallback_plan_t *fallback_plan,
const hb_ot_shape_plan_t *plan,
hb_font_t *font)
{
ASSERT_STATIC (ARRAY_LENGTH_CONST(arabic_fallback_features) <= ARABIC_FALLBACK_MAX_LOOKUPS);
unsigned int j = 0;
for (unsigned int i = 0; i < ARRAY_LENGTH(arabic_fallback_features) ; i++)
{
fallback_plan->mask_array[j] = plan->map.get_1_mask (arabic_fallback_features[i]);
if (fallback_plan->mask_array[j])
{
fallback_plan->lookup_array[j] = arabic_fallback_synthesize_lookup (plan, font, i);
if (fallback_plan->lookup_array[j])
{
fallback_plan->accel_array[j].init (*fallback_plan->lookup_array[j]);
j++;
}
}
}
fallback_plan->num_lookups = j;
fallback_plan->free_lookups = true;
return j > 0;
}
static arabic_fallback_plan_t * static arabic_fallback_plan_t *
arabic_fallback_plan_create (const hb_ot_shape_plan_t *plan, arabic_fallback_plan_create (const hb_ot_shape_plan_t *plan,
hb_font_t *font) hb_font_t *font)
@ -212,17 +301,21 @@ arabic_fallback_plan_create (const hb_ot_shape_plan_t *plan,
if (unlikely (!fallback_plan)) if (unlikely (!fallback_plan))
return const_cast<arabic_fallback_plan_t *> (&arabic_fallback_plan_nil); return const_cast<arabic_fallback_plan_t *> (&arabic_fallback_plan_nil);
for (unsigned int i = 0; i < ARABIC_NUM_FALLBACK_FEATURES; i++) fallback_plan->num_lookups = 0;
{ fallback_plan->free_lookups = false;
fallback_plan->mask_array[i] = plan->map.get_1_mask (arabic_fallback_features[i]);
if (fallback_plan->mask_array[i]) {
fallback_plan->lookup_array[i] = arabic_fallback_synthesize_lookup (plan, font, i);
if (fallback_plan->lookup_array[i])
fallback_plan->accel_array[i].init (*fallback_plan->lookup_array[i]);
}
}
return fallback_plan; /* Try synthesizing GSUB table using Unicode Arabic Presentation Forms,
* in case the font has cmap entries for the presentation-forms characters. */
if (arabic_fallback_plan_init_unicode (fallback_plan, plan, font))
return fallback_plan;
/* See if this looks like a Windows-1256-encoded font. If it does, use a
* hand-coded GSUB table. */
if (arabic_fallback_plan_init_win1256 (fallback_plan, plan, font))
return fallback_plan;
free (fallback_plan);
return const_cast<arabic_fallback_plan_t *> (&arabic_fallback_plan_nil);
} }
static void static void
@ -231,11 +324,12 @@ arabic_fallback_plan_destroy (arabic_fallback_plan_t *fallback_plan)
if (!fallback_plan || fallback_plan == &arabic_fallback_plan_nil) if (!fallback_plan || fallback_plan == &arabic_fallback_plan_nil)
return; return;
for (unsigned int i = 0; i < ARABIC_NUM_FALLBACK_FEATURES; i++) for (unsigned int i = 0; i < fallback_plan->num_lookups; i++)
if (fallback_plan->lookup_array[i]) if (fallback_plan->lookup_array[i])
{ {
fallback_plan->accel_array[i].fini (fallback_plan->lookup_array[i]); fallback_plan->accel_array[i].fini (fallback_plan->lookup_array[i]);
free (fallback_plan->lookup_array[i]); if (fallback_plan->free_lookups)
free (fallback_plan->lookup_array[i]);
} }
free (fallback_plan); free (fallback_plan);
@ -247,7 +341,7 @@ arabic_fallback_plan_shape (arabic_fallback_plan_t *fallback_plan,
hb_buffer_t *buffer) hb_buffer_t *buffer)
{ {
OT::hb_apply_context_t c (0, font, buffer); OT::hb_apply_context_t c (0, font, buffer);
for (unsigned int i = 0; i < ARABIC_NUM_FALLBACK_FEATURES; i++) for (unsigned int i = 0; i < fallback_plan->num_lookups; i++)
if (fallback_plan->lookup_array[i]) { if (fallback_plan->lookup_array[i]) {
c.set_lookup_mask (fallback_plan->mask_array[i]); c.set_lookup_mask (fallback_plan->mask_array[i]);
hb_ot_layout_substitute_lookup (&c, hb_ot_layout_substitute_lookup (&c,

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,321 @@
/*
* Copyright © 2014 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_OT_SHAPE_COMPLEX_ARABIC_WIN1256_HH
/*
* The macros in the first part of this file are generic macros that can
* be used to define the bytes for OpenType table data in code in a
* readable manner. We can move the macros to reside with their respective
* struct types, but since we only use these to define one data table, the
* Windows-1256 Arabic shaping table in this file, we keep them here.
*/
/* First we measure, then we cut. */
#ifndef OT_MEASURE
#define OT_MEASURE
#define OT_TABLE_START static const struct TABLE_NAME {
#define OT_TABLE_END }
#define OT_LABEL_START(Name) unsigned char Name[
#define OT_LABEL_END ];
#define OT_BYTE(u8) +1/*byte*/
#define OT_USHORT(u16) +2/*bytes*/
#else
#undef OT_MEASURE
#define OT_TABLE_START TABLE_NAME = {
#define OT_TABLE_END };
#define OT_LABEL_START(Name) {
#define OT_LABEL_END },
#define OT_BYTE(u8) (u8),
#define OT_USHORT(u16) (unsigned char)((u16)>>8), (unsigned char)((u16)&0xFFu),
#define OT_COUNT(Name, ItemSize) ((unsigned int) sizeof(((struct TABLE_NAME*)0)->Name) \
/ (unsigned int)(ItemSize) \
/* OT_ASSERT it's divisible (and positive). */)
#define OT_DISTANCE(From,To) ((unsigned int) \
((char*)(&((struct TABLE_NAME*)0)->To) - \
(char*)(&((struct TABLE_NAME*)0)->From)) \
/* OT_ASSERT it's positive. */)
#endif
#define OT_LABEL(Name) \
OT_LABEL_END \
OT_LABEL_START(Name)
/* Whenever we receive an argument that is a list, it will expand to
* contain commas. That cannot be passed to another macro because the
* commas will throw off the preprocessor. The solution is to wrap
* the passed-in argument in OT_LIST() before passing to the next macro.
* Unfortunately this trick requires vararg macros. */
#define OT_LIST(...) __VA_ARGS__
/*
* Basic Types
*/
#define OT_TAG(a,b,c,d) \
OT_BYTE(a) OT_BYTE(b) OT_BYTE(c) OT_BYTE(d)
#define OT_OFFSET(From, To) /* Offset from From to To in bytes */ \
OT_USHORT(OT_DISTANCE(From, To))
#define OT_GLYPHID /* GlyphID */ \
OT_USHORT
#define OT_UARRAY(Name, Items) \
OT_LABEL_START(Name) \
OT_USHORT(OT_COUNT(Name##Data, 2)) \
OT_LABEL(Name##Data) \
Items \
OT_LABEL_END
#define OT_UHEADLESSARRAY(Name, Items) \
OT_LABEL_START(Name) \
OT_USHORT(OT_COUNT(Name##Data, 2) + 1) \
OT_LABEL(Name##Data) \
Items \
OT_LABEL_END
/*
* Common Types
*/
#define OT_LOOKUP_FLAG_IGNORE_MARKS 0x08u
#define OT_LOOKUP(Name, LookupType, LookupFlag, SubLookupOffsets) \
OT_LABEL_START(Name) \
OT_USHORT(LookupType) \
OT_USHORT(LookupFlag) \
OT_LABEL_END \
OT_UARRAY(Name##SubLookupOffsetsArray, OT_LIST(SubLookupOffsets))
#define OT_SUBLOOKUP(Name, SubFormat, Items) \
OT_LABEL_START(Name) \
OT_USHORT(SubFormat) \
Items
#define OT_COVERAGE1(Name, Items) \
OT_LABEL_START(Name) \
OT_USHORT(1) \
OT_LABEL_END \
OT_UARRAY(Name##Glyphs, OT_LIST(Items))
/*
* GSUB
*/
#define OT_LOOKUP_TYPE_SUBST_SINGLE 1u
#define OT_LOOKUP_TYPE_SUBST_MULTIPLE 2u
#define OT_LOOKUP_TYPE_SUBST_LIGATURE 4u
#define OT_SUBLOOKUP_SINGLE_SUBST_FORMAT2(Name, FromGlyphs, ToGlyphs) \
OT_SUBLOOKUP(Name, 2, \
OT_OFFSET(Name, Name##Coverage) \
OT_LABEL_END \
OT_UARRAY(Name##Substitute, OT_LIST(ToGlyphs)) \
) \
OT_COVERAGE1(Name##Coverage, OT_LIST(FromGlyphs)) \
/* ASSERT_STATIC_EXPR len(FromGlyphs) == len(ToGlyphs) */
#define OT_SUBLOOKUP_LIGATURE_SUBST_FORMAT1(Name, FirstGlyphs, LigatureSetOffsets) \
OT_SUBLOOKUP(Name, 1, \
OT_OFFSET(Name, Name##Coverage) \
OT_LABEL_END \
OT_UARRAY(Name##LigatureSetOffsetsArray, OT_LIST(LigatureSetOffsets)) \
) \
OT_COVERAGE1(Name##Coverage, OT_LIST(FirstGlyphs)) \
/* ASSERT_STATIC_EXPR len(FirstGlyphs) == len(LigatureSetOffsets) */
#define OT_LIGATURE_SET(Name, LigatureSetOffsets) \
OT_UARRAY(Name, OT_LIST(LigatureSetOffsets))
#define OT_LIGATURE(Name, Components, LigGlyph) \
OT_LABEL_START(Name) \
LigGlyph \
OT_LABEL_END \
OT_UHEADLESSARRAY(Name##ComponentsArray, OT_LIST(Components))
/*
*
* Start of Windows-1256 shaping table.
*
*/
/* Table name. */
#define TABLE_NAME arabic_win1256_gsub_lookups
/* Table manifest. */
#define MANIFEST(Items) \
OT_LABEL_START(manifest) \
OT_USHORT(OT_COUNT(manifestData, 6)) \
OT_LABEL(manifestData) \
Items \
OT_LABEL_END
#define MANIFEST_LOOKUP(Tag, Name) \
Tag \
OT_OFFSET(manifest, Name)
/* Shorthand. */
#define G OT_GLYPHID
/*
* Table Start
*/
OT_TABLE_START
/*
* Manifest
*/
MANIFEST(
MANIFEST_LOOKUP(OT_TAG('r','l','i','g'), rligLookup)
MANIFEST_LOOKUP(OT_TAG('i','n','i','t'), initLookup)
MANIFEST_LOOKUP(OT_TAG('m','e','d','i'), mediLookup)
MANIFEST_LOOKUP(OT_TAG('f','i','n','a'), finaLookup)
MANIFEST_LOOKUP(OT_TAG('r','l','i','g'), rligMarksLookup)
)
/*
* Lookups
*/
OT_LOOKUP(initLookup, OT_LOOKUP_TYPE_SUBST_SINGLE, OT_LOOKUP_FLAG_IGNORE_MARKS,
OT_OFFSET(initLookup, initmediSubLookup)
OT_OFFSET(initLookup, initSubLookup)
)
OT_LOOKUP(mediLookup, OT_LOOKUP_TYPE_SUBST_SINGLE, OT_LOOKUP_FLAG_IGNORE_MARKS,
OT_OFFSET(mediLookup, initmediSubLookup)
OT_OFFSET(mediLookup, mediSubLookup)
OT_OFFSET(mediLookup, medifinaLamAlefSubLookup)
)
OT_LOOKUP(finaLookup, OT_LOOKUP_TYPE_SUBST_SINGLE, OT_LOOKUP_FLAG_IGNORE_MARKS,
OT_OFFSET(finaLookup, finaSubLookup)
/* We don't need this one currently as the sequence inherits masks
* from the first item. Just in case we change that in the future
* to be smart about Arabic masks when ligating... */
OT_OFFSET(finaLookup, medifinaLamAlefSubLookup)
)
OT_LOOKUP(rligLookup, OT_LOOKUP_TYPE_SUBST_LIGATURE, OT_LOOKUP_FLAG_IGNORE_MARKS,
OT_OFFSET(rligLookup, lamAlefLigaturesSubLookup)
)
OT_LOOKUP(rligMarksLookup, OT_LOOKUP_TYPE_SUBST_LIGATURE, 0,
OT_OFFSET(rligMarksLookup, shaddaLigaturesSubLookup)
)
/*
* init/medi/fina forms
*/
OT_SUBLOOKUP_SINGLE_SUBST_FORMAT2(initmediSubLookup,
G(198) G(200) G(201) G(202) G(203) G(204) G(205) G(206) G(211)
G(212) G(213) G(214) G(223) G(225) G(227) G(228) G(236) G(237),
G(162) G(4) G(5) G(5) G(6) G(7) G(9) G(11) G(13)
G(14) G(15) G(26) G(140) G(141) G(142) G(143) G(154) G(154)
)
OT_SUBLOOKUP_SINGLE_SUBST_FORMAT2(initSubLookup,
G(218) G(219) G(221) G(222) G(229),
G(27) G(30) G(128) G(131) G(144)
)
OT_SUBLOOKUP_SINGLE_SUBST_FORMAT2(mediSubLookup,
G(218) G(219) G(221) G(222) G(229),
G(28) G(31) G(129) G(138) G(149)
)
OT_SUBLOOKUP_SINGLE_SUBST_FORMAT2(finaSubLookup,
G(194) G(195) G(197) G(198) G(199) G(201) G(204) G(205) G(206)
G(218) G(219) G(229) G(236) G(237),
G(2) G(1) G(3) G(181) G(0) G(159) G(8) G(10) G(12)
G(29) G(127) G(152) G(160) G(156)
)
OT_SUBLOOKUP_SINGLE_SUBST_FORMAT2(medifinaLamAlefSubLookup,
G(165) G(178) G(180) G(252),
G(170) G(179) G(185) G(255)
)
/*
* Lam+Alef ligatures
*/
OT_SUBLOOKUP_LIGATURE_SUBST_FORMAT1(lamAlefLigaturesSubLookup,
G(225),
OT_OFFSET(lamAlefLigaturesSubLookup, lamLigatureSet)
)
OT_LIGATURE_SET(lamLigatureSet,
OT_OFFSET(lamLigatureSet, lamInitLigature1)
OT_OFFSET(lamLigatureSet, lamInitLigature2)
OT_OFFSET(lamLigatureSet, lamInitLigature3)
OT_OFFSET(lamLigatureSet, lamInitLigature4)
)
OT_LIGATURE(lamInitLigature1, G(199), G(165))
OT_LIGATURE(lamInitLigature2, G(195), G(178))
OT_LIGATURE(lamInitLigature3, G(194), G(180))
OT_LIGATURE(lamInitLigature4, G(197), G(252))
/*
* Shadda ligatures
*/
OT_SUBLOOKUP_LIGATURE_SUBST_FORMAT1(shaddaLigaturesSubLookup,
G(248),
OT_OFFSET(shaddaLigaturesSubLookup, shaddaLigatureSet)
)
OT_LIGATURE_SET(shaddaLigatureSet,
OT_OFFSET(shaddaLigatureSet, shaddaLigature1)
OT_OFFSET(shaddaLigatureSet, shaddaLigature2)
OT_OFFSET(shaddaLigatureSet, shaddaLigature3)
)
OT_LIGATURE(shaddaLigature1, G(243), G(172))
OT_LIGATURE(shaddaLigature2, G(245), G(173))
OT_LIGATURE(shaddaLigature3, G(246), G(175))
/*
* Table end
*/
OT_TABLE_END
/*
* Clean up
*/
#undef OT_TABLE_START
#undef OT_TABLE_END
#undef OT_LABEL_START
#undef OT_LABEL_END
#undef OT_BYTE
#undef OT_USHORT
#undef OT_DISTANCE
#undef OT_COUNT
/*
* Include a second time to get the table data...
*/
#ifdef OT_MEASURE
#include __FILE__
#endif
#define HB_OT_SHAPE_COMPLEX_ARABIC_WIN1256_HH
#endif /* HB_OT_SHAPE_COMPLEX_ARABIC_WIN1256_HH */

View File

@ -57,68 +57,41 @@ enum {
static unsigned int get_joining_type (hb_codepoint_t u, hb_unicode_general_category_t gen_cat) static unsigned int get_joining_type (hb_codepoint_t u, hb_unicode_general_category_t gen_cat)
{ {
if (likely (hb_in_range<hb_codepoint_t> (u, JOINING_TABLE_FIRST, JOINING_TABLE_LAST))) { unsigned int j_type = joining_type(u);
unsigned int j_type = joining_table[u - JOINING_TABLE_FIRST]; if (likely (j_type != JOINING_TYPE_X))
if (likely (j_type != JOINING_TYPE_X)) return j_type;
return j_type;
}
/* Mongolian joining data is not in ArabicJoining.txt yet. */ return (FLAG(gen_cat) &
if (unlikely (hb_in_range<hb_codepoint_t> (u, 0x1800, 0x18AF))) (FLAG(HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) |
{ FLAG(HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK) |
if (unlikely (hb_in_range<hb_codepoint_t> (u, 0x1880, 0x1886))) FLAG(HB_UNICODE_GENERAL_CATEGORY_FORMAT))
return JOINING_TYPE_U; ) ? JOINING_TYPE_T : JOINING_TYPE_U;
/* All letters, SIBE SYLLABLE BOUNDARY MARKER, and NIRUGU are D */
if ((FLAG(gen_cat) & (FLAG (HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER) |
FLAG (HB_UNICODE_GENERAL_CATEGORY_MODIFIER_LETTER)))
|| u == 0x1807 || u == 0x180A)
return JOINING_TYPE_D;
}
/* 'Phags-pa joining data is not in ArabicJoining.txt yet. */
if (unlikely (hb_in_range<hb_codepoint_t> (u, 0xA840, 0xA872)))
{
if (unlikely (u == 0xA872))
return JOINING_TYPE_L;
return JOINING_TYPE_D;
}
if (unlikely (hb_in_range<hb_codepoint_t> (u, 0x200C, 0x200D)))
{
return u == 0x200C ? JOINING_TYPE_U : JOINING_TYPE_C;
}
return (FLAG(gen_cat) & (FLAG(HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) | FLAG(HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK) | FLAG(HB_UNICODE_GENERAL_CATEGORY_FORMAT))) ?
JOINING_TYPE_T : JOINING_TYPE_U;
} }
#define FEATURE_IS_SYRIAC(tag) hb_in_range<unsigned char> ((unsigned char) (tag), '2', '3')
static const hb_tag_t arabic_features[] = static const hb_tag_t arabic_features[] =
{ {
HB_TAG('i','n','i','t'),
HB_TAG('m','e','d','i'),
HB_TAG('f','i','n','a'),
HB_TAG('i','s','o','l'), HB_TAG('i','s','o','l'),
/* Syriac */ HB_TAG('f','i','n','a'),
HB_TAG('m','e','d','2'),
HB_TAG('f','i','n','2'), HB_TAG('f','i','n','2'),
HB_TAG('f','i','n','3'), HB_TAG('f','i','n','3'),
HB_TAG('m','e','d','i'),
HB_TAG('m','e','d','2'),
HB_TAG('i','n','i','t'),
HB_TAG_NONE HB_TAG_NONE
}; };
/* Same order as the feature array */ /* Same order as the feature array */
enum { enum {
INIT,
MEDI,
FINA,
ISOL, ISOL,
FINA,
/* Syriac */
MED2,
FIN2, FIN2,
FIN3, FIN3,
MEDI,
MED2,
INIT,
NONE, NONE,
@ -171,14 +144,23 @@ collect_features_arabic (hb_ot_shape_planner_t *plan)
{ {
hb_ot_map_builder_t *map = &plan->map; hb_ot_map_builder_t *map = &plan->map;
/* For Language forms (in ArabicOT speak), we do the iso/fina/medi/init together, /* We apply features according to the Arabic spec, with pauses
* then rlig and calt each in their own stage. This makes IranNastaliq's ALLAH * in between most.
* ligature work correctly. It's unfortunate though...
* *
* This also makes Arial Bold in Windows7 work. See: * The pause between init/medi/... and rlig is required. See eg:
* https://bugzilla.mozilla.org/show_bug.cgi?id=644184 * https://bugzilla.mozilla.org/show_bug.cgi?id=644184
* *
* TODO: Add test cases for these two. * The pauses between init/medi/... themselves are not necessarily
* needed as only one of those features is applied to any character.
* The only difference it makes is when fonts have contextual
* substitutions. We now follow the order of the spec, which makes
* for better experience if that's what Uniscribe is doing.
*
* At least for Arabic, looks like Uniscribe has a pause between
* rlig and calt. Otherwise the IranNastaliq's ALLAH ligature won't
* work. However, testing shows that rlig and calt are applied
* together for Mongolian in Uniscribe. As such, we only add a
* pause for Arabic, not other scripts.
*/ */
map->add_gsub_pause (nuke_joiners); map->add_gsub_pause (nuke_joiners);
@ -189,16 +171,28 @@ collect_features_arabic (hb_ot_shape_planner_t *plan)
map->add_gsub_pause (NULL); map->add_gsub_pause (NULL);
for (unsigned int i = 0; i < ARABIC_NUM_FEATURES; i++) for (unsigned int i = 0; i < ARABIC_NUM_FEATURES; i++)
map->add_feature (arabic_features[i], 1, i < 4 ? F_HAS_FALLBACK : F_NONE); /* The first four features have fallback. */ {
bool has_fallback = plan->props.script == HB_SCRIPT_ARABIC && !FEATURE_IS_SYRIAC (arabic_features[i]);
map->add_gsub_pause (NULL); map->add_feature (arabic_features[i], 1, has_fallback ? F_HAS_FALLBACK : F_NONE);
map->add_gsub_pause (NULL);
}
map->add_feature (HB_TAG('r','l','i','g'), 1, F_GLOBAL|F_HAS_FALLBACK); map->add_feature (HB_TAG('r','l','i','g'), 1, F_GLOBAL|F_HAS_FALLBACK);
map->add_gsub_pause (arabic_fallback_shape); if (plan->props.script == HB_SCRIPT_ARABIC)
map->add_gsub_pause (arabic_fallback_shape);
map->add_global_bool_feature (HB_TAG('c','a','l','t')); map->add_global_bool_feature (HB_TAG('c','a','l','t'));
map->add_gsub_pause (NULL); map->add_gsub_pause (NULL);
/* The spec includes 'cswh'. Earlier versions of Windows
* used to enable this by default, but testing suggests
* that Windows 8 and later do not enable it by default,
* and spec now says 'Off by default'.
* We disabled this in ae23c24c32.
* Note that IranNastaliq uses this feature extensively
* to fixup broken glyph sequences. Oh well...
* Test case: U+0643,U+0640,U+0631. */
//map->add_global_bool_feature (HB_TAG('c','s','w','h'));
map->add_global_bool_feature (HB_TAG('m','s','e','t')); map->add_global_bool_feature (HB_TAG('m','s','e','t'));
} }
@ -228,8 +222,9 @@ data_create_arabic (const hb_ot_shape_plan_t *plan)
arabic_plan->do_fallback = plan->props.script == HB_SCRIPT_ARABIC; arabic_plan->do_fallback = plan->props.script == HB_SCRIPT_ARABIC;
for (unsigned int i = 0; i < ARABIC_NUM_FEATURES; i++) { for (unsigned int i = 0; i < ARABIC_NUM_FEATURES; i++) {
arabic_plan->mask_array[i] = plan->map.get_1_mask (arabic_features[i]); arabic_plan->mask_array[i] = plan->map.get_1_mask (arabic_features[i]);
if (i < 4) arabic_plan->do_fallback = arabic_plan->do_fallback &&
arabic_plan->do_fallback = arabic_plan->do_fallback && plan->map.needs_fallback (arabic_features[i]); (FEATURE_IS_SYRIAC (arabic_features[i]) ||
plan->map.needs_fallback (arabic_features[i]));
} }
return arabic_plan; return arabic_plan;
@ -249,61 +244,65 @@ static void
arabic_joining (hb_buffer_t *buffer) arabic_joining (hb_buffer_t *buffer)
{ {
unsigned int count = buffer->len; unsigned int count = buffer->len;
hb_glyph_info_t *info = buffer->info;
unsigned int prev = (unsigned int) -1, state = 0; unsigned int prev = (unsigned int) -1, state = 0;
HB_BUFFER_ALLOCATE_VAR (buffer, arabic_shaping_action);
/* Check pre-context */ /* Check pre-context */
if (!(buffer->flags & HB_BUFFER_FLAG_BOT)) for (unsigned int i = 0; i < buffer->context_len[0]; i++)
for (unsigned int i = 0; i < buffer->context_len[0]; i++) {
{ unsigned int this_type = get_joining_type (buffer->context[0][i], buffer->unicode->general_category (buffer->context[0][i]));
unsigned int this_type = get_joining_type (buffer->context[0][i], buffer->unicode->general_category (buffer->context[0][i]));
if (unlikely (this_type == JOINING_TYPE_T)) if (unlikely (this_type == JOINING_TYPE_T))
continue; continue;
const arabic_state_table_entry *entry = &arabic_state_table[state][this_type]; const arabic_state_table_entry *entry = &arabic_state_table[state][this_type];
state = entry->next_state; state = entry->next_state;
break; break;
} }
for (unsigned int i = 0; i < count; i++) for (unsigned int i = 0; i < count; i++)
{ {
unsigned int this_type = get_joining_type (buffer->info[i].codepoint, _hb_glyph_info_get_general_category (&buffer->info[i])); unsigned int this_type = get_joining_type (info[i].codepoint, _hb_glyph_info_get_general_category (&info[i]));
if (unlikely (this_type == JOINING_TYPE_T)) { if (unlikely (this_type == JOINING_TYPE_T)) {
buffer->info[i].arabic_shaping_action() = NONE; info[i].arabic_shaping_action() = NONE;
continue; continue;
} }
const arabic_state_table_entry *entry = &arabic_state_table[state][this_type]; const arabic_state_table_entry *entry = &arabic_state_table[state][this_type];
if (entry->prev_action != NONE && prev != (unsigned int) -1) if (entry->prev_action != NONE && prev != (unsigned int) -1)
for (; prev < i; prev++) info[prev].arabic_shaping_action() = entry->prev_action;
buffer->info[prev].arabic_shaping_action() = entry->prev_action;
buffer->info[i].arabic_shaping_action() = entry->curr_action; info[i].arabic_shaping_action() = entry->curr_action;
prev = i; prev = i;
state = entry->next_state; state = entry->next_state;
} }
if (!(buffer->flags & HB_BUFFER_FLAG_EOT)) for (unsigned int i = 0; i < buffer->context_len[1]; i++)
for (unsigned int i = 0; i < buffer->context_len[1]; i++) {
{ unsigned int this_type = get_joining_type (buffer->context[1][i], buffer->unicode->general_category (buffer->context[1][i]));
unsigned int this_type = get_joining_type (buffer->context[1][i], buffer->unicode->general_category (buffer->context[1][i]));
if (unlikely (this_type == JOINING_TYPE_T)) if (unlikely (this_type == JOINING_TYPE_T))
continue; continue;
const arabic_state_table_entry *entry = &arabic_state_table[state][this_type]; const arabic_state_table_entry *entry = &arabic_state_table[state][this_type];
if (entry->prev_action != NONE && prev != (unsigned int) -1) if (entry->prev_action != NONE && prev != (unsigned int) -1)
buffer->info[prev].arabic_shaping_action() = entry->prev_action; info[prev].arabic_shaping_action() = entry->prev_action;
break; break;
} }
}
static void
HB_BUFFER_DEALLOCATE_VAR (buffer, arabic_shaping_action); mongolian_variation_selectors (hb_buffer_t *buffer)
{
/* Copy arabic_shaping_action() from base to Mongolian variation selectors. */
unsigned int count = buffer->len;
hb_glyph_info_t *info = buffer->info;
for (unsigned int i = 1; i < count; i++)
if (unlikely (hb_in_range (info[i].codepoint, 0x180Bu, 0x180Du)))
info[i].arabic_shaping_action() = info[i - 1].arabic_shaping_action();
} }
static void static void
@ -311,12 +310,20 @@ setup_masks_arabic (const hb_ot_shape_plan_t *plan,
hb_buffer_t *buffer, hb_buffer_t *buffer,
hb_font_t *font HB_UNUSED) hb_font_t *font HB_UNUSED)
{ {
HB_BUFFER_ALLOCATE_VAR (buffer, arabic_shaping_action);
const arabic_shape_plan_t *arabic_plan = (const arabic_shape_plan_t *) plan->data; const arabic_shape_plan_t *arabic_plan = (const arabic_shape_plan_t *) plan->data;
arabic_joining (buffer); arabic_joining (buffer);
if (plan->props.script == HB_SCRIPT_MONGOLIAN)
mongolian_variation_selectors (buffer);
unsigned int count = buffer->len; unsigned int count = buffer->len;
hb_glyph_info_t *info = buffer->info;
for (unsigned int i = 0; i < count; i++) for (unsigned int i = 0; i < count; i++)
buffer->info[i].mask |= arabic_plan->mask_array[buffer->info[i].arabic_shaping_action()]; info[i].mask |= arabic_plan->mask_array[info[i].arabic_shaping_action()];
HB_BUFFER_DEALLOCATE_VAR (buffer, arabic_shaping_action);
} }
@ -326,9 +333,10 @@ nuke_joiners (const hb_ot_shape_plan_t *plan HB_UNUSED,
hb_buffer_t *buffer) hb_buffer_t *buffer)
{ {
unsigned int count = buffer->len; unsigned int count = buffer->len;
hb_glyph_info_t *info = buffer->info;
for (unsigned int i = 0; i < count; i++) for (unsigned int i = 0; i < count; i++)
if (_hb_glyph_info_is_zwj (&buffer->info[i])) if (_hb_glyph_info_is_zwj (&info[i]))
_hb_glyph_info_flip_joiners (&buffer->info[i]); _hb_glyph_info_flip_joiners (&info[i]);
} }
static void static void

View File

@ -59,6 +59,15 @@ collect_features_hangul (hb_ot_shape_planner_t *plan)
map->add_feature (hangul_features[i], 1, F_NONE); map->add_feature (hangul_features[i], 1, F_NONE);
} }
static void
override_features_hangul (hb_ot_shape_planner_t *plan)
{
/* Uniscribe does not apply 'calt' for Hangul, and certain fonts
* (Noto Sans CJK, Source Sans Han, etc) apply all of jamo lookups
* in calt, which is not desirable. */
plan->map.add_feature (HB_TAG('c','a','l','t'), 0, F_GLOBAL);
}
struct hangul_shape_plan_t struct hangul_shape_plan_t
{ {
ASSERT_POD (); ASSERT_POD ();
@ -86,26 +95,26 @@ data_destroy_hangul (void *data)
} }
/* Constants for algorithmic hangul syllable [de]composition. */ /* Constants for algorithmic hangul syllable [de]composition. */
#define LBase 0x1100 #define LBase 0x1100u
#define VBase 0x1161 #define VBase 0x1161u
#define TBase 0x11A7 #define TBase 0x11A7u
#define LCount 19 #define LCount 19u
#define VCount 21 #define VCount 21u
#define TCount 28 #define TCount 28u
#define SBase 0xAC00 #define SBase 0xAC00u
#define NCount (VCount * TCount) #define NCount (VCount * TCount)
#define SCount (LCount * NCount) #define SCount (LCount * NCount)
#define isCombiningL(u) (hb_in_range<hb_codepoint_t> ((u), LBase, LBase+LCount-1)) #define isCombiningL(u) (hb_in_range ((u), LBase, LBase+LCount-1))
#define isCombiningV(u) (hb_in_range<hb_codepoint_t> ((u), VBase, VBase+VCount-1)) #define isCombiningV(u) (hb_in_range ((u), VBase, VBase+VCount-1))
#define isCombiningT(u) (hb_in_range<hb_codepoint_t> ((u), TBase+1, TBase+TCount-1)) #define isCombiningT(u) (hb_in_range ((u), TBase+1, TBase+TCount-1))
#define isCombinedS(u) (hb_in_range<hb_codepoint_t> ((u), SBase, SBase+SCount-1)) #define isCombinedS(u) (hb_in_range ((u), SBase, SBase+SCount-1))
#define isL(u) (hb_in_ranges<hb_codepoint_t> ((u), 0x1100, 0x115F, 0xA960, 0xA97C)) #define isL(u) (hb_in_ranges ((u), 0x1100u, 0x115Fu, 0xA960u, 0xA97Cu))
#define isV(u) (hb_in_ranges<hb_codepoint_t> ((u), 0x1160, 0x11A7, 0xD7B0, 0xD7C6)) #define isV(u) (hb_in_ranges ((u), 0x1160u, 0x11A7u, 0xD7B0u, 0xD7C6u))
#define isT(u) (hb_in_ranges<hb_codepoint_t> ((u), 0x11A8, 0x11FF, 0xD7CB, 0xD7FB)) #define isT(u) (hb_in_ranges ((u), 0x11A8u, 0x11FFu, 0xD7CBu, 0xD7FBu))
#define isHangulTone(u) (hb_in_range<hb_codepoint_t> ((u), 0x302e, 0x302f)) #define isHangulTone(u) (hb_in_range ((u), 0x302Eu, 0x302Fu))
/* buffer var allocations */ /* buffer var allocations */
#define hangul_shaping_feature() complex_var_u8_0() /* hangul jamo shaping feature */ #define hangul_shaping_feature() complex_var_u8_0() /* hangul jamo shaping feature */
@ -211,14 +220,14 @@ preprocess_text_hangul (const hb_ot_shape_plan_t *plan,
else else
{ {
/* No valid syllable as base for tone mark; try to insert dotted circle. */ /* No valid syllable as base for tone mark; try to insert dotted circle. */
if (font->has_glyph (0x25cc)) if (font->has_glyph (0x25CCu))
{ {
hb_codepoint_t chars[2]; hb_codepoint_t chars[2];
if (!is_zero_width_char (font, u)) { if (!is_zero_width_char (font, u)) {
chars[0] = u; chars[0] = u;
chars[1] = 0x25cc; chars[1] = 0x25CCu;
} else { } else {
chars[0] = 0x25cc; chars[0] = 0x25CCu;
chars[1] = u; chars[1] = u;
} }
buffer->replace_glyphs (1, 2, chars); buffer->replace_glyphs (1, 2, chars);
@ -404,7 +413,7 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_hangul =
{ {
"hangul", "hangul",
collect_features_hangul, collect_features_hangul,
NULL, /* override_features */ override_features_hangul,
data_create_hangul, /* data_create */ data_create_hangul, /* data_create */
data_destroy_hangul, /* data_destroy */ data_destroy_hangul, /* data_destroy */
preprocess_text_hangul, preprocess_text_hangul,

View File

@ -35,116 +35,116 @@ compose_hebrew (const hb_ot_shape_normalize_context_t *c,
{ {
/* Hebrew presentation-form shaping. /* Hebrew presentation-form shaping.
* https://bugzilla.mozilla.org/show_bug.cgi?id=728866 * https://bugzilla.mozilla.org/show_bug.cgi?id=728866
* Hebrew presentation forms with dagesh, for characters 0x05D0..0x05EA; * Hebrew presentation forms with dagesh, for characters U+05D0..05EA;
* Note that some letters do not have a dagesh presForm encoded. * Note that some letters do not have a dagesh presForm encoded.
*/ */
static const hb_codepoint_t sDageshForms[0x05EA - 0x05D0 + 1] = { static const hb_codepoint_t sDageshForms[0x05EAu - 0x05D0u + 1] = {
0xFB30, /* ALEF */ 0xFB30u, /* ALEF */
0xFB31, /* BET */ 0xFB31u, /* BET */
0xFB32, /* GIMEL */ 0xFB32u, /* GIMEL */
0xFB33, /* DALET */ 0xFB33u, /* DALET */
0xFB34, /* HE */ 0xFB34u, /* HE */
0xFB35, /* VAV */ 0xFB35u, /* VAV */
0xFB36, /* ZAYIN */ 0xFB36u, /* ZAYIN */
0x0000, /* HET */ 0x0000u, /* HET */
0xFB38, /* TET */ 0xFB38u, /* TET */
0xFB39, /* YOD */ 0xFB39u, /* YOD */
0xFB3A, /* FINAL KAF */ 0xFB3Au, /* FINAL KAF */
0xFB3B, /* KAF */ 0xFB3Bu, /* KAF */
0xFB3C, /* LAMED */ 0xFB3Cu, /* LAMED */
0x0000, /* FINAL MEM */ 0x0000u, /* FINAL MEM */
0xFB3E, /* MEM */ 0xFB3Eu, /* MEM */
0x0000, /* FINAL NUN */ 0x0000u, /* FINAL NUN */
0xFB40, /* NUN */ 0xFB40u, /* NUN */
0xFB41, /* SAMEKH */ 0xFB41u, /* SAMEKH */
0x0000, /* AYIN */ 0x0000u, /* AYIN */
0xFB43, /* FINAL PE */ 0xFB43u, /* FINAL PE */
0xFB44, /* PE */ 0xFB44u, /* PE */
0x0000, /* FINAL TSADI */ 0x0000u, /* FINAL TSADI */
0xFB46, /* TSADI */ 0xFB46u, /* TSADI */
0xFB47, /* QOF */ 0xFB47u, /* QOF */
0xFB48, /* RESH */ 0xFB48u, /* RESH */
0xFB49, /* SHIN */ 0xFB49u, /* SHIN */
0xFB4A /* TAV */ 0xFB4Au /* TAV */
}; };
bool found = c->unicode->compose (a, b, ab); bool found = c->unicode->compose (a, b, ab);
if (!found) if (!found && !c->plan->has_mark)
{ {
/* Special-case Hebrew presentation forms that are excluded from /* Special-case Hebrew presentation forms that are excluded from
* standard normalization, but wanted for old fonts. */ * standard normalization, but wanted for old fonts. */
switch (b) { switch (b) {
case 0x05B4: /* HIRIQ */ case 0x05B4u: /* HIRIQ */
if (a == 0x05D9) { /* YOD */ if (a == 0x05D9u) { /* YOD */
*ab = 0xFB1D; *ab = 0xFB1Du;
found = true; found = true;
} }
break; break;
case 0x05B7: /* patah */ case 0x05B7u: /* patah */
if (a == 0x05F2) { /* YIDDISH YOD YOD */ if (a == 0x05F2u) { /* YIDDISH YOD YOD */
*ab = 0xFB1F; *ab = 0xFB1Fu;
found = true; found = true;
} else if (a == 0x05D0) { /* ALEF */ } else if (a == 0x05D0u) { /* ALEF */
*ab = 0xFB2E; *ab = 0xFB2Eu;
found = true; found = true;
} }
break; break;
case 0x05B8: /* QAMATS */ case 0x05B8u: /* QAMATS */
if (a == 0x05D0) { /* ALEF */ if (a == 0x05D0u) { /* ALEF */
*ab = 0xFB2F; *ab = 0xFB2Fu;
found = true; found = true;
} }
break; break;
case 0x05B9: /* HOLAM */ case 0x05B9u: /* HOLAM */
if (a == 0x05D5) { /* VAV */ if (a == 0x05D5u) { /* VAV */
*ab = 0xFB4B; *ab = 0xFB4Bu;
found = true; found = true;
} }
break; break;
case 0x05BC: /* DAGESH */ case 0x05BCu: /* DAGESH */
if (a >= 0x05D0 && a <= 0x05EA) { if (a >= 0x05D0u && a <= 0x05EAu) {
*ab = sDageshForms[a - 0x05D0]; *ab = sDageshForms[a - 0x05D0u];
found = (*ab != 0); found = (*ab != 0);
} else if (a == 0xFB2A) { /* SHIN WITH SHIN DOT */ } else if (a == 0xFB2Au) { /* SHIN WITH SHIN DOT */
*ab = 0xFB2C; *ab = 0xFB2Cu;
found = true; found = true;
} else if (a == 0xFB2B) { /* SHIN WITH SIN DOT */ } else if (a == 0xFB2Bu) { /* SHIN WITH SIN DOT */
*ab = 0xFB2D; *ab = 0xFB2Du;
found = true; found = true;
} }
break; break;
case 0x05BF: /* RAFE */ case 0x05BFu: /* RAFE */
switch (a) { switch (a) {
case 0x05D1: /* BET */ case 0x05D1u: /* BET */
*ab = 0xFB4C; *ab = 0xFB4Cu;
found = true; found = true;
break; break;
case 0x05DB: /* KAF */ case 0x05DBu: /* KAF */
*ab = 0xFB4D; *ab = 0xFB4Du;
found = true; found = true;
break; break;
case 0x05E4: /* PE */ case 0x05E4u: /* PE */
*ab = 0xFB4E; *ab = 0xFB4Eu;
found = true; found = true;
break; break;
} }
break; break;
case 0x05C1: /* SHIN DOT */ case 0x05C1u: /* SHIN DOT */
if (a == 0x05E9) { /* SHIN */ if (a == 0x05E9u) { /* SHIN */
*ab = 0xFB2A; *ab = 0xFB2Au;
found = true; found = true;
} else if (a == 0xFB49) { /* SHIN WITH DAGESH */ } else if (a == 0xFB49u) { /* SHIN WITH DAGESH */
*ab = 0xFB2C; *ab = 0xFB2Cu;
found = true; found = true;
} }
break; break;
case 0x05C2: /* SIN DOT */ case 0x05C2u: /* SIN DOT */
if (a == 0x05E9) { /* SHIN */ if (a == 0x05E9u) { /* SHIN */
*ab = 0xFB2B; *ab = 0xFB2Bu;
found = true; found = true;
} else if (a == 0xFB49) { /* SHIN WITH DAGESH */ } else if (a == 0xFB49u) { /* SHIN WITH DAGESH */
*ab = 0xFB2D; *ab = 0xFB2Du;
found = true; found = true;
} }
break; break;
@ -167,6 +167,6 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_hebrew =
NULL, /* decompose */ NULL, /* decompose */
compose_hebrew, compose_hebrew,
NULL, /* setup_masks */ NULL, /* setup_masks */
HB_OT_SHAPE_ZERO_WIDTH_MARKS_DEFAULT, HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
true, /* fallback_position */ true, /* fallback_position */
}; };

File diff suppressed because it is too large Load Diff

View File

@ -49,14 +49,14 @@ M = 7;
SM = 8; SM = 8;
VD = 9; VD = 9;
A = 10; A = 10;
NBSP = 11; PLACEHOLDER = 11;
DOTTEDCIRCLE = 12; DOTTEDCIRCLE = 12;
RS = 13; RS = 13;
Coeng = 14; Coeng = 14;
Repha = 15; Repha = 15;
Ra = 16; Ra = 16;
CM = 17; CM = 17;
Avag = 18; Symbol= 18;
CM2 = 31; CM2 = 31;
c = (C | Ra); # is_consonant c = (C | Ra); # is_consonant
@ -67,21 +67,20 @@ reph = (Ra H | Repha); # possible reph
cn = c.ZWJ?.n?; cn = c.ZWJ?.n?;
forced_rakar = ZWJ H ZWJ Ra; forced_rakar = ZWJ H ZWJ Ra;
avagraha = Avag.N?; symbol = Symbol.N?;
matra_group = z{0,3}.M.N?.(H | forced_rakar)?; matra_group = z{0,3}.M.N?.(H | forced_rakar)?;
syllable_tail2 = (SM.SM?.ZWNJ?)? (A.A?)? VD?; syllable_tail = (SM.SM?.ZWNJ?)? A{0,3}? VD{0,2};
syllable_tail = (Coeng (cn|V))? avagraha? syllable_tail2; place_holder = PLACEHOLDER | DOTTEDCIRCLE;
place_holder = NBSP | DOTTEDCIRCLE;
halant_group = (z?.h.(ZWJ.N?)?); halant_group = (z?.h.(ZWJ.N?)?);
final_halant_group = halant_group | h.ZWNJ; final_halant_group = halant_group | h.ZWNJ;
medial_group = CM?.CM2?; medial_group = CM?.CM2?;
halant_or_matra_group = (final_halant_group | (h.ZWJ)? matra_group{0,4}); halant_or_matra_group = (final_halant_group | (h.ZWJ)? matra_group{0,4}) (Coeng (cn|V))?;
consonant_syllable = Repha? (cn.halant_group){0,4} cn medial_group halant_or_matra_group syllable_tail; consonant_syllable = Repha? (cn.halant_group){0,4} cn medial_group halant_or_matra_group syllable_tail;
vowel_syllable = reph? V.n? (ZWJ | (halant_group.cn){0,4} medial_group halant_or_matra_group syllable_tail); vowel_syllable = reph? V.n? (ZWJ | (halant_group.cn){0,4} medial_group halant_or_matra_group syllable_tail);
standalone_cluster = reph? place_holder.n? (halant_group.cn){0,4} medial_group halant_or_matra_group syllable_tail; standalone_cluster = (Repha? PLACEHOLDER | reph? DOTTEDCIRCLE).n? (halant_group.cn){0,4} medial_group halant_or_matra_group syllable_tail;
avagraha_cluster = avagraha syllable_tail2; symbol_cluster = symbol syllable_tail;
broken_cluster = reph? n? (halant_group.cn){0,4} medial_group halant_or_matra_group syllable_tail; broken_cluster = reph? n? (halant_group.cn){0,4} medial_group halant_or_matra_group syllable_tail;
other = any; other = any;
@ -89,7 +88,7 @@ main := |*
consonant_syllable => { found_syllable (consonant_syllable); }; consonant_syllable => { found_syllable (consonant_syllable); };
vowel_syllable => { found_syllable (vowel_syllable); }; vowel_syllable => { found_syllable (vowel_syllable); };
standalone_cluster => { found_syllable (standalone_cluster); }; standalone_cluster => { found_syllable (standalone_cluster); };
avagraha_cluster => { found_syllable (avagraha_cluster); }; symbol_cluster => { found_syllable (symbol_cluster); };
broken_cluster => { found_syllable (broken_cluster); }; broken_cluster => { found_syllable (broken_cluster); };
other => { found_syllable (non_indic_cluster); }; other => { found_syllable (non_indic_cluster); };
*|; *|;

View File

@ -53,17 +53,29 @@ enum indic_category_t {
OT_SM = 8, OT_SM = 8,
OT_VD = 9, OT_VD = 9,
OT_A = 10, OT_A = 10,
OT_NBSP = 11, OT_PLACEHOLDER = 11,
OT_DOTTEDCIRCLE = 12, OT_DOTTEDCIRCLE = 12,
OT_RS = 13, /* Register Shifter, used in Khmer OT spec. */ OT_RS = 13, /* Register Shifter, used in Khmer OT spec. */
OT_Coeng = 14, /* Khmer-style Virama. */ OT_Coeng = 14, /* Khmer-style Virama. */
OT_Repha = 15, /* Atomically-encoded logical or visual repha. */ OT_Repha = 15, /* Atomically-encoded logical or visual repha. */
OT_Ra = 16, OT_Ra = 16,
OT_CM = 17, /* Consonant-Medial. */ OT_CM = 17, /* Consonant-Medial. */
OT_Avag = 18, /* Avagraha. */ OT_Symbol = 18, /* Avagraha, etc that take marks (SM,A,VD). */
OT_CM2 = 31 /* Consonant-Medial, second slot. */ OT_CM2 = 31 /* Consonant-Medial, second slot. */
}; };
#define MEDIAL_FLAGS (FLAG (OT_CM) | FLAG (OT_CM2))
/* Note:
*
* We treat Vowels and placeholders as if they were consonants. This is safe because Vowels
* cannot happen in a consonant syllable. The plus side however is, we can call the
* consonant syllable logic from the vowel syllable function and get it all right! */
#define CONSONANT_FLAGS (FLAG (OT_C) | FLAG (OT_Ra) | MEDIAL_FLAGS | FLAG (OT_V) | FLAG (OT_PLACEHOLDER) | FLAG (OT_DOTTEDCIRCLE))
#define JOINER_FLAGS (FLAG (OT_ZWJ) | FLAG (OT_ZWNJ))
#define HALANT_OR_COENG_FLAGS (FLAG (OT_H) | FLAG (OT_Coeng))
/* Visual positions in a syllable from left to right. */ /* Visual positions in a syllable from left to right. */
enum indic_position_t { enum indic_position_t {
POS_START, POS_START,
@ -93,57 +105,74 @@ enum indic_position_t {
/* Categories used in IndicSyllabicCategory.txt from UCD. */ /* Categories used in IndicSyllabicCategory.txt from UCD. */
enum indic_syllabic_category_t { enum indic_syllabic_category_t {
INDIC_SYLLABIC_CATEGORY_OTHER = OT_X, INDIC_SYLLABIC_CATEGORY_OTHER = OT_X,
INDIC_SYLLABIC_CATEGORY_AVAGRAHA = OT_Avag, INDIC_SYLLABIC_CATEGORY_AVAGRAHA = OT_Symbol,
INDIC_SYLLABIC_CATEGORY_BINDU = OT_SM, INDIC_SYLLABIC_CATEGORY_BINDU = OT_SM,
INDIC_SYLLABIC_CATEGORY_CONSONANT = OT_C, INDIC_SYLLABIC_CATEGORY_BRAHMI_JOINING_NUMBER = OT_PLACEHOLDER, /* TODO */
INDIC_SYLLABIC_CATEGORY_CONSONANT_DEAD = OT_C, INDIC_SYLLABIC_CATEGORY_CANTILLATION_MARK = OT_A,
INDIC_SYLLABIC_CATEGORY_CONSONANT_FINAL = OT_CM, INDIC_SYLLABIC_CATEGORY_CONSONANT = OT_C,
INDIC_SYLLABIC_CATEGORY_CONSONANT_HEAD_LETTER = OT_C, INDIC_SYLLABIC_CATEGORY_CONSONANT_DEAD = OT_C,
INDIC_SYLLABIC_CATEGORY_CONSONANT_MEDIAL = OT_CM, INDIC_SYLLABIC_CATEGORY_CONSONANT_FINAL = OT_CM,
INDIC_SYLLABIC_CATEGORY_CONSONANT_PLACEHOLDER = OT_NBSP, INDIC_SYLLABIC_CATEGORY_CONSONANT_HEAD_LETTER = OT_C,
INDIC_SYLLABIC_CATEGORY_CONSONANT_SUBJOINED = OT_CM, INDIC_SYLLABIC_CATEGORY_CONSONANT_MEDIAL = OT_CM,
INDIC_SYLLABIC_CATEGORY_CONSONANT_REPHA = OT_Repha, INDIC_SYLLABIC_CATEGORY_CONSONANT_PLACEHOLDER = OT_PLACEHOLDER,
INDIC_SYLLABIC_CATEGORY_MODIFYING_LETTER = OT_X, INDIC_SYLLABIC_CATEGORY_CONSONANT_PRECEDING_REPHA = OT_Repha,
INDIC_SYLLABIC_CATEGORY_NUKTA = OT_N, INDIC_SYLLABIC_CATEGORY_CONSONANT_SUBJOINED = OT_CM,
INDIC_SYLLABIC_CATEGORY_REGISTER_SHIFTER = OT_RS, INDIC_SYLLABIC_CATEGORY_CONSONANT_SUCCEEDING_REPHA = OT_N,
INDIC_SYLLABIC_CATEGORY_TONE_LETTER = OT_X, INDIC_SYLLABIC_CATEGORY_GEMINATION_MARK = OT_SM,
INDIC_SYLLABIC_CATEGORY_TONE_MARK = OT_N, INDIC_SYLLABIC_CATEGORY_INVISIBLE_STACKER = OT_H, /* TODO */
INDIC_SYLLABIC_CATEGORY_VIRAMA = OT_H, INDIC_SYLLABIC_CATEGORY_JOINER = OT_ZWJ,
INDIC_SYLLABIC_CATEGORY_VISARGA = OT_SM, INDIC_SYLLABIC_CATEGORY_MODIFYING_LETTER = OT_X,
INDIC_SYLLABIC_CATEGORY_VOWEL = OT_V, INDIC_SYLLABIC_CATEGORY_NON_JOINER = OT_ZWNJ,
INDIC_SYLLABIC_CATEGORY_VOWEL_DEPENDENT = OT_M, INDIC_SYLLABIC_CATEGORY_NUKTA = OT_N,
INDIC_SYLLABIC_CATEGORY_VOWEL_INDEPENDENT = OT_V INDIC_SYLLABIC_CATEGORY_NUMBER = OT_PLACEHOLDER,
INDIC_SYLLABIC_CATEGORY_NUMBER_JOINER = OT_PLACEHOLDER, /* TODO */
INDIC_SYLLABIC_CATEGORY_PURE_KILLER = OT_H, /* TODO */
INDIC_SYLLABIC_CATEGORY_REGISTER_SHIFTER = OT_RS,
INDIC_SYLLABIC_CATEGORY_TONE_LETTER = OT_X,
INDIC_SYLLABIC_CATEGORY_TONE_MARK = OT_N,
INDIC_SYLLABIC_CATEGORY_VIRAMA = OT_H,
INDIC_SYLLABIC_CATEGORY_VISARGA = OT_SM,
INDIC_SYLLABIC_CATEGORY_VOWEL = OT_V,
INDIC_SYLLABIC_CATEGORY_VOWEL_DEPENDENT = OT_M,
INDIC_SYLLABIC_CATEGORY_VOWEL_INDEPENDENT = OT_V
}; };
/* Categories used in IndicSMatraCategory.txt from UCD */ /* Categories used in IndicSMatraCategory.txt from UCD */
enum indic_matra_category_t { enum indic_matra_category_t {
INDIC_MATRA_CATEGORY_NOT_APPLICABLE = POS_END, INDIC_MATRA_CATEGORY_NOT_APPLICABLE = POS_END,
INDIC_MATRA_CATEGORY_LEFT = POS_PRE_C, INDIC_MATRA_CATEGORY_LEFT = POS_PRE_C,
INDIC_MATRA_CATEGORY_TOP = POS_ABOVE_C, INDIC_MATRA_CATEGORY_TOP = POS_ABOVE_C,
INDIC_MATRA_CATEGORY_BOTTOM = POS_BELOW_C, INDIC_MATRA_CATEGORY_BOTTOM = POS_BELOW_C,
INDIC_MATRA_CATEGORY_RIGHT = POS_POST_C, INDIC_MATRA_CATEGORY_RIGHT = POS_POST_C,
/* These should resolve to the position of the last part of the split sequence. */ /* These should resolve to the position of the last part of the split sequence. */
INDIC_MATRA_CATEGORY_BOTTOM_AND_RIGHT = INDIC_MATRA_CATEGORY_RIGHT, INDIC_MATRA_CATEGORY_BOTTOM_AND_RIGHT = INDIC_MATRA_CATEGORY_RIGHT,
INDIC_MATRA_CATEGORY_LEFT_AND_RIGHT = INDIC_MATRA_CATEGORY_RIGHT, INDIC_MATRA_CATEGORY_LEFT_AND_RIGHT = INDIC_MATRA_CATEGORY_RIGHT,
INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM = INDIC_MATRA_CATEGORY_BOTTOM, INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM = INDIC_MATRA_CATEGORY_BOTTOM,
INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM_AND_RIGHT = INDIC_MATRA_CATEGORY_RIGHT, INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM_AND_RIGHT = INDIC_MATRA_CATEGORY_RIGHT,
INDIC_MATRA_CATEGORY_TOP_AND_LEFT = INDIC_MATRA_CATEGORY_TOP, INDIC_MATRA_CATEGORY_TOP_AND_LEFT = INDIC_MATRA_CATEGORY_TOP,
INDIC_MATRA_CATEGORY_TOP_AND_LEFT_AND_RIGHT = INDIC_MATRA_CATEGORY_RIGHT, INDIC_MATRA_CATEGORY_TOP_AND_LEFT_AND_RIGHT = INDIC_MATRA_CATEGORY_RIGHT,
INDIC_MATRA_CATEGORY_TOP_AND_RIGHT = INDIC_MATRA_CATEGORY_RIGHT, INDIC_MATRA_CATEGORY_TOP_AND_RIGHT = INDIC_MATRA_CATEGORY_RIGHT,
INDIC_MATRA_CATEGORY_INVISIBLE = INDIC_MATRA_CATEGORY_NOT_APPLICABLE, INDIC_MATRA_CATEGORY_OVERSTRUCK = POS_AFTER_MAIN,
INDIC_MATRA_CATEGORY_OVERSTRUCK = POS_AFTER_MAIN, INDIC_MATRA_CATEGORY_VISUAL_ORDER_LEFT = POS_PRE_M
INDIC_MATRA_CATEGORY_VISUAL_ORDER_LEFT = POS_PRE_M
}; };
/* Note: We use ASSERT_STATIC_EXPR_ZERO() instead of ASSERT_STATIC_EXPR() and the comma operation /* Note: We use ASSERT_STATIC_EXPR_ZERO() instead of ASSERT_STATIC_EXPR() and the comma operation
* because gcc fails to optimize the latter and fills the table in at runtime. */ * because gcc fails to optimize the latter and fills the table in at runtime. */
#define INDIC_COMBINE_CATEGORIES(S,M) \ #define INDIC_COMBINE_CATEGORIES(S,M) \
(ASSERT_STATIC_EXPR_ZERO (M == INDIC_MATRA_CATEGORY_NOT_APPLICABLE || (S == INDIC_SYLLABIC_CATEGORY_VIRAMA || S == INDIC_SYLLABIC_CATEGORY_VOWEL_DEPENDENT)) + \ (ASSERT_STATIC_EXPR_ZERO (M == INDIC_MATRA_CATEGORY_NOT_APPLICABLE || \
( \
S == INDIC_SYLLABIC_CATEGORY_CONSONANT_MEDIAL || \
S == INDIC_SYLLABIC_CATEGORY_GEMINATION_MARK || \
S == INDIC_SYLLABIC_CATEGORY_REGISTER_SHIFTER || \
S == INDIC_SYLLABIC_CATEGORY_CONSONANT_SUCCEEDING_REPHA || \
S == INDIC_SYLLABIC_CATEGORY_VIRAMA || \
S == INDIC_SYLLABIC_CATEGORY_VOWEL_DEPENDENT || \
false)) + \
ASSERT_STATIC_EXPR_ZERO (S < 255 && M < 255) + \ ASSERT_STATIC_EXPR_ZERO (S < 255 && M < 255) + \
((M << 8) | S)) ((M << 8) | S))

File diff suppressed because it is too large Load Diff

View File

@ -1,872 +0,0 @@
/* == Start of generated table == */
/*
* The following table is generated by running:
*
* ./gen-indic-table.py IndicSyllabicCategory.txt IndicMatraCategory.txt Blocks.txt
*
* on files with these headers:
*
* # IndicSyllabicCategory-6.2.0.txt
* # Date: 2012-05-15, 21:12:00 GMT [KW]
* # IndicMatraCategory-6.2.0.txt
* # Date: 2012-05-15, 21:10:00 GMT [KW]
* # Blocks-6.2.0.txt
* # Date: 2012-05-14, 22:42:00 GMT [KW, LI]
*/
#ifndef HB_OT_SHAPE_COMPLEX_INDIC_TABLE_HH
#define HB_OT_SHAPE_COMPLEX_INDIC_TABLE_HH
#define ISC_A INDIC_SYLLABIC_CATEGORY_AVAGRAHA /* 11 chars; Avagraha */
#define ISC_Bi INDIC_SYLLABIC_CATEGORY_BINDU /* 34 chars; Bindu */
#define ISC_C INDIC_SYLLABIC_CATEGORY_CONSONANT /* 123 chars; Consonant */
#define ISC_CD INDIC_SYLLABIC_CATEGORY_CONSONANT_DEAD /* 2 chars; Consonant_Dead */
#define ISC_CF INDIC_SYLLABIC_CATEGORY_CONSONANT_FINAL /* 17 chars; Consonant_Final */
#define ISC_CHL INDIC_SYLLABIC_CATEGORY_CONSONANT_HEAD_LETTER /* 1 chars; Consonant_Head_Letter */
#define ISC_CM INDIC_SYLLABIC_CATEGORY_CONSONANT_MEDIAL /* 12 chars; Consonant_Medial */
#define ISC_CP INDIC_SYLLABIC_CATEGORY_CONSONANT_PLACEHOLDER /* 4 chars; Consonant_Placeholder */
#define ISC_CR INDIC_SYLLABIC_CATEGORY_CONSONANT_REPHA /* 5 chars; Consonant_Repha */
#define ISC_CS INDIC_SYLLABIC_CATEGORY_CONSONANT_SUBJOINED /* 10 chars; Consonant_Subjoined */
#define ISC_ML INDIC_SYLLABIC_CATEGORY_MODIFYING_LETTER /* 1 chars; Modifying_Letter */
#define ISC_N INDIC_SYLLABIC_CATEGORY_NUKTA /* 12 chars; Nukta */
#define ISC_x INDIC_SYLLABIC_CATEGORY_OTHER /* 1 chars; Other */
#define ISC_RS INDIC_SYLLABIC_CATEGORY_REGISTER_SHIFTER /* 1 chars; Register_Shifter */
#define ISC_TL INDIC_SYLLABIC_CATEGORY_TONE_LETTER /* 3 chars; Tone_Letter */
#define ISC_TM INDIC_SYLLABIC_CATEGORY_TONE_MARK /* 16 chars; Tone_Mark */
#define ISC_V INDIC_SYLLABIC_CATEGORY_VIRAMA /* 34 chars; Virama */
#define ISC_Vs INDIC_SYLLABIC_CATEGORY_VISARGA /* 25 chars; Visarga */
#define ISC_Vo INDIC_SYLLABIC_CATEGORY_VOWEL /* 5 chars; Vowel */
#define ISC_M INDIC_SYLLABIC_CATEGORY_VOWEL_DEPENDENT /* 165 chars; Vowel_Dependent */
#define ISC_VI INDIC_SYLLABIC_CATEGORY_VOWEL_INDEPENDENT /* 59 chars; Vowel_Independent */
#define IMC_B INDIC_MATRA_CATEGORY_BOTTOM /* 65 chars; Bottom */
#define IMC_BR INDIC_MATRA_CATEGORY_BOTTOM_AND_RIGHT /* 2 chars; Bottom_And_Right */
#define IMC_I INDIC_MATRA_CATEGORY_INVISIBLE /* 6 chars; Invisible */
#define IMC_L INDIC_MATRA_CATEGORY_LEFT /* 30 chars; Left */
#define IMC_LR INDIC_MATRA_CATEGORY_LEFT_AND_RIGHT /* 8 chars; Left_And_Right */
#define IMC_x INDIC_MATRA_CATEGORY_NOT_APPLICABLE /* 1 chars; Not_Applicable */
#define IMC_O INDIC_MATRA_CATEGORY_OVERSTRUCK /* 2 chars; Overstruck */
#define IMC_R INDIC_MATRA_CATEGORY_RIGHT /* 75 chars; Right */
#define IMC_T INDIC_MATRA_CATEGORY_TOP /* 83 chars; Top */
#define IMC_TB INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM /* 6 chars; Top_And_Bottom */
#define IMC_TBR INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM_AND_RIGHT /* 1 chars; Top_And_Bottom_And_Right */
#define IMC_TL INDIC_MATRA_CATEGORY_TOP_AND_LEFT /* 4 chars; Top_And_Left */
#define IMC_TLR INDIC_MATRA_CATEGORY_TOP_AND_LEFT_AND_RIGHT /* 2 chars; Top_And_Left_And_Right */
#define IMC_TR INDIC_MATRA_CATEGORY_TOP_AND_RIGHT /* 8 chars; Top_And_Right */
#define IMC_VOL INDIC_MATRA_CATEGORY_VISUAL_ORDER_LEFT /* 5 chars; Visual_Order_Left */
#define _(S,M) INDIC_COMBINE_CATEGORIES (ISC_##S, IMC_##M)
static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {
#define indic_offset_0x0900 0
/* Devanagari (0900..097F) */
/* 0900 */ _(Bi,x), _(Bi,x), _(Bi,x), _(Vs,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
/* 0908 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
/* 0910 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x),
/* 0918 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0920 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0928 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0930 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0938 */ _(C,x), _(C,x), _(M,T), _(M,R), _(N,x), _(A,x), _(M,R), _(M,L),
/* 0940 */ _(M,R), _(M,B), _(M,B), _(M,B), _(M,B), _(M,T), _(M,T), _(M,T),
/* 0948 */ _(M,T), _(M,R), _(M,R), _(M,R), _(M,R), _(V,B), _(M,L), _(M,R),
/* 0950 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(M,T), _(M,B), _(M,B),
/* 0958 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0960 */ _(VI,x), _(VI,x), _(M,B), _(M,B), _(x,x), _(x,x), _(x,x), _(x,x),
/* 0968 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 0970 */ _(x,x), _(x,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
/* 0978 */ _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* Bengali (0980..09FF) */
/* 0980 */ _(x,x), _(Bi,x), _(Bi,x), _(Vs,x), _(x,x), _(VI,x), _(VI,x), _(VI,x),
/* 0988 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(x,x), _(x,x), _(VI,x),
/* 0990 */ _(VI,x), _(x,x), _(x,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x),
/* 0998 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 09A0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 09A8 */ _(C,x), _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 09B0 */ _(C,x), _(x,x), _(C,x), _(x,x), _(x,x), _(x,x), _(C,x), _(C,x),
/* 09B8 */ _(C,x), _(C,x), _(x,x), _(x,x), _(N,x), _(A,x), _(M,R), _(M,L),
/* 09C0 */ _(M,R), _(M,B), _(M,B), _(M,B), _(M,B), _(x,x), _(x,x), _(M,L),
/* 09C8 */ _(M,L), _(x,x), _(x,x), _(M,LR), _(M,LR), _(V,B), _(CD,x), _(x,x),
/* 09D0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(M,R),
/* 09D8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(C,x), _(C,x), _(x,x), _(C,x),
/* 09E0 */ _(VI,x), _(VI,x), _(M,B), _(M,B), _(x,x), _(x,x), _(x,x), _(x,x),
/* 09E8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 09F0 */ _(C,x), _(C,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 09F8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* Gurmukhi (0A00..0A7F) */
/* 0A00 */ _(x,x), _(Bi,x), _(Bi,x), _(Vs,x), _(x,x), _(VI,x), _(VI,x), _(VI,x),
/* 0A08 */ _(VI,x), _(VI,x), _(VI,x), _(x,x), _(x,x), _(x,x), _(x,x), _(VI,x),
/* 0A10 */ _(VI,x), _(x,x), _(x,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x),
/* 0A18 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0A20 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0A28 */ _(C,x), _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0A30 */ _(C,x), _(x,x), _(C,x), _(C,x), _(x,x), _(C,x), _(C,x), _(x,x),
/* 0A38 */ _(C,x), _(C,x), _(x,x), _(x,x), _(N,x), _(x,x), _(M,R), _(M,L),
/* 0A40 */ _(M,R), _(M,B), _(M,B), _(x,x), _(x,x), _(x,x), _(x,x), _(M,T),
/* 0A48 */ _(M,T), _(x,x), _(x,x), _(M,T), _(M,T), _(V,B), _(x,x), _(x,x),
/* 0A50 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 0A58 */ _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(x,x), _(C,x), _(x,x),
/* 0A60 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 0A68 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 0A70 */ _(Bi,x), _(x,x), _(CP,x), _(CP,x), _(x,x), _(CM,x), _(x,x), _(x,x),
/* 0A78 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* Gujarati (0A80..0AFF) */
/* 0A80 */ _(x,x), _(Bi,x), _(Bi,x), _(Vs,x), _(x,x), _(VI,x), _(VI,x), _(VI,x),
/* 0A88 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(x,x), _(VI,x),
/* 0A90 */ _(VI,x), _(VI,x), _(x,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x),
/* 0A98 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0AA0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0AA8 */ _(C,x), _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0AB0 */ _(C,x), _(x,x), _(C,x), _(C,x), _(x,x), _(C,x), _(C,x), _(C,x),
/* 0AB8 */ _(C,x), _(C,x), _(x,x), _(x,x), _(N,x), _(A,x), _(M,R), _(M,L),
/* 0AC0 */ _(M,R), _(M,B), _(M,B), _(M,B), _(M,B), _(M,T), _(x,x), _(M,T),
/* 0AC8 */ _(M,T), _(M,TR), _(x,x), _(M,R), _(M,R), _(V,B), _(x,x), _(x,x),
/* 0AD0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 0AD8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 0AE0 */ _(VI,x), _(VI,x), _(M,B), _(M,B), _(x,x), _(x,x), _(x,x), _(x,x),
/* 0AE8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 0AF0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 0AF8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* Oriya (0B00..0B7F) */
/* 0B00 */ _(x,x), _(Bi,x), _(Bi,x), _(Vs,x), _(x,x), _(VI,x), _(VI,x), _(VI,x),
/* 0B08 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(x,x), _(x,x), _(VI,x),
/* 0B10 */ _(VI,x), _(x,x), _(x,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x),
/* 0B18 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0B20 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0B28 */ _(C,x), _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0B30 */ _(C,x), _(x,x), _(C,x), _(C,x), _(x,x), _(C,x), _(C,x), _(C,x),
/* 0B38 */ _(C,x), _(C,x), _(x,x), _(x,x), _(N,x), _(A,x), _(M,R), _(M,T),
/* 0B40 */ _(M,R), _(M,B), _(M,B), _(M,B), _(M,B), _(x,x), _(x,x), _(M,L),
/* 0B48 */ _(M,TL), _(x,x), _(x,x), _(M,LR),_(M,TLR), _(V,B), _(x,x), _(x,x),
/* 0B50 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(M,T), _(M,TR),
/* 0B58 */ _(x,x), _(x,x), _(x,x), _(x,x), _(C,x), _(C,x), _(x,x), _(C,x),
/* 0B60 */ _(VI,x), _(VI,x), _(M,B), _(M,B), _(x,x), _(x,x), _(x,x), _(x,x),
/* 0B68 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 0B70 */ _(x,x), _(C,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 0B78 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* Tamil (0B80..0BFF) */
/* 0B80 */ _(x,x), _(x,x), _(Bi,x), _(ML,x), _(x,x), _(VI,x), _(VI,x), _(VI,x),
/* 0B88 */ _(VI,x), _(VI,x), _(VI,x), _(x,x), _(x,x), _(x,x), _(VI,x), _(VI,x),
/* 0B90 */ _(VI,x), _(x,x), _(VI,x), _(VI,x), _(VI,x), _(C,x), _(x,x), _(x,x),
/* 0B98 */ _(x,x), _(C,x), _(C,x), _(x,x), _(C,x), _(x,x), _(C,x), _(C,x),
/* 0BA0 */ _(x,x), _(x,x), _(x,x), _(C,x), _(C,x), _(x,x), _(x,x), _(x,x),
/* 0BA8 */ _(C,x), _(C,x), _(C,x), _(x,x), _(x,x), _(x,x), _(C,x), _(C,x),
/* 0BB0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0BB8 */ _(C,x), _(C,x), _(x,x), _(x,x), _(x,x), _(x,x), _(M,R), _(M,R),
/* 0BC0 */ _(M,T), _(M,B), _(M,B), _(x,x), _(x,x), _(x,x), _(M,L), _(M,L),
/* 0BC8 */ _(M,L), _(x,x), _(M,LR), _(M,LR), _(M,LR), _(V,T), _(x,x), _(x,x),
/* 0BD0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(M,R),
/* 0BD8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 0BE0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 0BE8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 0BF0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 0BF8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* Telugu (0C00..0C7F) */
/* 0C00 */ _(x,x), _(Bi,x), _(Bi,x), _(Vs,x), _(x,x), _(VI,x), _(VI,x), _(VI,x),
/* 0C08 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(x,x), _(VI,x), _(VI,x),
/* 0C10 */ _(VI,x), _(x,x), _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x),
/* 0C18 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0C20 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0C28 */ _(C,x), _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0C30 */ _(C,x), _(C,x), _(C,x), _(C,x), _(x,x), _(C,x), _(C,x), _(C,x),
/* 0C38 */ _(C,x), _(C,x), _(x,x), _(x,x), _(x,x), _(A,x), _(M,T), _(M,T),
/* 0C40 */ _(M,T), _(M,R), _(M,R), _(M,R), _(M,R), _(x,x), _(M,T), _(M,T),
/* 0C48 */ _(M,TB), _(x,x), _(M,T), _(M,T), _(M,T), _(V,T), _(x,x), _(x,x),
/* 0C50 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(M,T), _(M,B), _(x,x),
/* 0C58 */ _(C,x), _(C,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 0C60 */ _(VI,x), _(VI,x), _(M,B), _(M,B), _(x,x), _(x,x), _(x,x), _(x,x),
/* 0C68 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 0C70 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 0C78 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* Kannada (0C80..0CFF) */
/* 0C80 */ _(x,x), _(x,x), _(Bi,x), _(Vs,x), _(x,x), _(VI,x), _(VI,x), _(VI,x),
/* 0C88 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(x,x), _(VI,x), _(VI,x),
/* 0C90 */ _(VI,x), _(x,x), _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x),
/* 0C98 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0CA0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0CA8 */ _(C,x), _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0CB0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(x,x), _(C,x), _(C,x), _(C,x),
/* 0CB8 */ _(C,x), _(C,x), _(x,x), _(x,x), _(N,x), _(A,x), _(M,R), _(M,T),
/* 0CC0 */ _(M,TR), _(M,R), _(M,R), _(M,R), _(M,R), _(x,x), _(M,T), _(M,TR),
/* 0CC8 */ _(M,TR), _(x,x), _(M,TR), _(M,TR), _(M,T), _(V,T), _(x,x), _(x,x),
/* 0CD0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(M,R), _(M,R), _(x,x),
/* 0CD8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(C,x), _(x,x),
/* 0CE0 */ _(VI,x), _(VI,x), _(M,B), _(M,B), _(x,x), _(x,x), _(x,x), _(x,x),
/* 0CE8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 0CF0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 0CF8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* Malayalam (0D00..0D7F) */
/* 0D00 */ _(x,x), _(x,x), _(Bi,x), _(Vs,x), _(x,x), _(VI,x), _(VI,x), _(VI,x),
/* 0D08 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(x,x), _(VI,x), _(VI,x),
/* 0D10 */ _(VI,x), _(x,x), _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x),
/* 0D18 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0D20 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0D28 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0D30 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0D38 */ _(C,x), _(C,x), _(C,x), _(x,x), _(x,x), _(A,x), _(M,R), _(M,R),
/* 0D40 */ _(M,R), _(M,R), _(M,R), _(M,B), _(M,B), _(x,x), _(M,L), _(M,L),
/* 0D48 */ _(M,L), _(x,x), _(M,LR), _(M,LR), _(M,LR), _(V,T), _(CR,x), _(x,x),
/* 0D50 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(M,R),
/* 0D58 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 0D60 */ _(VI,x), _(VI,x), _(M,B), _(M,B), _(x,x), _(x,x), _(x,x), _(x,x),
/* 0D68 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 0D70 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 0D78 */ _(x,x), _(x,x), _(CD,x), _(CD,x), _(CD,x), _(CD,x), _(CD,x), _(CD,x),
/* Sinhala (0D80..0DFF) */
/* 0D80 */ _(x,x), _(x,x), _(Bi,x), _(Vs,x), _(x,x), _(VI,x), _(VI,x), _(VI,x),
/* 0D88 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
/* 0D90 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(x,x),
/* 0D98 */ _(x,x), _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0DA0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0DA8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0DB0 */ _(C,x), _(C,x), _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0DB8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(x,x), _(C,x), _(x,x), _(x,x),
/* 0DC0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(x,x),
/* 0DC8 */ _(x,x), _(x,x), _(V,T), _(x,x), _(x,x), _(x,x), _(x,x), _(M,R),
/* 0DD0 */ _(M,R), _(M,R), _(M,T), _(M,T), _(M,B), _(x,x), _(M,B), _(x,x),
/* 0DD8 */ _(M,R), _(M,L), _(M,TL), _(M,L), _(M,LR), _(M,LR), _(M,LR), _(M,R),
/* 0DE0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 0DE8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 0DF0 */ _(x,x), _(x,x), _(M,R), _(M,R), _(x,x), _(x,x), _(x,x), _(x,x),
/* 0DF8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* Thai (0E00..0E7F) */
/* 0E00 */ _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0E08 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0E10 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0E18 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0E20 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0E28 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(x,x),
/* 0E30 */ _(M,R), _(M,T), _(M,R), _(M,R), _(M,T), _(M,T), _(M,T), _(M,T),
/* 0E38 */ _(M,B), _(M,B), _(V,B), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 0E40 */_(M,VOL),_(M,VOL),_(M,VOL),_(M,VOL),_(M,VOL), _(M,R), _(x,x), _(M,T),
/* 0E48 */ _(TM,x), _(TM,x), _(TM,x), _(TM,x), _(x,x), _(Bi,x), _(V,T), _(x,x),
/* 0E50 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 0E58 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 0E60 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 0E68 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 0E70 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 0E78 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* Lao (0E80..0EFF) */
/* 0E80 */ _(x,x), _(C,x), _(C,x), _(x,x), _(C,x), _(x,x), _(x,x), _(C,x),
/* 0E88 */ _(C,x), _(x,x), _(C,x), _(x,x), _(x,x), _(C,x), _(x,x), _(x,x),
/* 0E90 */ _(x,x), _(x,x), _(x,x), _(x,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0E98 */ _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0EA0 */ _(x,x), _(C,x), _(C,x), _(C,x), _(x,x), _(C,x), _(x,x), _(C,x),
/* 0EA8 */ _(x,x), _(x,x), _(C,x), _(C,x), _(x,x), _(C,x), _(C,x), _(x,x),
/* 0EB0 */ _(M,R), _(M,T), _(M,R), _(M,R), _(M,T), _(M,T), _(M,T), _(M,T),
/* 0EB8 */ _(M,B), _(M,B), _(x,x), _(M,T), _(CM,x), _(CM,x), _(x,x), _(x,x),
/* 0EC0 */_(M,VOL),_(M,VOL),_(M,VOL),_(M,VOL),_(M,VOL), _(x,x), _(x,x), _(x,x),
/* 0EC8 */ _(TM,x), _(TM,x), _(TM,x), _(TM,x), _(x,x), _(Bi,x), _(x,x), _(x,x),
/* 0ED0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 0ED8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(C,x), _(C,x), _(x,x), _(x,x),
/* 0EE0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 0EE8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 0EF0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 0EF8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* Tibetan (0F00..0FFF) */
/* 0F00 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 0F08 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 0F10 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 0F18 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 0F20 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 0F28 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 0F30 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 0F38 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 0F40 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0F48 */ _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0F50 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0F58 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0F60 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0F68 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(x,x), _(x,x), _(x,x),
/* 0F70 */ _(x,x), _(M,B), _(M,T), _(M,TB), _(M,B), _(M,B), _(M,TB), _(M,TB),
/* 0F78 */ _(M,TB), _(M,TB), _(M,T), _(M,T), _(M,T), _(M,T), _(Bi,x), _(Vs,x),
/* 0F80 */ _(M,T), _(M,TB), _(Bi,x), _(Bi,x), _(V,B), _(A,x), _(x,x), _(x,x),
/* 0F88 */_(CHL,x),_(CHL,x),_(CHL,x),_(CHL,x),_(CHL,x), _(CS,x), _(CS,x), _(CS,x),
/* 0F90 */ _(CS,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x),
/* 0F98 */ _(x,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x),
/* 0FA0 */ _(CS,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x),
/* 0FA8 */ _(CS,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x),
/* 0FB0 */ _(CS,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x),
/* 0FB8 */ _(CS,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x), _(x,x), _(x,x), _(x,x),
/* 0FC0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 0FC8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 0FD0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 0FD8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 0FE0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 0FE8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 0FF0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 0FF8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* Myanmar (1000..109F) */
/* 1000 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 1008 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 1010 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 1018 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 1020 */ _(C,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
/* 1028 */ _(VI,x), _(VI,x), _(VI,x), _(M,R), _(M,R), _(M,T), _(M,T), _(M,B),
/* 1030 */ _(M,B), _(M,L), _(M,T), _(M,T), _(M,T), _(M,T), _(Bi,x), _(TM,x),
/* 1038 */ _(Vs,x), _(V,I), _(V,T), _(CM,x), _(CM,x), _(CM,x), _(CM,x), _(C,x),
/* 1040 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 1048 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 1050 */ _(C,x), _(C,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(M,R), _(M,R),
/* 1058 */ _(M,B), _(M,B), _(C,x), _(C,x), _(C,x), _(C,x), _(CM,x), _(CM,x),
/* 1060 */ _(CM,x), _(C,x), _(M,R), _(TM,x), _(TM,x), _(C,x), _(C,x), _(M,R),
/* 1068 */ _(M,R), _(TM,x), _(TM,x), _(TM,x), _(TM,x), _(TM,x), _(C,x), _(C,x),
/* 1070 */ _(C,x), _(M,T), _(M,T), _(M,T), _(M,T), _(C,x), _(C,x), _(C,x),
/* 1078 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 1080 */ _(C,x), _(C,x), _(CM,x), _(M,R), _(M,L), _(M,T), _(M,T), _(TM,x),
/* 1088 */ _(TM,x), _(TM,x), _(TM,x), _(TM,x), _(TM,x), _(TM,x), _(C,x), _(TM,x),
/* 1090 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 1098 */ _(x,x), _(x,x), _(TM,x), _(TM,x), _(M,R), _(M,T), _(x,x), _(x,x),
#define indic_offset_0x1700 1952
/* Tagalog (1700..171F) */
/* 1700 */ _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 1708 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(x,x), _(C,x), _(C,x),
/* 1710 */ _(C,x), _(C,x), _(M,T), _(M,B), _(V,B), _(x,x), _(x,x), _(x,x),
/* 1718 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* Hanunoo (1720..173F) */
/* 1720 */ _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 1728 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 1730 */ _(C,x), _(C,x), _(M,T), _(M,B), _(V,B), _(x,x), _(x,x), _(x,x),
/* 1738 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* Buhid (1740..175F) */
/* 1740 */ _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 1748 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 1750 */ _(C,x), _(C,x), _(M,T), _(M,B), _(x,x), _(x,x), _(x,x), _(x,x),
/* 1758 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* Tagbanwa (1760..177F) */
/* 1760 */ _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 1768 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(x,x), _(C,x), _(C,x),
/* 1770 */ _(C,x), _(x,x), _(M,T), _(M,B), _(x,x), _(x,x), _(x,x), _(x,x),
/* 1778 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* Khmer (1780..17FF) */
/* 1780 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 1788 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 1790 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 1798 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 17A0 */ _(C,x), _(C,x), _(C,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
/* 17A8 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
/* 17B0 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(x,x), _(x,x), _(M,R), _(M,T),
/* 17B8 */ _(M,T), _(M,T), _(M,T), _(M,B), _(M,B), _(M,B), _(M,TL),_(M,TLR),
/* 17C0 */ _(M,LR), _(M,L), _(M,L), _(M,L), _(M,LR), _(M,LR), _(Bi,x), _(Vs,x),
/* 17C8 */ _(M,R), _(RS,x), _(RS,x), _(x,x), _(CR,x), _(x,x), _(x,x), _(x,x),
/* 17D0 */ _(x,x), _(V,T), _(V,I), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 17D8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(A,x), _(x,x), _(x,x), _(x,x),
/* 17E0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 17E8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 17F0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 17F8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
#define indic_offset_0x1900 2208
/* Limbu (1900..194F) */
/* 1900 */ _(CP,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 1908 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 1910 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 1918 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(x,x), _(x,x), _(x,x),
/* 1920 */ _(M,T), _(M,T), _(M,B), _(M,R), _(M,R), _(M,TR), _(M,TR), _(M,T),
/* 1928 */ _(M,T), _(CS,x), _(CS,x), _(CS,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 1930 */ _(CF,x), _(CF,x), _(Bi,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x),
/* 1938 */ _(CF,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 1940 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 1948 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* Tai Le (1950..197F) */
/* 1950 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 1958 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 1960 */ _(C,x), _(C,x), _(C,x), _(Vo,x), _(Vo,x), _(Vo,x), _(Vo,x), _(Vo,x),
/* 1968 */ _(Vo,x), _(Vo,x), _(Vo,x), _(Vo,x), _(Vo,x), _(Vo,x), _(x,x), _(x,x),
/* 1970 */ _(TL,x), _(TL,x), _(TL,x), _(TL,x), _(TL,x), _(x,x), _(x,x), _(x,x),
/* 1978 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* New Tai Lue (1980..19DF) */
/* 1980 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 1988 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 1990 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 1998 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 19A0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 19A8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 19B0 */ _(M,R), _(M,R), _(M,R), _(M,R), _(M,R), _(M,L), _(M,L), _(M,L),
/* 19B8 */ _(M,R), _(M,R), _(M,L), _(M,R), _(M,R), _(M,R), _(M,R), _(M,R),
/* 19C0 */ _(M,R), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x),
/* 19C8 */ _(TM,x), _(TM,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 19D0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 19D8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* FILLER (19E0..19FF) */
/* 19E0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 19E8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 19F0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 19F8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* Buginese (1A00..1A1F) */
/* 1A00 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 1A08 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 1A10 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(M,T),
/* 1A18 */ _(M,B), _(M,L), _(M,R), _(M,L), _(x,x), _(x,x), _(x,x), _(x,x),
/* Tai Tham (1A20..1AAF) */
/* 1A20 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 1A28 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 1A30 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 1A38 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 1A40 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 1A48 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(VI,x), _(VI,x), _(VI,x),
/* 1A50 */ _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(CM,x), _(CM,x), _(CF,x),
/* 1A58 */ _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(x,x),
/* 1A60 */ _(V,I), _(M,R), _(M,T), _(M,R), _(M,R), _(M,T), _(M,T), _(M,T),
/* 1A68 */ _(M,T), _(M,B), _(M,B), _(M,T), _(M,B), _(M,R), _(M,L), _(M,L),
/* 1A70 */ _(M,L), _(M,L), _(M,L), _(M,T), _(M,T), _(TM,x), _(TM,x), _(TM,x),
/* 1A78 */ _(TM,x), _(TM,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 1A80 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 1A88 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 1A90 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 1A98 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 1AA0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 1AA8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
#define indic_offset_0x1b00 2640
/* Balinese (1B00..1B7F) */
/* 1B00 */ _(Bi,x), _(Bi,x), _(Bi,x), _(CR,x), _(Vs,x), _(VI,x), _(VI,x), _(VI,x),
/* 1B08 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
/* 1B10 */ _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 1B18 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 1B20 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 1B28 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 1B30 */ _(C,x), _(C,x), _(C,x), _(C,x), _(N,x), _(M,R), _(M,T), _(M,T),
/* 1B38 */ _(M,B), _(M,B), _(M,B), _(M,BR), _(M,TB),_(M,TBR), _(M,L), _(M,L),
/* 1B40 */ _(M,LR), _(M,LR), _(M,T), _(M,TR), _(V,R), _(C,x), _(C,x), _(C,x),
/* 1B48 */ _(C,x), _(C,x), _(C,x), _(C,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 1B50 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 1B58 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 1B60 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 1B68 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 1B70 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 1B78 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* Sundanese (1B80..1BBF) */
/* 1B80 */ _(Bi,x), _(CR,x), _(Vs,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
/* 1B88 */ _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 1B90 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 1B98 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 1BA0 */ _(C,x), _(CS,x), _(CS,x), _(CS,x), _(M,T), _(M,B), _(M,L), _(M,R),
/* 1BA8 */ _(M,T), _(M,T), _(V,R), _(V,x), _(CS,x), _(CS,x), _(C,x), _(C,x),
/* 1BB0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 1BB8 */ _(x,x), _(x,x), _(A,x), _(C,x), _(C,x), _(C,x), _(CF,x), _(CF,x),
/* Batak (1BC0..1BFF) */
/* 1BC0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 1BC8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 1BD0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 1BD8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 1BE0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(VI,x), _(VI,x), _(N,x), _(M,x),
/* 1BE8 */ _(M,x), _(M,x), _(M,x), _(M,x), _(M,x), _(M,x), _(M,x), _(M,x),
/* 1BF0 */ _(CF,x), _(CF,x), _(V,R), _(V,R), _(x,x), _(x,x), _(x,x), _(x,x),
/* 1BF8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* Lepcha (1C00..1C4F) */
/* 1C00 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 1C08 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 1C10 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 1C18 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 1C20 */ _(C,x), _(C,x), _(C,x), _(C,x), _(CS,x), _(CS,x), _(M,R), _(M,L),
/* 1C28 */ _(M,L), _(M,TL), _(M,R), _(M,R), _(M,B), _(CF,x), _(CF,x), _(CF,x),
/* 1C30 */ _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(Bi,x), _(Bi,x), _(x,x), _(N,x),
/* 1C38 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 1C40 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 1C48 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(C,x), _(C,x), _(C,x),
#define indic_offset_0x1cd0 2976
/* Vedic Extensions (1CD0..1CFF) */
/* 1CD0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 1CD8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 1CE0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 1CE8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 1CF0 */ _(x,x), _(x,x), _(Vs,x), _(Vs,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 1CF8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
#define indic_offset_0xa800 3024
/* Syloti Nagri (A800..A82F) */
/* A800 */ _(VI,x), _(VI,x), _(x,x), _(VI,x), _(VI,x), _(VI,x), _(V,T), _(C,x),
/* A808 */ _(C,x), _(C,x), _(C,x), _(Bi,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* A810 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* A818 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* A820 */ _(C,x), _(C,x), _(C,x), _(M,R), _(M,R), _(M,B), _(M,T), _(M,R),
/* A828 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* FILLER (A830..A83F) */
/* A830 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* A838 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* Phags-pa (A840..A87F) */
/* A840 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* A848 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* A850 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* A858 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(Vo,x), _(Vo,x),
/* A860 */ _(Vo,x), _(Vo,x), _(C,x), _(C,x), _(C,x), _(C,x), _(Vo,x), _(CS,x),
/* A868 */ _(CS,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* A870 */ _(C,x), _(CS,x), _(C,x), _(Bi,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* A878 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* Saurashtra (A880..A8DF) */
/* A880 */ _(Bi,x), _(Vs,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
/* A888 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
/* A890 */ _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* A898 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* A8A0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* A8A8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* A8B0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(CF,x), _(M,R), _(M,R), _(M,R),
/* A8B8 */ _(M,R), _(M,R), _(M,R), _(M,R), _(M,R), _(M,R), _(M,R), _(M,R),
/* A8C0 */ _(M,R), _(M,R), _(M,R), _(M,R), _(V,B), _(x,x), _(x,x), _(x,x),
/* A8C8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* A8D0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* A8D8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* FILLER (A8E0..A8FF) */
/* A8E0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* A8E8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* A8F0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* A8F8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* Kayah Li (A900..A92F) */
/* A900 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* A908 */ _(x,x), _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* A910 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* A918 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* A920 */ _(C,x), _(C,x), _(Vo,x), _(Vo,x), _(Vo,x), _(Vo,x), _(Vo,x), _(Vo,x),
/* A928 */ _(Vo,x), _(Vo,x), _(Vo,x), _(TM,x), _(TM,x), _(TM,x), _(x,x), _(x,x),
/* Rejang (A930..A95F) */
/* A930 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* A938 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* A940 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(M,B),
/* A948 */ _(M,B), _(M,B), _(M,T), _(M,B), _(M,B), _(M,B), _(M,B), _(CF,x),
/* A950 */ _(CF,x), _(CF,x), _(CF,x), _(V,R), _(x,x), _(x,x), _(x,x), _(x,x),
/* A958 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* FILLER (A960..A97F) */
/* A960 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* A968 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* A970 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* A978 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* Javanese (A980..A9DF) */
/* A980 */ _(Bi,x), _(Bi,x), _(CR,x), _(Vs,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
/* A988 */ _(VI,x), _(C,x), _(C,x), _(C,x), _(VI,x), _(VI,x), _(VI,x), _(C,x),
/* A990 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* A998 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* A9A0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* A9A8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* A9B0 */ _(C,x), _(C,x), _(C,x), _(N,x), _(M,R), _(M,R), _(M,T), _(M,T),
/* A9B8 */ _(M,B), _(M,B), _(M,L), _(M,L), _(M,T), _(CS,x), _(CM,x), _(CM,x),
/* A9C0 */ _(V,BR), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* A9C8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* A9D0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* A9D8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* FILLER (A9E0..A9FF) */
/* A9E0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* A9E8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* A9F0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* A9F8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* Cham (AA00..AA5F) */
/* AA00 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x),
/* AA08 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* AA10 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* AA18 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* AA20 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* AA28 */ _(C,x), _(M,T), _(M,T), _(M,T), _(M,T), _(M,B), _(M,T), _(M,L),
/* AA30 */ _(M,L), _(M,T), _(M,B), _(CM,x), _(CM,x), _(CM,x), _(CM,x), _(x,x),
/* AA38 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* AA40 */ _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x),
/* AA48 */ _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(x,x), _(x,x),
/* AA50 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* AA58 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* Myanmar Extended-A (AA60..AA7F) */
/* AA60 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* AA68 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* AA70 */ _(x,x), _(C,x), _(C,x), _(C,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* AA78 */ _(x,x), _(x,x), _(C,x), _(TM,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* Tai Viet (AA80..AADF) */
/* AA80 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* AA88 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* AA90 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* AA98 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* AAA0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* AAA8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* AAB0 */ _(M,T), _(M,R), _(M,T), _(M,T), _(M,B),_(M,VOL),_(M,VOL), _(M,T),
/* AAB8 */ _(M,T),_(M,VOL), _(M,R),_(M,VOL),_(M,VOL), _(M,R), _(M,T), _(TM,x),
/* AAC0 */ _(TL,x), _(TM,x), _(TL,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* AAC8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* AAD0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* AAD8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* Meetei Mayek Extensions (AAE0..AAFF) */
/* AAE0 */ _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* AAE8 */ _(C,x), _(C,x), _(C,x), _(M,L), _(M,B), _(M,T), _(M,L), _(M,R),
/* AAF0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(Vs,x), _(V,I), _(x,x),
/* AAF8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
#define indic_offset_0xabc0 3792
/* Meetei Mayek (ABC0..ABFF) */
/* ABC0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* ABC8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(VI,x), _(VI,x),
/* ABD0 */ _(C,x), _(VI,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* ABD8 */ _(C,x), _(C,x), _(C,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x),
/* ABE0 */ _(CF,x), _(CF,x), _(CF,x), _(M,R), _(M,R), _(M,T), _(M,R), _(M,R),
/* ABE8 */ _(M,B), _(M,R), _(M,R), _(x,x), _(TM,x), _(V,B), _(x,x), _(x,x),
/* ABF0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* ABF8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
#define indic_offset_0x10a00 3856
/* Kharoshthi (10A00..10A5F) */
/* 10A00 */ _(C,x), _(M,O), _(M,B), _(M,B), _(x,x), _(M,T), _(M,O), _(x,x),
/* 10A08 */ _(x,x), _(x,x), _(x,x), _(x,x), _(M,B), _(x,x), _(Bi,x), _(Vs,x),
/* 10A10 */ _(C,x), _(C,x), _(C,x), _(C,x), _(x,x), _(C,x), _(C,x), _(C,x),
/* 10A18 */ _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 10A20 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 10A28 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 10A30 */ _(C,x), _(C,x), _(C,x), _(C,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 10A38 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(V,I),
/* 10A40 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 10A48 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 10A50 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 10A58 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
#define indic_offset_0x11000 3952
/* Brahmi (11000..1107F) */
/* 11000 */ _(Bi,x), _(Bi,x), _(Vs,x), _(x,x), _(x,x), _(VI,x), _(VI,x), _(VI,x),
/* 11008 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
/* 11010 */ _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 11018 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 11020 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 11028 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 11030 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 11038 */ _(M,T), _(M,T), _(M,T), _(M,T), _(M,B), _(M,B), _(M,B), _(M,B),
/* 11040 */ _(M,B), _(M,B), _(M,T), _(M,T), _(M,T), _(M,T), _(V,T), _(x,x),
/* 11048 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 11050 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 11058 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 11060 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 11068 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 11070 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 11078 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* Kaithi (11080..110CF) */
/* 11080 */ _(Bi,x), _(Bi,x), _(Vs,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
/* 11088 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x),
/* 11090 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 11098 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 110A0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 110A8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 110B0 */ _(M,R), _(M,L), _(M,R), _(M,B), _(M,B), _(M,T), _(M,T), _(M,R),
/* 110B8 */ _(M,R), _(V,B), _(N,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 110C0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 110C8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
#define indic_offset_0x11100 4160
/* Chakma (11100..1114F) */
/* 11100 */ _(Bi,x), _(Bi,x), _(Vs,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(C,x),
/* 11108 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 11110 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 11118 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 11120 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(M,T),
/* 11128 */ _(M,T), _(M,T), _(M,B), _(M,B), _(M,L), _(M,T), _(M,TB), _(M,TB),
/* 11130 */ _(M,T), _(M,B), _(M,B), _(V,I), _(V,T), _(x,x), _(x,x), _(x,x),
/* 11138 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 11140 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 11148 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
#define indic_offset_0x11180 4240
/* Sharada (11180..111DF) */
/* 11180 */ _(Bi,x), _(Bi,x), _(Vs,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
/* 11188 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
/* 11190 */ _(VI,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 11198 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 111A0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 111A8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 111B0 */ _(C,x), _(C,x), _(C,x), _(M,R), _(M,L), _(M,R), _(M,B), _(M,B),
/* 111B8 */ _(M,B), _(M,B), _(M,B), _(M,B), _(M,T), _(M,T), _(M,T), _(M,TR),
/* 111C0 */ _(V,R), _(A,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 111C8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 111D0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 111D8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
#define indic_offset_0x11680 4336
/* Takri (11680..116CF) */
/* 11680 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
/* 11688 */ _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 11690 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 11698 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 116A0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 116A8 */ _(C,x), _(C,x), _(C,x), _(Bi,x), _(Vs,x), _(M,T), _(M,L), _(M,R),
/* 116B0 */ _(M,B), _(M,B), _(M,T), _(M,T), _(M,T), _(M,T), _(V,T), _(N,x),
/* 116B8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 116C0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 116C8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
#define indic_offset_total 4416
}; /* Table occupancy: 60% */
static INDIC_TABLE_ELEMENT_TYPE
get_indic_categories (hb_codepoint_t u)
{
if (0x0900 <= u && u <= 0x10A0) return indic_table[u - 0x0900 + indic_offset_0x0900];
if (0x1700 <= u && u <= 0x1800) return indic_table[u - 0x1700 + indic_offset_0x1700];
if (0x1900 <= u && u <= 0x1AB0) return indic_table[u - 0x1900 + indic_offset_0x1900];
if (0x1B00 <= u && u <= 0x1C50) return indic_table[u - 0x1B00 + indic_offset_0x1b00];
if (0x1CD0 <= u && u <= 0x1D00) return indic_table[u - 0x1CD0 + indic_offset_0x1cd0];
if (0xA800 <= u && u <= 0xAB00) return indic_table[u - 0xA800 + indic_offset_0xa800];
if (0xABC0 <= u && u <= 0xAC00) return indic_table[u - 0xABC0 + indic_offset_0xabc0];
if (0x10A00 <= u && u <= 0x10A60) return indic_table[u - 0x10A00 + indic_offset_0x10a00];
if (0x11000 <= u && u <= 0x110D0) return indic_table[u - 0x11000 + indic_offset_0x11000];
if (0x11100 <= u && u <= 0x11150) return indic_table[u - 0x11100 + indic_offset_0x11100];
if (0x11180 <= u && u <= 0x111E0) return indic_table[u - 0x11180 + indic_offset_0x11180];
if (0x11680 <= u && u <= 0x116D0) return indic_table[u - 0x11680 + indic_offset_0x11680];
if (unlikely (u == 0x00A0)) return _(CP,x);
if (unlikely (u == 0x25CC)) return _(CP,x);
return _(x,x);
}
#undef _
#undef ISC_A
#undef ISC_Bi
#undef ISC_C
#undef ISC_CD
#undef ISC_CF
#undef ISC_CHL
#undef ISC_CM
#undef ISC_CP
#undef ISC_CR
#undef ISC_CS
#undef ISC_ML
#undef ISC_N
#undef ISC_x
#undef ISC_RS
#undef ISC_TL
#undef ISC_TM
#undef ISC_V
#undef ISC_Vs
#undef ISC_Vo
#undef ISC_M
#undef ISC_VI
#undef IMC_B
#undef IMC_BR
#undef IMC_I
#undef IMC_L
#undef IMC_LR
#undef IMC_x
#undef IMC_O
#undef IMC_R
#undef IMC_T
#undef IMC_TB
#undef IMC_TBR
#undef IMC_TL
#undef IMC_TLR
#undef IMC_TR
#undef IMC_VOL
#endif /* HB_OT_SHAPE_COMPLEX_INDIC_TABLE_HH */
/* == End of generated table == */

View File

@ -37,19 +37,19 @@
*/ */
#define IN_HALF_BLOCK(u, Base) (((u) & ~0x7F) == (Base)) #define IN_HALF_BLOCK(u, Base) (((u) & ~0x7Fu) == (Base))
#define IS_DEVA(u) (IN_HALF_BLOCK (u, 0x0900)) #define IS_DEVA(u) (IN_HALF_BLOCK (u, 0x0900u))
#define IS_BENG(u) (IN_HALF_BLOCK (u, 0x0980)) #define IS_BENG(u) (IN_HALF_BLOCK (u, 0x0980u))
#define IS_GURU(u) (IN_HALF_BLOCK (u, 0x0A00)) #define IS_GURU(u) (IN_HALF_BLOCK (u, 0x0A00u))
#define IS_GUJR(u) (IN_HALF_BLOCK (u, 0x0A80)) #define IS_GUJR(u) (IN_HALF_BLOCK (u, 0x0A80u))
#define IS_ORYA(u) (IN_HALF_BLOCK (u, 0x0B00)) #define IS_ORYA(u) (IN_HALF_BLOCK (u, 0x0B00u))
#define IS_TAML(u) (IN_HALF_BLOCK (u, 0x0B80)) #define IS_TAML(u) (IN_HALF_BLOCK (u, 0x0B80u))
#define IS_TELU(u) (IN_HALF_BLOCK (u, 0x0C00)) #define IS_TELU(u) (IN_HALF_BLOCK (u, 0x0C00u))
#define IS_KNDA(u) (IN_HALF_BLOCK (u, 0x0C80)) #define IS_KNDA(u) (IN_HALF_BLOCK (u, 0x0C80u))
#define IS_MLYM(u) (IN_HALF_BLOCK (u, 0x0D00)) #define IS_MLYM(u) (IN_HALF_BLOCK (u, 0x0D00u))
#define IS_SINH(u) (IN_HALF_BLOCK (u, 0x0D80)) #define IS_SINH(u) (IN_HALF_BLOCK (u, 0x0D80u))
#define IS_KHMR(u) (IN_HALF_BLOCK (u, 0x1780)) #define IS_KHMR(u) (IN_HALF_BLOCK (u, 0x1780u))
#define MATRA_POS_LEFT(u) POS_PRE_M #define MATRA_POS_LEFT(u) POS_PRE_M
@ -60,8 +60,8 @@
IS_GUJR(u) ? POS_AFTER_POST : \ IS_GUJR(u) ? POS_AFTER_POST : \
IS_ORYA(u) ? POS_AFTER_POST : \ IS_ORYA(u) ? POS_AFTER_POST : \
IS_TAML(u) ? POS_AFTER_POST : \ IS_TAML(u) ? POS_AFTER_POST : \
IS_TELU(u) ? (u <= 0x0C42 ? POS_BEFORE_SUB : POS_AFTER_SUB) : \ IS_TELU(u) ? (u <= 0x0C42u ? POS_BEFORE_SUB : POS_AFTER_SUB) : \
IS_KNDA(u) ? (u < 0x0CC3 || u > 0xCD6 ? POS_BEFORE_SUB : POS_AFTER_SUB) : \ IS_KNDA(u) ? (u < 0x0CC3u || u > 0xCD6u ? POS_BEFORE_SUB : POS_AFTER_SUB) : \
IS_MLYM(u) ? POS_AFTER_POST : \ IS_MLYM(u) ? POS_AFTER_POST : \
IS_SINH(u) ? POS_AFTER_SUB : \ IS_SINH(u) ? POS_AFTER_SUB : \
IS_KHMR(u) ? POS_AFTER_POST : \ IS_KHMR(u) ? POS_AFTER_POST : \
@ -112,20 +112,20 @@ matra_position (hb_codepoint_t u, indic_position_t side)
* Or completely remove it and just check in the tables. * Or completely remove it and just check in the tables.
*/ */
static const hb_codepoint_t ra_chars[] = { static const hb_codepoint_t ra_chars[] = {
0x0930, /* Devanagari */ 0x0930u, /* Devanagari */
0x09B0, /* Bengali */ 0x09B0u, /* Bengali */
0x09F0, /* Bengali */ 0x09F0u, /* Bengali */
0x0A30, /* Gurmukhi */ /* No Reph */ 0x0A30u, /* Gurmukhi */ /* No Reph */
0x0AB0, /* Gujarati */ 0x0AB0u, /* Gujarati */
0x0B30, /* Oriya */ 0x0B30u, /* Oriya */
0x0BB0, /* Tamil */ /* No Reph */ 0x0BB0u, /* Tamil */ /* No Reph */
0x0C30, /* Telugu */ /* Reph formed only with ZWJ */ 0x0C30u, /* Telugu */ /* Reph formed only with ZWJ */
0x0CB0, /* Kannada */ 0x0CB0u, /* Kannada */
0x0D30, /* Malayalam */ /* No Reph, Logical Repha */ 0x0D30u, /* Malayalam */ /* No Reph, Logical Repha */
0x0DBB, /* Sinhala */ /* Reph formed only with ZWJ */ 0x0DBBu, /* Sinhala */ /* Reph formed only with ZWJ */
0x179A, /* Khmer */ /* No Reph, Visual Repha */ 0x179Au, /* Khmer */ /* No Reph, Visual Repha */
}; };
static inline bool static inline bool
@ -145,28 +145,18 @@ is_one_of (const hb_glyph_info_t &info, unsigned int flags)
return !!(FLAG (info.indic_category()) & flags); return !!(FLAG (info.indic_category()) & flags);
} }
#define JOINER_FLAGS (FLAG (OT_ZWJ) | FLAG (OT_ZWNJ))
static inline bool static inline bool
is_joiner (const hb_glyph_info_t &info) is_joiner (const hb_glyph_info_t &info)
{ {
return is_one_of (info, JOINER_FLAGS); return is_one_of (info, JOINER_FLAGS);
} }
#define MEDIAL_FLAGS (FLAG (OT_CM) | FLAG (OT_CM2))
/* Note:
*
* We treat Vowels and placeholders as if they were consonants. This is safe because Vowels
* cannot happen in a consonant syllable. The plus side however is, we can call the
* consonant syllable logic from the vowel syllable function and get it all right! */
#define CONSONANT_FLAGS (FLAG (OT_C) | FLAG (OT_Ra) | MEDIAL_FLAGS | FLAG (OT_V) | FLAG (OT_NBSP) | FLAG (OT_DOTTEDCIRCLE))
static inline bool static inline bool
is_consonant (const hb_glyph_info_t &info) is_consonant (const hb_glyph_info_t &info)
{ {
return is_one_of (info, CONSONANT_FLAGS); return is_one_of (info, CONSONANT_FLAGS);
} }
#define HALANT_OR_COENG_FLAGS (FLAG (OT_H) | FLAG (OT_Coeng))
static inline bool static inline bool
is_halant_or_coeng (const hb_glyph_info_t &info) is_halant_or_coeng (const hb_glyph_info_t &info)
{ {
@ -178,7 +168,7 @@ set_indic_properties (hb_glyph_info_t &info)
{ {
hb_codepoint_t u = info.codepoint; hb_codepoint_t u = info.codepoint;
unsigned int type = hb_indic_get_categories (u); unsigned int type = hb_indic_get_categories (u);
indic_category_t cat = (indic_category_t) (type & 0x7F); indic_category_t cat = (indic_category_t) (type & 0x7Fu);
indic_position_t pos = (indic_position_t) (type >> 8); indic_position_t pos = (indic_position_t) (type >> 8);
@ -188,48 +178,59 @@ set_indic_properties (hb_glyph_info_t &info)
/* The spec says U+0952 is OT_A. However, testing shows that Uniscribe /* The spec says U+0952 is OT_A. However, testing shows that Uniscribe
* treats U+0951..U+0954 all behave similarly. * treats a whole bunch of characters similarly.
* TESTS: * TESTS: For example, for U+0951:
* U+092E,U+0947,U+0952 * U+092E,U+0947,U+0952
* U+092E,U+0952,U+0947 * U+092E,U+0952,U+0947
* U+092E,U+0947,U+0951 * U+092E,U+0947,U+0951
* U+092E,U+0951,U+0947 * U+092E,U+0951,U+0947
* U+092E,U+0951,U+0952
* U+092E,U+0952,U+0951
*/ */
if (unlikely (hb_in_range<hb_codepoint_t> (u, 0x0951, 0x0954))) if (unlikely (hb_in_ranges (u, 0x0951u, 0x0952u,
0x1CD0u, 0x1CD2u,
0x1CD4u, 0x1CE1u) ||
u == 0x1CF4u))
cat = OT_A; cat = OT_A;
/* The following act more like the Bindus. */
if (unlikely (u == 0x17D1)) else if (unlikely (hb_in_range (u, 0x0953u, 0x0954u)))
cat = OT_X; cat = OT_SM;
if (cat == OT_X && /* The following act like consonants. */
unlikely (hb_in_range<hb_codepoint_t> (u, 0x17CB, 0x17D3))) /* Khmer Various signs */ else if (unlikely (hb_in_ranges (u, 0x0A72u, 0x0A73u,
0x1CF5u, 0x1CF6u)))
cat = OT_C;
/* TODO: The following should only be allowed after a Visarga.
* For now, just treat them like regular tone marks. */
else if (unlikely (hb_in_range (u, 0x1CE2u, 0x1CE8u)))
cat = OT_A;
/* TODO: The following should only be allowed after some of
* the nasalization marks, maybe only for U+1CE9..U+1CF1.
* For now, just treat them like tone marks. */
else if (unlikely (u == 0x1CEDu))
cat = OT_A;
/* The following take marks in standalone clusters, similar to Avagraha. */
else if (unlikely (hb_in_ranges (u, 0xA8F2u, 0xA8F7u,
0x1CE9u, 0x1CECu,
0x1CEEu, 0x1CF1u)))
{
cat = OT_Symbol;
ASSERT_STATIC ((int) INDIC_SYLLABIC_CATEGORY_AVAGRAHA == OT_Symbol);
}
else if (unlikely (hb_in_range (u, 0x17CDu, 0x17D1u) ||
u == 0x17CBu || u == 0x17D3u || u == 0x17DDu)) /* Khmer Various signs */
{ {
/* These are like Top Matras. */ /* These are like Top Matras. */
cat = OT_M; cat = OT_M;
pos = POS_ABOVE_C; pos = POS_ABOVE_C;
} }
if (u == 0x17C6) /* Khmer Bindu doesn't like to be repositioned. */ else if (unlikely (u == 0x17C6u)) cat = OT_N; /* Khmer Bindu doesn't like to be repositioned. */
cat = OT_N; else if (unlikely (u == 0x17D2u)) cat = OT_Coeng; /* Khmer coeng */
else if (unlikely (hb_in_range (u, 0x2010u, 0x2011u)))
if (unlikely (u == 0x17D2)) cat = OT_Coeng; /* Khmer coeng */ cat = OT_PLACEHOLDER;
else if (unlikely (u == 0x200C)) cat = OT_ZWNJ; else if (unlikely (u == 0x25CCu)) cat = OT_DOTTEDCIRCLE;
else if (unlikely (u == 0x200D)) cat = OT_ZWJ; else if (unlikely (u == 0xA982u)) cat = OT_SM; /* Javanese repha. */
else if (unlikely (u == 0x25CC)) cat = OT_DOTTEDCIRCLE; else if (unlikely (u == 0xA9BEu)) cat = OT_CM2; /* Javanese medial ya. */
else if (unlikely (u == 0x0A71)) cat = OT_SM; /* GURMUKHI ADDAK. Move it to the end. */ else if (unlikely (u == 0xA9BDu)) { cat = OT_M; pos = POS_POST_C; } /* Javanese vocalic r. */
else if (unlikely (u == 0xA982)) cat = OT_SM; /* Javanese repha. */
else if (unlikely (u == 0xA9BE)) cat = OT_CM2; /* Javanese medial ya. */
else if (unlikely (u == 0xA9BD)) { cat = OT_M; pos = POS_POST_C; } /* Javanese vocalic r. */
if (cat == OT_Repha) {
/* There are two kinds of characters marked as Repha:
* - The ones that are GenCat=Mn are already positioned visually, ie. after base. (eg. Khmer)
* - The ones that are GenCat=Lo is encoded logically, ie. beginning of syllable. (eg. Malayalam)
*
* We recategorize the first kind to look like a Nukta and attached to the base directly.
*/
if (_hb_glyph_info_get_general_category (&info) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
cat = OT_N;
}
/* /*
@ -246,12 +247,12 @@ set_indic_properties (hb_glyph_info_t &info)
{ {
pos = matra_position (u, pos); pos = matra_position (u, pos);
} }
else if ((FLAG (cat) & (FLAG (OT_SM) | FLAG (OT_VD) | FLAG (OT_A) | FLAG (OT_Avag)))) else if ((FLAG (cat) & (FLAG (OT_SM) | FLAG (OT_VD) | FLAG (OT_A) | FLAG (OT_Symbol))))
{ {
pos = POS_SMVD; pos = POS_SMVD;
} }
if (unlikely (u == 0x0B01)) pos = POS_BEFORE_SUB; /* Oriya Bindu is BeforeSub in the spec. */ if (unlikely (u == 0x0B01u)) pos = POS_BEFORE_SUB; /* Oriya Bindu is BeforeSub in the spec. */
@ -315,20 +316,20 @@ struct indic_config_t
static const indic_config_t indic_configs[] = static const indic_config_t indic_configs[] =
{ {
/* Default. Should be first. */ /* Default. Should be first. */
{HB_SCRIPT_INVALID, false, 0,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_1}, {HB_SCRIPT_INVALID, false, 0,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_1},
{HB_SCRIPT_DEVANAGARI,true, 0x094D,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE}, {HB_SCRIPT_DEVANAGARI,true, 0x094Du,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE},
{HB_SCRIPT_BENGALI, true, 0x09CD,BASE_POS_LAST, REPH_POS_AFTER_SUB, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE}, {HB_SCRIPT_BENGALI, true, 0x09CDu,BASE_POS_LAST, REPH_POS_AFTER_SUB, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE},
{HB_SCRIPT_GURMUKHI, true, 0x0A4D,BASE_POS_LAST, REPH_POS_BEFORE_SUB, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE}, {HB_SCRIPT_GURMUKHI, true, 0x0A4Du,BASE_POS_LAST, REPH_POS_BEFORE_SUB, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE},
{HB_SCRIPT_GUJARATI, true, 0x0ACD,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE}, {HB_SCRIPT_GUJARATI, true, 0x0ACDu,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE},
{HB_SCRIPT_ORIYA, true, 0x0B4D,BASE_POS_LAST, REPH_POS_AFTER_MAIN, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE}, {HB_SCRIPT_ORIYA, true, 0x0B4Du,BASE_POS_LAST, REPH_POS_AFTER_MAIN, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE},
{HB_SCRIPT_TAMIL, true, 0x0BCD,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_2}, {HB_SCRIPT_TAMIL, true, 0x0BCDu,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_2},
{HB_SCRIPT_TELUGU, true, 0x0C4D,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_EXPLICIT, BLWF_MODE_POST_ONLY, PREF_LEN_2}, {HB_SCRIPT_TELUGU, true, 0x0C4Du,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_EXPLICIT, BLWF_MODE_POST_ONLY, PREF_LEN_2},
{HB_SCRIPT_KANNADA, true, 0x0CCD,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_IMPLICIT, BLWF_MODE_POST_ONLY, PREF_LEN_2}, {HB_SCRIPT_KANNADA, true, 0x0CCDu,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_IMPLICIT, BLWF_MODE_POST_ONLY, PREF_LEN_2},
{HB_SCRIPT_MALAYALAM, true, 0x0D4D,BASE_POS_LAST, REPH_POS_AFTER_MAIN, REPH_MODE_LOG_REPHA,BLWF_MODE_PRE_AND_POST, PREF_LEN_2}, {HB_SCRIPT_MALAYALAM, true, 0x0D4Du,BASE_POS_LAST, REPH_POS_AFTER_MAIN, REPH_MODE_LOG_REPHA,BLWF_MODE_PRE_AND_POST, PREF_LEN_2},
{HB_SCRIPT_SINHALA, false,0x0DCA,BASE_POS_LAST_SINHALA, {HB_SCRIPT_SINHALA, false,0x0DCAu,BASE_POS_LAST_SINHALA,
REPH_POS_AFTER_MAIN, REPH_MODE_EXPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE}, REPH_POS_AFTER_MAIN, REPH_MODE_EXPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE},
{HB_SCRIPT_KHMER, false,0x17D2,BASE_POS_FIRST,REPH_POS_DONT_CARE, REPH_MODE_VIS_REPHA,BLWF_MODE_PRE_AND_POST, PREF_LEN_2}, {HB_SCRIPT_KHMER, false,0x17D2u,BASE_POS_FIRST,REPH_POS_DONT_CARE, REPH_MODE_VIS_REPHA,BLWF_MODE_PRE_AND_POST, PREF_LEN_2},
{HB_SCRIPT_JAVANESE, false,0xA9C0,BASE_POS_FIRST,REPH_POS_DONT_CARE, REPH_MODE_VIS_REPHA,BLWF_MODE_PRE_AND_POST, PREF_LEN_1}, {HB_SCRIPT_JAVANESE, false,0xA9C0u,BASE_POS_FIRST,REPH_POS_DONT_CARE, REPH_MODE_VIS_REPHA,BLWF_MODE_PRE_AND_POST, PREF_LEN_1},
}; };
@ -552,12 +553,12 @@ data_create_indic (const hb_ot_shape_plan_t *plan)
break; break;
} }
indic_plan->is_old_spec = indic_plan->config->has_old_spec && ((plan->map.chosen_script[0] & 0x000000FF) != '2'); indic_plan->is_old_spec = indic_plan->config->has_old_spec && ((plan->map.chosen_script[0] & 0x000000FFu) != '2');
indic_plan->virama_glyph = (hb_codepoint_t) -1; indic_plan->virama_glyph = (hb_codepoint_t) -1;
/* Use zero-context would_substitute() matching for new-spec of the main /* Use zero-context would_substitute() matching for new-spec of the main
* Indic scripts, but not for old-spec or scripts with one spec only. */ * Indic scripts, and scripts with one spec only, but not for old-specs. */
bool zero_context = indic_plan->config->has_old_spec || !indic_plan->is_old_spec; bool zero_context = !indic_plan->is_old_spec;
indic_plan->rphf.init (&plan->map, HB_TAG('r','p','h','f'), zero_context); indic_plan->rphf.init (&plan->map, HB_TAG('r','p','h','f'), zero_context);
indic_plan->pref.init (&plan->map, HB_TAG('p','r','e','f'), zero_context); indic_plan->pref.init (&plan->map, HB_TAG('p','r','e','f'), zero_context);
indic_plan->blwf.init (&plan->map, HB_TAG('b','l','w','f'), zero_context); indic_plan->blwf.init (&plan->map, HB_TAG('b','l','w','f'), zero_context);
@ -614,7 +615,7 @@ enum syllable_type_t {
consonant_syllable, consonant_syllable,
vowel_syllable, vowel_syllable,
standalone_cluster, standalone_cluster,
avagraha_cluster, symbol_cluster,
broken_cluster, broken_cluster,
non_indic_cluster, non_indic_cluster,
}; };
@ -634,8 +635,9 @@ setup_masks_indic (const hb_ot_shape_plan_t *plan HB_UNUSED,
* and setup masks later on in a pause-callback. */ * and setup masks later on in a pause-callback. */
unsigned int count = buffer->len; unsigned int count = buffer->len;
hb_glyph_info_t *info = buffer->info;
for (unsigned int i = 0; i < count; i++) for (unsigned int i = 0; i < count; i++)
set_indic_properties (buffer->info[i]); set_indic_properties (info[i]);
} }
static void static void
@ -672,10 +674,12 @@ update_consonant_positions (const hb_ot_shape_plan_t *plan,
{ {
hb_face_t *face = font->face; hb_face_t *face = font->face;
unsigned int count = buffer->len; unsigned int count = buffer->len;
hb_glyph_info_t *info = buffer->info;
for (unsigned int i = 0; i < count; i++) for (unsigned int i = 0; i < count; i++)
if (buffer->info[i].indic_position() == POS_BASE_C) { if (info[i].indic_position() == POS_BASE_C)
hb_codepoint_t consonant = buffer->info[i].codepoint; {
buffer->info[i].indic_position() = consonant_position_from_face (indic_plan, consonant, virama, face); hb_codepoint_t consonant = info[i].codepoint;
info[i].indic_position() = consonant_position_from_face (indic_plan, consonant, virama, face);
} }
} }
} }
@ -725,8 +729,13 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
)) ))
{ {
/* See if it matches the 'rphf' feature. */ /* See if it matches the 'rphf' feature. */
hb_codepoint_t glyphs[2] = {info[start].codepoint, info[start + 1].codepoint}; hb_codepoint_t glyphs[3] = {info[start].codepoint,
if (indic_plan->rphf.would_substitute (glyphs, ARRAY_LENGTH (glyphs), face)) info[start + 1].codepoint,
indic_plan->config->reph_mode == REPH_MODE_EXPLICIT ?
info[start + 2].codepoint : 0};
if (indic_plan->rphf.would_substitute (glyphs, 2, face) ||
(indic_plan->config->reph_mode == REPH_MODE_EXPLICIT &&
indic_plan->rphf.would_substitute (glyphs, 3, face)))
{ {
limit += 2; limit += 2;
while (limit < end && is_joiner (info[limit])) while (limit < end && is_joiner (info[limit]))
@ -801,7 +810,7 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
case BASE_POS_LAST_SINHALA: case BASE_POS_LAST_SINHALA:
{ {
/* Sinhala base positioning is slightly different from main Indic, in that: /* Sinhala base positioning is slightly different from main Indic, in that:
* 1. It's ZWJ behavior is different, * 1. Its ZWJ behavior is different,
* 2. We don't need to look into the font for consonant positions. * 2. We don't need to look into the font for consonant positions.
*/ */
@ -912,14 +921,32 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
info[start].indic_position() = POS_RA_TO_BECOME_REPH; info[start].indic_position() = POS_RA_TO_BECOME_REPH;
/* For old-style Indic script tags, move the first post-base Halant after /* For old-style Indic script tags, move the first post-base Halant after
* last consonant. Only do this if there is *not* a Halant after last * last consonant.
* consonant. Otherwise it becomes messy. */ *
if (indic_plan->is_old_spec) { * Reports suggest that in some scripts Uniscribe does this only if there
* is *not* a Halant after last consonant already (eg. Kannada), while it
* does it unconditionally in other scripts (eg. Malayalam). We don't
* currently know about other scripts, so we single out Malayalam for now.
*
* Kannada test case:
* U+0C9A,U+0CCD,U+0C9A,U+0CCD
* With some versions of Lohit Kannada.
* https://bugs.freedesktop.org/show_bug.cgi?id=59118
*
* Malayalam test case:
* U+0D38,U+0D4D,U+0D31,U+0D4D,U+0D31,U+0D4D
* With lohit-ttf-20121122/Lohit-Malayalam.ttf
*/
if (indic_plan->is_old_spec)
{
bool disallow_double_halants = buffer->props.script != HB_SCRIPT_MALAYALAM;
for (unsigned int i = base + 1; i < end; i++) for (unsigned int i = base + 1; i < end; i++)
if (info[i].indic_category() == OT_H) { if (info[i].indic_category() == OT_H)
{
unsigned int j; unsigned int j;
for (j = end - 1; j > i; j--) for (j = end - 1; j > i; j--)
if (is_consonant (info[j]) || info[j].indic_category() == OT_H) if (is_consonant (info[j]) ||
(disallow_double_halants && info[j].indic_category() == OT_H))
break; break;
if (info[j].indic_category() != OT_H && j > i) { if (info[j].indic_category() != OT_H && j > i) {
/* Move Halant to after last consonant. */ /* Move Halant to after last consonant. */
@ -1151,8 +1178,8 @@ initial_reordering_standalone_cluster (const hb_ot_shape_plan_t *plan,
hb_buffer_t *buffer, hb_buffer_t *buffer,
unsigned int start, unsigned int end) unsigned int start, unsigned int end)
{ {
/* We treat NBSP/dotted-circle as if they are consonants, so we should just chain. /* We treat placeholder/dotted-circle as if they are consonants, so we
* Only if not in compatibility mode that is... */ * should just chain. Only if not in compatibility mode that is... */
if (hb_options ().uniscribe_bug_compatible) if (hb_options ().uniscribe_bug_compatible)
{ {
@ -1177,10 +1204,10 @@ initial_reordering_broken_cluster (const hb_ot_shape_plan_t *plan,
} }
static void static void
initial_reordering_avagraha_cluster (const hb_ot_shape_plan_t *plan HB_UNUSED, initial_reordering_symbol_cluster (const hb_ot_shape_plan_t *plan HB_UNUSED,
hb_face_t *face HB_UNUSED, hb_face_t *face HB_UNUSED,
hb_buffer_t *buffer HB_UNUSED, hb_buffer_t *buffer HB_UNUSED,
unsigned int start HB_UNUSED, unsigned int end HB_UNUSED) unsigned int start HB_UNUSED, unsigned int end HB_UNUSED)
{ {
/* Nothing to do right now. If we ever switch to using the output /* Nothing to do right now. If we ever switch to using the output
* buffer in the reordering process, we'd need to next_glyph() here. */ * buffer in the reordering process, we'd need to next_glyph() here. */
@ -1208,7 +1235,7 @@ initial_reordering_syllable (const hb_ot_shape_plan_t *plan,
case consonant_syllable: initial_reordering_consonant_syllable (plan, face, buffer, start, end); return; case consonant_syllable: initial_reordering_consonant_syllable (plan, face, buffer, start, end); return;
case vowel_syllable: initial_reordering_vowel_syllable (plan, face, buffer, start, end); return; case vowel_syllable: initial_reordering_vowel_syllable (plan, face, buffer, start, end); return;
case standalone_cluster: initial_reordering_standalone_cluster (plan, face, buffer, start, end); return; case standalone_cluster: initial_reordering_standalone_cluster (plan, face, buffer, start, end); return;
case avagraha_cluster: initial_reordering_avagraha_cluster (plan, face, buffer, start, end); return; case symbol_cluster: initial_reordering_symbol_cluster (plan, face, buffer, start, end); return;
case broken_cluster: initial_reordering_broken_cluster (plan, face, buffer, start, end); return; case broken_cluster: initial_reordering_broken_cluster (plan, face, buffer, start, end); return;
case non_indic_cluster: initial_reordering_non_indic_cluster (plan, face, buffer, start, end); return; case non_indic_cluster: initial_reordering_non_indic_cluster (plan, face, buffer, start, end); return;
} }
@ -1222,8 +1249,10 @@ insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED,
/* Note: This loop is extra overhead, but should not be measurable. */ /* Note: This loop is extra overhead, but should not be measurable. */
bool has_broken_syllables = false; bool has_broken_syllables = false;
unsigned int count = buffer->len; unsigned int count = buffer->len;
hb_glyph_info_t *info = buffer->info;
for (unsigned int i = 0; i < count; i++) for (unsigned int i = 0; i < count; i++)
if ((buffer->info[i].syllable() & 0x0F) == broken_cluster) { if ((info[i].syllable() & 0x0F) == broken_cluster)
{
has_broken_syllables = true; has_broken_syllables = true;
break; break;
} }
@ -1232,11 +1261,11 @@ insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED,
hb_codepoint_t dottedcircle_glyph; hb_codepoint_t dottedcircle_glyph;
if (!font->get_glyph (0x25CC, 0, &dottedcircle_glyph)) if (!font->get_glyph (0x25CCu, 0, &dottedcircle_glyph))
return; return;
hb_glyph_info_t dottedcircle = {0}; hb_glyph_info_t dottedcircle = {0};
dottedcircle.codepoint = 0x25CC; dottedcircle.codepoint = 0x25CCu;
set_indic_properties (dottedcircle); set_indic_properties (dottedcircle);
dottedcircle.codepoint = dottedcircle_glyph; dottedcircle.codepoint = dottedcircle_glyph;
@ -1256,6 +1285,7 @@ insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED,
info.cluster = buffer->cur().cluster; info.cluster = buffer->cur().cluster;
info.mask = buffer->cur().mask; info.mask = buffer->cur().mask;
info.syllable() = buffer->cur().syllable(); info.syllable() = buffer->cur().syllable();
/* TODO Set glyph_props? */
/* Insert dottedcircle after possible Repha. */ /* Insert dottedcircle after possible Repha. */
while (buffer->idx < buffer->len && while (buffer->idx < buffer->len &&
@ -1302,6 +1332,27 @@ final_reordering_syllable (const hb_ot_shape_plan_t *plan,
const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data; const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data;
hb_glyph_info_t *info = buffer->info; hb_glyph_info_t *info = buffer->info;
/* This function relies heavily on halant glyphs. Lots of ligation
* and possibly multiplication substitutions happened prior to this
* phase, and that might have messed up our properties. Recover
* from a particular case of that where we're fairly sure that a
* class of OT_H is desired but has been lost. */
if (indic_plan->virama_glyph)
{
unsigned int virama_glyph = indic_plan->virama_glyph;
for (unsigned int i = start; i < end; i++)
if (info[i].codepoint == virama_glyph &&
_hb_glyph_info_ligated (&info[i]) &&
_hb_glyph_info_multiplied (&info[i]))
{
/* This will make sure that this glyph passes is_halant_or_coeng() test. */
info[i].indic_category() = OT_H;
_hb_glyph_info_clear_ligated_and_multiplied (&info[i]);
}
}
/* 4. Final reordering: /* 4. Final reordering:
* *
* After the localized forms and basic shaping forms GSUB features have been * After the localized forms and basic shaping forms GSUB features have been
@ -1310,21 +1361,45 @@ final_reordering_syllable (const hb_ot_shape_plan_t *plan,
* cluster. * cluster.
*/ */
bool try_pref = !!indic_plan->mask_array[PREF];
/* Find base again */ /* Find base again */
unsigned int base; unsigned int base;
for (base = start; base < end; base++) for (base = start; base < end; base++)
if (info[base].indic_position() >= POS_BASE_C) { if (info[base].indic_position() >= POS_BASE_C)
{
if (try_pref && base + 1 < end && indic_plan->config->pref_len == 2)
{
for (unsigned int i = base + 1; i < end; i++)
if ((info[i].mask & indic_plan->mask_array[PREF]) != 0)
{
if (!(_hb_glyph_info_substituted (&info[i]) &&
_hb_glyph_info_ligated_and_didnt_multiply (&info[i])))
{
/* Ok, this was a 'pref' candidate but didn't form any.
* Base is around here... */
base = i;
while (base < end && is_halant_or_coeng (info[base]))
base++;
info[base].indic_position() = POS_BASE_C;
try_pref = false;
}
break;
}
}
if (start < base && info[base].indic_position() > POS_BASE_C) if (start < base && info[base].indic_position() > POS_BASE_C)
base--; base--;
break; break;
} }
if (base == end && start < base && if (base == end && start < base &&
info[base - 1].indic_category() != OT_ZWJ) is_one_of (info[base - 1], FLAG (OT_ZWJ)))
base--;
while (start < base &&
(info[base].indic_category() == OT_H ||
info[base].indic_category() == OT_N))
base--; base--;
if (base < end)
while (start < base &&
is_one_of (info[base], (FLAG (OT_N) | HALANT_OR_COENG_FLAGS)))
base--;
/* o Reorder matras: /* o Reorder matras:
@ -1349,7 +1424,7 @@ final_reordering_syllable (const hb_ot_shape_plan_t *plan,
if (buffer->props.script != HB_SCRIPT_MALAYALAM && buffer->props.script != HB_SCRIPT_TAMIL) if (buffer->props.script != HB_SCRIPT_MALAYALAM && buffer->props.script != HB_SCRIPT_TAMIL)
{ {
while (new_pos > start && while (new_pos > start &&
!(is_one_of (info[new_pos], (FLAG (OT_M) | FLAG (OT_H) | FLAG (OT_Coeng))))) !(is_one_of (info[new_pos], (FLAG (OT_M) | HALANT_OR_COENG_FLAGS))))
new_pos--; new_pos--;
/* If we found no Halant we are done. /* If we found no Halant we are done.
@ -1412,7 +1487,7 @@ final_reordering_syllable (const hb_ot_shape_plan_t *plan,
if (start + 1 < end && if (start + 1 < end &&
info[start].indic_position() == POS_RA_TO_BECOME_REPH && info[start].indic_position() == POS_RA_TO_BECOME_REPH &&
((info[start].indic_category() == OT_Repha) ^ ((info[start].indic_category() == OT_Repha) ^
_hb_glyph_info_ligated (&info[start]))) _hb_glyph_info_ligated_and_didnt_multiply (&info[start])))
{ {
unsigned int new_reph_pos; unsigned int new_reph_pos;
reph_position_t reph_pos = indic_plan->config->reph_pos; reph_position_t reph_pos = indic_plan->config->reph_pos;
@ -1549,7 +1624,7 @@ final_reordering_syllable (const hb_ot_shape_plan_t *plan,
* the following rules: * the following rules:
*/ */
if (indic_plan->mask_array[PREF] && base + 1 < end) /* Otherwise there can't be any pre-base reordering Ra. */ if (try_pref && base + 1 < end) /* Otherwise there can't be any pre-base reordering Ra. */
{ {
unsigned int pref_len = indic_plan->config->pref_len; unsigned int pref_len = indic_plan->config->pref_len;
for (unsigned int i = base + 1; i < end; i++) for (unsigned int i = base + 1; i < end; i++)
@ -1565,7 +1640,7 @@ final_reordering_syllable (const hb_ot_shape_plan_t *plan,
* If pref len is longer than one, then only reorder if it ligated. If * If pref len is longer than one, then only reorder if it ligated. If
* pref len is one, only reorder if it didn't ligate with other things. */ * pref len is one, only reorder if it didn't ligate with other things. */
if (_hb_glyph_info_substituted (&info[i]) && if (_hb_glyph_info_substituted (&info[i]) &&
((pref_len == 1) ^ _hb_glyph_info_ligated (&info[i]))) ((pref_len == 1) ^ _hb_glyph_info_ligated_and_didnt_multiply (&info[i])))
{ {
/* /*
* 2. Try to find a target position the same way as for pre-base matra. * 2. Try to find a target position the same way as for pre-base matra.
@ -1699,37 +1774,37 @@ decompose_indic (const hb_ot_shape_normalize_context_t *c,
switch (ab) switch (ab)
{ {
/* Don't decompose these. */ /* Don't decompose these. */
case 0x0931 : return false; case 0x0931u : return false;
case 0x0B94 : return false; case 0x0B94u : return false;
/* /*
* Decompose split matras that don't have Unicode decompositions. * Decompose split matras that don't have Unicode decompositions.
*/ */
case 0x0F77 : *a = 0x0FB2; *b= 0x0F81; return true; case 0x0F77u : *a = 0x0FB2u; *b= 0x0F81u; return true;
case 0x0F79 : *a = 0x0FB3; *b= 0x0F81; return true; case 0x0F79u : *a = 0x0FB3u; *b= 0x0F81u; return true;
case 0x17BE : *a = 0x17C1; *b= 0x17BE; return true; case 0x17BEu : *a = 0x17C1u; *b= 0x17BEu; return true;
case 0x17BF : *a = 0x17C1; *b= 0x17BF; return true; case 0x17BFu : *a = 0x17C1u; *b= 0x17BFu; return true;
case 0x17C0 : *a = 0x17C1; *b= 0x17C0; return true; case 0x17C0u : *a = 0x17C1u; *b= 0x17C0u; return true;
case 0x17C4 : *a = 0x17C1; *b= 0x17C4; return true; case 0x17C4u : *a = 0x17C1u; *b= 0x17C4u; return true;
case 0x17C5 : *a = 0x17C1; *b= 0x17C5; return true; case 0x17C5u : *a = 0x17C1u; *b= 0x17C5u; return true;
case 0x1925 : *a = 0x1920; *b= 0x1923; return true; case 0x1925u : *a = 0x1920u; *b= 0x1923u; return true;
case 0x1926 : *a = 0x1920; *b= 0x1924; return true; case 0x1926u : *a = 0x1920u; *b= 0x1924u; return true;
case 0x1B3C : *a = 0x1B42; *b= 0x1B3C; return true; case 0x1B3Cu : *a = 0x1B42u; *b= 0x1B3Cu; return true;
case 0x1112E : *a = 0x11127; *b= 0x11131; return true; case 0x1112Eu : *a = 0x11127u; *b= 0x11131u; return true;
case 0x1112F : *a = 0x11127; *b= 0x11132; return true; case 0x1112Fu : *a = 0x11127u; *b= 0x11132u; return true;
#if 0 #if 0
/* This one has no decomposition in Unicode, but needs no decomposition either. */ /* This one has no decomposition in Unicode, but needs no decomposition either. */
/* case 0x0AC9 : return false; */ /* case 0x0AC9u : return false; */
case 0x0B57 : *a = no decomp, -> RIGHT; return true; case 0x0B57u : *a = no decomp, -> RIGHT; return true;
case 0x1C29 : *a = no decomp, -> LEFT; return true; case 0x1C29u : *a = no decomp, -> LEFT; return true;
case 0xA9C0 : *a = no decomp, -> RIGHT; return true; case 0xA9C0u : *a = no decomp, -> RIGHT; return true;
case 0x111BF : *a = no decomp, -> ABOVE; return true; case 0x111BuF : *a = no decomp, -> ABOVE; return true;
#endif #endif
} }
if ((ab == 0x0DDA || hb_in_range<hb_codepoint_t> (ab, 0x0DDC, 0x0DDE))) if ((ab == 0x0DDAu || hb_in_range (ab, 0x0DDCu, 0x0DDEu)))
{ {
/* /*
* Sinhala split matras... Let the fun begin. * Sinhala split matras... Let the fun begin.
@ -1766,7 +1841,7 @@ decompose_indic (const hb_ot_shape_normalize_context_t *c,
indic_plan->pstf.would_substitute (&glyph, 1, c->font->face))) indic_plan->pstf.would_substitute (&glyph, 1, c->font->face)))
{ {
/* Ok, safe to use Uniscribe-style decomposition. */ /* Ok, safe to use Uniscribe-style decomposition. */
*a = 0x0DD9; *a = 0x0DD9u;
*b = ab; *b = ab;
return true; return true;
} }
@ -1786,7 +1861,7 @@ compose_indic (const hb_ot_shape_normalize_context_t *c,
return false; return false;
/* Composition-exclusion exceptions that we want to recompose. */ /* Composition-exclusion exceptions that we want to recompose. */
if (a == 0x09AF && b == 0x09BC) { *ab = 0x09DF; return true; } if (a == 0x09AFu && b == 0x09BCu) { *ab = 0x09DFu; return true; }
return c->unicode->compose (a, b, ab); return c->unicode->compose (a, b, ab);
} }

View File

@ -62,7 +62,7 @@ static const short _myanmar_syllable_machine_index_offsets[] = {
static const char _myanmar_syllable_machine_indicies[] = { static const char _myanmar_syllable_machine_indicies[] = {
1, 1, 2, 3, 4, 4, 0, 5, 1, 1, 2, 3, 4, 4, 0, 5,
0, 6, 0, 1, 0, 0, 0, 7, 0, 6, 1, 0, 0, 0, 0, 7,
0, 8, 1, 0, 9, 10, 11, 12, 0, 8, 1, 0, 9, 10, 11, 12,
13, 14, 15, 16, 17, 18, 19, 0, 13, 14, 15, 16, 17, 18, 19, 0,
21, 22, 23, 23, 20, 24, 20, 25, 21, 22, 23, 23, 20, 24, 20, 25,
@ -119,14 +119,14 @@ static const char _myanmar_syllable_machine_indicies[] = {
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
20, 31, 20, 33, 20, 35, 20, 21, 20, 31, 20, 33, 20, 35, 20, 21,
20, 23, 23, 20, 24, 20, 25, 20, 20, 23, 23, 20, 24, 20, 25, 20,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 34, 20,
20, 27, 20, 29, 20, 31, 32, 33, 20, 27, 20, 29, 20, 31, 32, 33,
34, 35, 20, 21, 20, 23, 23, 20, 34, 35, 20, 21, 20, 23, 23, 20,
24, 20, 25, 20, 20, 20, 20, 20, 24, 20, 25, 20, 20, 20, 20, 20,
20, 20, 34, 20, 20, 27, 20, 20, 20, 20, 34, 20, 20, 27, 20, 20,
20, 31, 32, 33, 34, 35, 20, 21, 20, 31, 32, 33, 34, 35, 20, 21,
20, 23, 23, 20, 24, 20, 25, 20, 20, 23, 23, 20, 24, 20, 25, 20,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 34, 20,
20, 27, 28, 29, 20, 31, 32, 33, 20, 27, 28, 29, 20, 31, 32, 33,
34, 35, 20, 21, 22, 23, 23, 20, 34, 35, 20, 21, 22, 23, 23, 20,
24, 20, 25, 20, 20, 20, 20, 20, 24, 20, 25, 20, 20, 20, 20, 20,
@ -169,8 +169,8 @@ static const char _myanmar_syllable_machine_indicies[] = {
25, 20, 20, 20, 20, 20, 20, 20, 25, 20, 20, 20, 20, 20, 20, 20,
26, 20, 20, 27, 28, 29, 30, 31, 26, 20, 20, 27, 28, 29, 30, 31,
32, 33, 34, 35, 20, 1, 1, 2, 32, 33, 34, 35, 20, 1, 1, 2,
3, 3, 3, 42, 5, 42, 6, 42, 3, 3, 3, 42, 5, 42, 6, 1,
1, 42, 42, 42, 1, 42, 8, 1, 42, 42, 42, 42, 1, 42, 8, 1,
42, 9, 10, 11, 12, 13, 14, 15, 42, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 42, 2, 42, 3, 3, 16, 17, 18, 42, 2, 42, 3, 3,
42, 5, 42, 6, 42, 42, 42, 42, 42, 5, 42, 6, 42, 42, 42, 42,
@ -191,14 +191,14 @@ static const char _myanmar_syllable_machine_indicies[] = {
42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
42, 42, 13, 42, 15, 42, 17, 42, 42, 42, 13, 42, 15, 42, 17, 42,
2, 42, 3, 3, 42, 5, 42, 6, 2, 42, 3, 3, 42, 5, 42, 6,
42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 16,
42, 42, 9, 42, 11, 42, 13, 14, 42, 42, 9, 42, 11, 42, 13, 14,
15, 16, 17, 42, 2, 42, 3, 3, 15, 16, 17, 42, 2, 42, 3, 3,
42, 5, 42, 6, 42, 42, 42, 42, 42, 5, 42, 6, 42, 42, 42, 42,
42, 42, 42, 16, 42, 42, 9, 42, 42, 42, 42, 16, 42, 42, 9, 42,
42, 42, 13, 14, 15, 16, 17, 42, 42, 42, 13, 14, 15, 16, 17, 42,
2, 42, 3, 3, 42, 5, 42, 6, 2, 42, 3, 3, 42, 5, 42, 6,
42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 16,
42, 42, 9, 10, 11, 42, 13, 14, 42, 42, 9, 10, 11, 42, 13, 14,
15, 16, 17, 42, 2, 3, 3, 3, 15, 16, 17, 42, 2, 3, 3, 3,
42, 5, 42, 6, 42, 42, 42, 42, 42, 5, 42, 6, 42, 42, 42, 42,

View File

@ -44,7 +44,7 @@ C = 1;
D = 19; D = 19;
D0 = 20; D0 = 20;
DB = 3; DB = 3;
GB = 12; GB = 11;
H = 4; H = 4;
IV = 2; IV = 2;
MH = 21; MH = 21;
@ -68,7 +68,7 @@ k = (Ra As H); # Kinzi
c = C|Ra; # is_consonant c = C|Ra; # is_consonant
medial_group = MY? MR? ((MW MH? | MH) As?)?; medial_group = MY? MR? MW? MH? As?;
main_vowel_group = VPre* VAbv* VBlw* A* (DB As?)?; main_vowel_group = VPre* VAbv* VBlw* A* (DB As?)?;
post_vowel_group = VPst MH? As* VAbv* A* (DB As?)?; post_vowel_group = VPst MH? As* VAbv* A* (DB As?)?;
pwo_tone_group = PT A* DB? As?; pwo_tone_group = PT A* DB? As?;

View File

@ -134,7 +134,7 @@ enum myanmar_category_t {
OT_D = 19, /* Digits except zero */ OT_D = 19, /* Digits except zero */
OT_D0 = 20, /* Digit zero */ OT_D0 = 20, /* Digit zero */
OT_DB = OT_N, /* Dot below */ OT_DB = OT_N, /* Dot below */
OT_GB = OT_DOTTEDCIRCLE, OT_GB = OT_PLACEHOLDER,
OT_MH = 21, /* Various consonant medial types */ OT_MH = 21, /* Various consonant medial types */
OT_MR = 22, /* Various consonant medial types */ OT_MR = 22, /* Various consonant medial types */
OT_MW = 23, /* Various consonant medial types */ OT_MW = 23, /* Various consonant medial types */
@ -157,12 +157,6 @@ is_one_of (const hb_glyph_info_t &info, unsigned int flags)
return !!(FLAG (info.myanmar_category()) & flags); return !!(FLAG (info.myanmar_category()) & flags);
} }
/* Note:
*
* We treat Vowels and placeholders as if they were consonants. This is safe because Vowels
* cannot happen in a consonant syllable. The plus side however is, we can call the
* consonant syllable logic from the vowel syllable function and get it all right! */
#define CONSONANT_FLAGS (FLAG (OT_C) | FLAG (OT_CM) | FLAG (OT_Ra) | FLAG (OT_V) | FLAG (OT_NBSP) | FLAG (OT_GB))
static inline bool static inline bool
is_consonant (const hb_glyph_info_t &info) is_consonant (const hb_glyph_info_t &info)
{ {
@ -175,82 +169,80 @@ set_myanmar_properties (hb_glyph_info_t &info)
{ {
hb_codepoint_t u = info.codepoint; hb_codepoint_t u = info.codepoint;
unsigned int type = hb_indic_get_categories (u); unsigned int type = hb_indic_get_categories (u);
indic_category_t cat = (indic_category_t) (type & 0x7F); indic_category_t cat = (indic_category_t) (type & 0x7Fu);
indic_position_t pos = (indic_position_t) (type >> 8); indic_position_t pos = (indic_position_t) (type >> 8);
/* Myanmar /* Myanmar
* http://www.microsoft.com/typography/OpenTypeDev/myanmar/intro.htm#analyze * http://www.microsoft.com/typography/OpenTypeDev/myanmar/intro.htm#analyze
*/ */
if (unlikely (hb_in_range<hb_codepoint_t> (u, 0xFE00, 0xFE0F))) if (unlikely (hb_in_range (u, 0xFE00u, 0xFE0Fu)))
cat = (indic_category_t) OT_VS; cat = (indic_category_t) OT_VS;
else if (unlikely (u == 0x200C)) cat = (indic_category_t) OT_ZWNJ;
else if (unlikely (u == 0x200D)) cat = (indic_category_t) OT_ZWJ;
switch (u) switch (u)
{ {
case 0x104E: case 0x104Eu:
cat = (indic_category_t) OT_C; /* The spec says C, IndicSyllableCategory doesn't have. */ cat = (indic_category_t) OT_C; /* The spec says C, IndicSyllableCategory doesn't have. */
break; break;
case 0x002D: case 0x00A0: case 0x00D7: case 0x2012: case 0x002Du: case 0x00A0u: case 0x00D7u: case 0x2012u:
case 0x2013: case 0x2014: case 0x2015: case 0x2022: case 0x2013u: case 0x2014u: case 0x2015u: case 0x2022u:
case 0x25CC: case 0x25FB: case 0x25FC: case 0x25FD: case 0x25CCu: case 0x25FBu: case 0x25FCu: case 0x25FDu:
case 0x25FE: case 0x25FEu:
cat = (indic_category_t) OT_GB; cat = (indic_category_t) OT_GB;
break; break;
case 0x1004: case 0x101B: case 0x105A: case 0x1004u: case 0x101Bu: case 0x105Au:
cat = (indic_category_t) OT_Ra; cat = (indic_category_t) OT_Ra;
break; break;
case 0x1032: case 0x1036: case 0x1032u: case 0x1036u:
cat = (indic_category_t) OT_A; cat = (indic_category_t) OT_A;
break; break;
case 0x103A: case 0x103Au:
cat = (indic_category_t) OT_As; cat = (indic_category_t) OT_As;
break; break;
case 0x1041: case 0x1042: case 0x1043: case 0x1044: case 0x1041u: case 0x1042u: case 0x1043u: case 0x1044u:
case 0x1045: case 0x1046: case 0x1047: case 0x1048: case 0x1045u: case 0x1046u: case 0x1047u: case 0x1048u:
case 0x1049: case 0x1090: case 0x1091: case 0x1092: case 0x1049u: case 0x1090u: case 0x1091u: case 0x1092u:
case 0x1093: case 0x1094: case 0x1095: case 0x1096: case 0x1093u: case 0x1094u: case 0x1095u: case 0x1096u:
case 0x1097: case 0x1098: case 0x1099: case 0x1097u: case 0x1098u: case 0x1099u:
cat = (indic_category_t) OT_D; cat = (indic_category_t) OT_D;
break; break;
case 0x1040: case 0x1040u:
cat = (indic_category_t) OT_D; /* XXX The spec says D0, but Uniscribe doesn't seem to do. */ cat = (indic_category_t) OT_D; /* XXX The spec says D0, but Uniscribe doesn't seem to do. */
break; break;
case 0x103E: case 0x1060: case 0x103Eu: case 0x1060u:
cat = (indic_category_t) OT_MH; cat = (indic_category_t) OT_MH;
break; break;
case 0x103C: case 0x103Cu:
cat = (indic_category_t) OT_MR; cat = (indic_category_t) OT_MR;
break; break;
case 0x103D: case 0x1082: case 0x103Du: case 0x1082u:
cat = (indic_category_t) OT_MW; cat = (indic_category_t) OT_MW;
break; break;
case 0x103B: case 0x105E: case 0x105F: case 0x103Bu: case 0x105Eu: case 0x105Fu:
cat = (indic_category_t) OT_MY; cat = (indic_category_t) OT_MY;
break; break;
case 0x1063: case 0x1064: case 0x1069: case 0x106A: case 0x1063u: case 0x1064u: case 0x1069u: case 0x106Au:
case 0x106B: case 0x106C: case 0x106D: case 0xAA7B: case 0x106Bu: case 0x106Cu: case 0x106Du: case 0xAA7Bu:
cat = (indic_category_t) OT_PT; cat = (indic_category_t) OT_PT;
break; break;
case 0x1038: case 0x1087: case 0x1088: case 0x1089: case 0x1038u: case 0x1087u: case 0x1088u: case 0x1089u:
case 0x108A: case 0x108B: case 0x108C: case 0x108D: case 0x108Au: case 0x108Bu: case 0x108Cu: case 0x108Du:
case 0x108F: case 0x109A: case 0x109B: case 0x109C: case 0x108Fu: case 0x109Au: case 0x109Bu: case 0x109Cu:
cat = (indic_category_t) OT_SM; cat = (indic_category_t) OT_SM;
break; break;
case 0x104A: case 0x104B: case 0x104Au: case 0x104Bu:
cat = (indic_category_t) OT_P; cat = (indic_category_t) OT_P;
break; break;
} }
@ -285,8 +277,9 @@ setup_masks_myanmar (const hb_ot_shape_plan_t *plan HB_UNUSED,
* and setup masks later on in a pause-callback. */ * and setup masks later on in a pause-callback. */
unsigned int count = buffer->len; unsigned int count = buffer->len;
hb_glyph_info_t *info = buffer->info;
for (unsigned int i = 0; i < count; i++) for (unsigned int i = 0; i < count; i++)
set_myanmar_properties (buffer->info[i]); set_myanmar_properties (info[i]);
} }
static void static void
@ -459,8 +452,10 @@ insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED,
/* Note: This loop is extra overhead, but should not be measurable. */ /* Note: This loop is extra overhead, but should not be measurable. */
bool has_broken_syllables = false; bool has_broken_syllables = false;
unsigned int count = buffer->len; unsigned int count = buffer->len;
hb_glyph_info_t *info = buffer->info;
for (unsigned int i = 0; i < count; i++) for (unsigned int i = 0; i < count; i++)
if ((buffer->info[i].syllable() & 0x0F) == broken_cluster) { if ((info[i].syllable() & 0x0F) == broken_cluster)
{
has_broken_syllables = true; has_broken_syllables = true;
break; break;
} }
@ -469,11 +464,11 @@ insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED,
hb_codepoint_t dottedcircle_glyph; hb_codepoint_t dottedcircle_glyph;
if (!font->get_glyph (0x25CC, 0, &dottedcircle_glyph)) if (!font->get_glyph (0x25CCu, 0, &dottedcircle_glyph))
return; return;
hb_glyph_info_t dottedcircle = {0}; hb_glyph_info_t dottedcircle = {0};
dottedcircle.codepoint = 0x25CC; dottedcircle.codepoint = 0x25CCu;
set_myanmar_properties (dottedcircle); set_myanmar_properties (dottedcircle);
dottedcircle.codepoint = dottedcircle_glyph; dottedcircle.codepoint = dottedcircle_glyph;
@ -541,6 +536,24 @@ final_reordering (const hb_ot_shape_plan_t *plan,
} }
/* Uniscribe seems to have a shaper for 'mymr' that is like the
* generic shaper, except that it zeros mark advances GDEF_LATE. */
const hb_ot_complex_shaper_t _hb_ot_complex_shaper_myanmar_old =
{
"default",
NULL, /* collect_features */
NULL, /* override_features */
NULL, /* data_create */
NULL, /* data_destroy */
NULL, /* preprocess_text */
HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
NULL, /* decompose */
NULL, /* compose */
NULL, /* setup_masks */
HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
true, /* fallback_position */
};
const hb_ot_complex_shaper_t _hb_ot_complex_shaper_myanmar = const hb_ot_complex_shaper_t _hb_ot_complex_shaper_myanmar =
{ {
"myanmar", "myanmar",

View File

@ -56,6 +56,7 @@ enum hb_ot_shape_zero_width_marks_type_t {
HB_COMPLEX_SHAPER_IMPLEMENT (arabic) \ HB_COMPLEX_SHAPER_IMPLEMENT (arabic) \
HB_COMPLEX_SHAPER_IMPLEMENT (hangul) \ HB_COMPLEX_SHAPER_IMPLEMENT (hangul) \
HB_COMPLEX_SHAPER_IMPLEMENT (hebrew) \ HB_COMPLEX_SHAPER_IMPLEMENT (hebrew) \
HB_COMPLEX_SHAPER_IMPLEMENT (myanmar_old) \
HB_COMPLEX_SHAPER_IMPLEMENT (indic) \ HB_COMPLEX_SHAPER_IMPLEMENT (indic) \
HB_COMPLEX_SHAPER_IMPLEMENT (myanmar) \ HB_COMPLEX_SHAPER_IMPLEMENT (myanmar) \
HB_COMPLEX_SHAPER_IMPLEMENT (sea) \ HB_COMPLEX_SHAPER_IMPLEMENT (sea) \
@ -173,6 +174,10 @@ hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner)
/* Unicode-6.0 additions */ /* Unicode-6.0 additions */
case HB_SCRIPT_MANDAIC: case HB_SCRIPT_MANDAIC:
/* Unicode-7.0 additions */
case HB_SCRIPT_MANICHAEAN:
case HB_SCRIPT_PSALTER_PAHLAVI:
/* For Arabic script, use the Arabic shaper even if no OT script tag was found. /* For Arabic script, use the Arabic shaper even if no OT script tag was found.
* This is because we do fallback shaping for Arabic script (and not others). */ * This is because we do fallback shaping for Arabic script (and not others). */
if (planner->map.chosen_script[0] != HB_OT_TAG_DEFAULT_SCRIPT || if (planner->map.chosen_script[0] != HB_OT_TAG_DEFAULT_SCRIPT ||
@ -325,10 +330,10 @@ hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner)
return &_hb_ot_complex_shaper_default; return &_hb_ot_complex_shaper_default;
case HB_SCRIPT_MYANMAR: case HB_SCRIPT_MYANMAR:
/* For Myanmar, we only want to use the Myanmar shaper if the "new" script
* tag is found. For "old" script tag we want to use the default shaper. */
if (planner->map.chosen_script[0] == HB_TAG ('m','y','m','2')) if (planner->map.chosen_script[0] == HB_TAG ('m','y','m','2'))
return &_hb_ot_complex_shaper_myanmar; return &_hb_ot_complex_shaper_myanmar;
else if (planner->map.chosen_script[0] == HB_TAG ('m','y','m','r'))
return &_hb_ot_complex_shaper_myanmar_old;
else else
return &_hb_ot_complex_shaper_default; return &_hb_ot_complex_shaper_default;

View File

@ -139,11 +139,11 @@ set_sea_properties (hb_glyph_info_t &info)
{ {
hb_codepoint_t u = info.codepoint; hb_codepoint_t u = info.codepoint;
unsigned int type = hb_indic_get_categories (u); unsigned int type = hb_indic_get_categories (u);
indic_category_t cat = (indic_category_t) (type & 0x7F); indic_category_t cat = (indic_category_t) (type & 0x7Fu);
indic_position_t pos = (indic_position_t) (type >> 8); indic_position_t pos = (indic_position_t) (type >> 8);
/* Medial Ra */ /* Medial Ra */
if (u == 0x1A55 || u == 0xAA34) if (u == 0x1A55u || u == 0xAA34u)
cat = (indic_category_t) OT_MR; cat = (indic_category_t) OT_MR;
if (cat == OT_M) if (cat == OT_M)
@ -174,8 +174,9 @@ setup_masks_sea (const hb_ot_shape_plan_t *plan HB_UNUSED,
* and setup masks later on in a pause-callback. */ * and setup masks later on in a pause-callback. */
unsigned int count = buffer->len; unsigned int count = buffer->len;
hb_glyph_info_t *info = buffer->info;
for (unsigned int i = 0; i < count; i++) for (unsigned int i = 0; i < count; i++)
set_sea_properties (buffer->info[i]); set_sea_properties (info[i]);
} }
static void static void
@ -278,8 +279,10 @@ insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED,
/* Note: This loop is extra overhead, but should not be measurable. */ /* Note: This loop is extra overhead, but should not be measurable. */
bool has_broken_syllables = false; bool has_broken_syllables = false;
unsigned int count = buffer->len; unsigned int count = buffer->len;
hb_glyph_info_t *info = buffer->info;
for (unsigned int i = 0; i < count; i++) for (unsigned int i = 0; i < count; i++)
if ((buffer->info[i].syllable() & 0x0F) == broken_cluster) { if ((info[i].syllable() & 0x0F) == broken_cluster)
{
has_broken_syllables = true; has_broken_syllables = true;
break; break;
} }
@ -288,11 +291,11 @@ insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED,
hb_codepoint_t dottedcircle_glyph; hb_codepoint_t dottedcircle_glyph;
if (!font->get_glyph (0x25CC, 0, &dottedcircle_glyph)) if (!font->get_glyph (0x25CCu, 0, &dottedcircle_glyph))
return; return;
hb_glyph_info_t dottedcircle = {0}; hb_glyph_info_t dottedcircle = {0};
dottedcircle.codepoint = 0x25CC; dottedcircle.codepoint = 0x25CCu;
set_sea_properties (dottedcircle); set_sea_properties (dottedcircle);
dottedcircle.codepoint = dottedcircle_glyph; dottedcircle.codepoint = dottedcircle_glyph;

View File

@ -46,13 +46,13 @@ enum thai_consonant_type_t
static thai_consonant_type_t static thai_consonant_type_t
get_consonant_type (hb_codepoint_t u) get_consonant_type (hb_codepoint_t u)
{ {
if (u == 0x0E1B || u == 0x0E1D || u == 0x0E1F/* || u == 0x0E2C*/) if (u == 0x0E1Bu || u == 0x0E1Du || u == 0x0E1Fu/* || u == 0x0E2Cu*/)
return AC; return AC;
if (u == 0x0E0D || u == 0x0E10) if (u == 0x0E0Du || u == 0x0E10u)
return RC; return RC;
if (u == 0x0E0E || u == 0x0E0F) if (u == 0x0E0Eu || u == 0x0E0Fu)
return DC; return DC;
if (hb_in_range<hb_codepoint_t> (u, 0x0E01, 0x0E2E)) if (hb_in_range (u, 0x0E01u, 0x0E2Eu))
return NC; return NC;
return NOT_CONSONANT; return NOT_CONSONANT;
} }
@ -70,12 +70,12 @@ enum thai_mark_type_t
static thai_mark_type_t static thai_mark_type_t
get_mark_type (hb_codepoint_t u) get_mark_type (hb_codepoint_t u)
{ {
if (u == 0x0E31 || hb_in_range<hb_codepoint_t> (u, 0x0E34, 0x0E37) || if (u == 0x0E31u || hb_in_range (u, 0x0E34u, 0x0E37u) ||
u == 0x0E47 || hb_in_range<hb_codepoint_t> (u, 0x0E4D, 0x0E4E)) u == 0x0E47u || hb_in_range (u, 0x0E4Du, 0x0E4Eu))
return AV; return AV;
if (hb_in_range<hb_codepoint_t> (u, 0x0E38, 0x0E3A)) if (hb_in_range (u, 0x0E38u, 0x0E3Au))
return BV; return BV;
if (hb_in_range<hb_codepoint_t> (u, 0x0E48, 0x0E4C)) if (hb_in_range (u, 0x0E48u, 0x0E4Cu))
return T; return T;
return NOT_MARK; return NOT_MARK;
} }
@ -99,43 +99,43 @@ thai_pua_shape (hb_codepoint_t u, thai_action_t action, hb_font_t *font)
hb_codepoint_t mac_pua; hb_codepoint_t mac_pua;
} const *pua_mappings = NULL; } const *pua_mappings = NULL;
static const thai_pua_mapping_t SD_mappings[] = { static const thai_pua_mapping_t SD_mappings[] = {
{0x0E48, 0xF70A, 0xF88B}, /* MAI EK */ {0x0E48u, 0xF70Au, 0xF88Bu}, /* MAI EK */
{0x0E49, 0xF70B, 0xF88E}, /* MAI THO */ {0x0E49u, 0xF70Bu, 0xF88Eu}, /* MAI THO */
{0x0E4A, 0xF70C, 0xF891}, /* MAI TRI */ {0x0E4Au, 0xF70Cu, 0xF891u}, /* MAI TRI */
{0x0E4B, 0xF70D, 0xF894}, /* MAI CHATTAWA */ {0x0E4Bu, 0xF70Du, 0xF894u}, /* MAI CHATTAWA */
{0x0E4C, 0xF70E, 0xF897}, /* THANTHAKHAT */ {0x0E4Cu, 0xF70Eu, 0xF897u}, /* THANTHAKHAT */
{0x0E38, 0xF718, 0xF89B}, /* SARA U */ {0x0E38u, 0xF718u, 0xF89Bu}, /* SARA U */
{0x0E39, 0xF719, 0xF89C}, /* SARA UU */ {0x0E39u, 0xF719u, 0xF89Cu}, /* SARA UU */
{0x0E3A, 0xF71A, 0xF89D}, /* PHINTHU */ {0x0E3Au, 0xF71Au, 0xF89Du}, /* PHINTHU */
{0x0000, 0x0000, 0x0000} {0x0000u, 0x0000u, 0x0000u}
}; };
static const thai_pua_mapping_t SDL_mappings[] = { static const thai_pua_mapping_t SDL_mappings[] = {
{0x0E48, 0xF705, 0xF88C}, /* MAI EK */ {0x0E48u, 0xF705u, 0xF88Cu}, /* MAI EK */
{0x0E49, 0xF706, 0xF88F}, /* MAI THO */ {0x0E49u, 0xF706u, 0xF88Fu}, /* MAI THO */
{0x0E4A, 0xF707, 0xF892}, /* MAI TRI */ {0x0E4Au, 0xF707u, 0xF892u}, /* MAI TRI */
{0x0E4B, 0xF708, 0xF895}, /* MAI CHATTAWA */ {0x0E4Bu, 0xF708u, 0xF895u}, /* MAI CHATTAWA */
{0x0E4C, 0xF709, 0xF898}, /* THANTHAKHAT */ {0x0E4Cu, 0xF709u, 0xF898u}, /* THANTHAKHAT */
{0x0000, 0x0000, 0x0000} {0x0000u, 0x0000u, 0x0000u}
}; };
static const thai_pua_mapping_t SL_mappings[] = { static const thai_pua_mapping_t SL_mappings[] = {
{0x0E48, 0xF713, 0xF88A}, /* MAI EK */ {0x0E48u, 0xF713u, 0xF88Au}, /* MAI EK */
{0x0E49, 0xF714, 0xF88D}, /* MAI THO */ {0x0E49u, 0xF714u, 0xF88Du}, /* MAI THO */
{0x0E4A, 0xF715, 0xF890}, /* MAI TRI */ {0x0E4Au, 0xF715u, 0xF890u}, /* MAI TRI */
{0x0E4B, 0xF716, 0xF893}, /* MAI CHATTAWA */ {0x0E4Bu, 0xF716u, 0xF893u}, /* MAI CHATTAWA */
{0x0E4C, 0xF717, 0xF896}, /* THANTHAKHAT */ {0x0E4Cu, 0xF717u, 0xF896u}, /* THANTHAKHAT */
{0x0E31, 0xF710, 0xF884}, /* MAI HAN-AKAT */ {0x0E31u, 0xF710u, 0xF884u}, /* MAI HAN-AKAT */
{0x0E34, 0xF701, 0xF885}, /* SARA I */ {0x0E34u, 0xF701u, 0xF885u}, /* SARA I */
{0x0E35, 0xF702, 0xF886}, /* SARA II */ {0x0E35u, 0xF702u, 0xF886u}, /* SARA II */
{0x0E36, 0xF703, 0xF887}, /* SARA UE */ {0x0E36u, 0xF703u, 0xF887u}, /* SARA UE */
{0x0E37, 0xF704, 0xF888}, /* SARA UEE */ {0x0E37u, 0xF704u, 0xF888u}, /* SARA UEE */
{0x0E47, 0xF712, 0xF889}, /* MAITAIKHU */ {0x0E47u, 0xF712u, 0xF889u}, /* MAITAIKHU */
{0x0E4D, 0xF711, 0xF899}, /* NIKHAHIT */ {0x0E4Du, 0xF711u, 0xF899u}, /* NIKHAHIT */
{0x0000, 0x0000, 0x0000} {0x0000u, 0x0000u, 0x0000u}
}; };
static const thai_pua_mapping_t RD_mappings[] = { static const thai_pua_mapping_t RD_mappings[] = {
{0x0E0D, 0xF70F, 0xF89A}, /* YO YING */ {0x0E0Du, 0xF70Fu, 0xF89Au}, /* YO YING */
{0x0E10, 0xF700, 0xF89E}, /* THO THAN */ {0x0E10u, 0xF700u, 0xF89Eu}, /* THO THAN */
{0x0000, 0x0000, 0x0000} {0x0000u, 0x0000u, 0x0000u}
}; };
switch (action) { switch (action) {
@ -308,10 +308,10 @@ preprocess_text_thai (const hb_ot_shape_plan_t *plan,
/* We only get one script at a time, so a script-agnostic implementation /* We only get one script at a time, so a script-agnostic implementation
* is adequate here. */ * is adequate here. */
#define IS_SARA_AM(x) (((x) & ~0x0080) == 0x0E33) #define IS_SARA_AM(x) (((x) & ~0x0080u) == 0x0E33u)
#define NIKHAHIT_FROM_SARA_AM(x) ((x) - 0xE33 + 0xE4D) #define NIKHAHIT_FROM_SARA_AM(x) ((x) - 0x0E33u + 0x0E4Du)
#define SARA_AA_FROM_SARA_AM(x) ((x) - 1) #define SARA_AA_FROM_SARA_AM(x) ((x) - 1)
#define IS_TONE_MARK(x) (hb_in_ranges<hb_codepoint_t> ((x) & ~0x0080, 0x0E34, 0x0E37, 0x0E47, 0x0E4E, 0x0E31, 0x0E31)) #define IS_TONE_MARK(x) (hb_in_ranges ((x) & ~0x0080u, 0x0E34u, 0x0E37u, 0x0E47u, 0x0E4Eu, 0x0E31u, 0x0E31u))
buffer->clear_output (); buffer->clear_output ();
unsigned int count = buffer->len; unsigned int count = buffer->len;

View File

@ -35,42 +35,42 @@ recategorize_combining_class (hb_codepoint_t u,
return klass; return klass;
/* Thai / Lao need some per-character work. */ /* Thai / Lao need some per-character work. */
if ((u & ~0xFF) == 0x0E00) if ((u & ~0xFF) == 0x0E00u)
{ {
if (unlikely (klass == 0)) if (unlikely (klass == 0))
{ {
switch (u) switch (u)
{ {
case 0x0E31: case 0x0E31u:
case 0x0E34: case 0x0E34u:
case 0x0E35: case 0x0E35u:
case 0x0E36: case 0x0E36u:
case 0x0E37: case 0x0E37u:
case 0x0E47: case 0x0E47u:
case 0x0E4C: case 0x0E4Cu:
case 0x0E4D: case 0x0E4Du:
case 0x0E4E: case 0x0E4Eu:
klass = HB_UNICODE_COMBINING_CLASS_ABOVE_RIGHT; klass = HB_UNICODE_COMBINING_CLASS_ABOVE_RIGHT;
break; break;
case 0x0EB1: case 0x0EB1u:
case 0x0EB4: case 0x0EB4u:
case 0x0EB5: case 0x0EB5u:
case 0x0EB6: case 0x0EB6u:
case 0x0EB7: case 0x0EB7u:
case 0x0EBB: case 0x0EBBu:
case 0x0ECC: case 0x0ECCu:
case 0x0ECD: case 0x0ECDu:
klass = HB_UNICODE_COMBINING_CLASS_ABOVE; klass = HB_UNICODE_COMBINING_CLASS_ABOVE;
break; break;
case 0x0EBC: case 0x0EBCu:
klass = HB_UNICODE_COMBINING_CLASS_BELOW; klass = HB_UNICODE_COMBINING_CLASS_BELOW;
break; break;
} }
} else { } else {
/* Thai virama is below-right */ /* Thai virama is below-right */
if (u == 0x0E3A) if (u == 0x0E3Au)
klass = HB_UNICODE_COMBINING_CLASS_BELOW_RIGHT; klass = HB_UNICODE_COMBINING_CLASS_BELOW_RIGHT;
} }
} }
@ -167,11 +167,12 @@ _hb_ot_shape_fallback_position_recategorize_marks (const hb_ot_shape_plan_t *pla
hb_buffer_t *buffer) hb_buffer_t *buffer)
{ {
unsigned int count = buffer->len; unsigned int count = buffer->len;
hb_glyph_info_t *info = buffer->info;
for (unsigned int i = 0; i < count; i++) for (unsigned int i = 0; i < count; i++)
if (_hb_glyph_info_get_general_category (&buffer->info[i]) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) { if (_hb_glyph_info_get_general_category (&info[i]) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) {
unsigned int combining_class = _hb_glyph_info_get_modified_combining_class (&buffer->info[i]); unsigned int combining_class = _hb_glyph_info_get_modified_combining_class (&info[i]);
combining_class = recategorize_combining_class (buffer->info[i].codepoint, combining_class); combining_class = recategorize_combining_class (info[i].codepoint, combining_class);
_hb_glyph_info_set_modified_combining_class (&buffer->info[i], combining_class); _hb_glyph_info_set_modified_combining_class (&info[i], combining_class);
} }
} }
@ -181,8 +182,9 @@ zero_mark_advances (hb_buffer_t *buffer,
unsigned int start, unsigned int start,
unsigned int end) unsigned int end)
{ {
hb_glyph_info_t *info = buffer->info;
for (unsigned int i = start; i < end; i++) for (unsigned int i = start; i < end; i++)
if (_hb_glyph_info_get_general_category (&buffer->info[i]) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) if (_hb_glyph_info_get_general_category (&info[i]) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
{ {
buffer->pos[i].x_advance = 0; buffer->pos[i].x_advance = 0;
buffer->pos[i].y_advance = 0; buffer->pos[i].y_advance = 0;
@ -327,12 +329,13 @@ position_around_base (const hb_ot_shape_plan_t *plan,
unsigned int last_lig_component = (unsigned int) -1; unsigned int last_lig_component = (unsigned int) -1;
unsigned int last_combining_class = 255; unsigned int last_combining_class = 255;
hb_glyph_extents_t cluster_extents = base_extents; /* Initialization is just to shut gcc up. */ hb_glyph_extents_t cluster_extents = base_extents; /* Initialization is just to shut gcc up. */
hb_glyph_info_t *info = buffer->info;
for (unsigned int i = base + 1; i < end; i++) for (unsigned int i = base + 1; i < end; i++)
if (_hb_glyph_info_get_modified_combining_class (&buffer->info[i])) if (_hb_glyph_info_get_modified_combining_class (&info[i]))
{ {
if (num_lig_components > 1) { if (num_lig_components > 1) {
unsigned int this_lig_id = _hb_glyph_info_get_lig_id (&buffer->info[i]); unsigned int this_lig_id = _hb_glyph_info_get_lig_id (&info[i]);
unsigned int this_lig_component = _hb_glyph_info_get_lig_comp (&buffer->info[i]) - 1; unsigned int this_lig_component = _hb_glyph_info_get_lig_comp (&info[i]) - 1;
/* Conditions for attaching to the last component. */ /* Conditions for attaching to the last component. */
if (!lig_id || lig_id != this_lig_id || this_lig_component >= num_lig_components) if (!lig_id || lig_id != this_lig_id || this_lig_component >= num_lig_components)
this_lig_component = num_lig_components - 1; this_lig_component = num_lig_components - 1;
@ -355,7 +358,7 @@ position_around_base (const hb_ot_shape_plan_t *plan,
} }
} }
unsigned int this_combining_class = _hb_glyph_info_get_modified_combining_class (&buffer->info[i]); unsigned int this_combining_class = _hb_glyph_info_get_modified_combining_class (&info[i]);
if (last_combining_class != this_combining_class) if (last_combining_class != this_combining_class)
{ {
last_combining_class = this_combining_class; last_combining_class = this_combining_class;
@ -391,13 +394,14 @@ position_cluster (const hb_ot_shape_plan_t *plan,
return; return;
/* Find the base glyph */ /* Find the base glyph */
hb_glyph_info_t *info = buffer->info;
for (unsigned int i = start; i < end; i++) for (unsigned int i = start; i < end; i++)
if (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&buffer->info[i]))) if (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info[i])))
{ {
/* Find mark glyphs */ /* Find mark glyphs */
unsigned int j; unsigned int j;
for (j = i + 1; j < end; j++) for (j = i + 1; j < end; j++)
if (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&buffer->info[j]))) if (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info[j])))
break; break;
position_around_base (plan, font, buffer, i, j); position_around_base (plan, font, buffer, i, j);
@ -411,6 +415,8 @@ _hb_ot_shape_fallback_position (const hb_ot_shape_plan_t *plan,
hb_font_t *font, hb_font_t *font,
hb_buffer_t *buffer) hb_buffer_t *buffer)
{ {
_hb_buffer_assert_gsubgpos_vars (buffer);
unsigned int start = 0; unsigned int start = 0;
unsigned int last_cluster = buffer->info[0].cluster; unsigned int last_cluster = buffer->info[0].cluster;
unsigned int count = buffer->len; unsigned int count = buffer->len;
@ -432,15 +438,13 @@ _hb_ot_shape_fallback_kern (const hb_ot_shape_plan_t *plan,
{ {
if (!plan->has_kern) return; if (!plan->has_kern) return;
unsigned int count = buffer->len;
OT::hb_apply_context_t c (1, font, buffer); OT::hb_apply_context_t c (1, font, buffer);
c.set_lookup_mask (plan->kern_mask); c.set_lookup_mask (plan->kern_mask);
c.set_lookup_props (OT::LookupFlag::IgnoreMarks); c.set_lookup_props (OT::LookupFlag::IgnoreMarks);
unsigned int count = buffer->len;
hb_glyph_info_t *info = buffer->info; hb_glyph_info_t *info = buffer->info;
hb_glyph_position_t *pos = buffer->pos; hb_glyph_position_t *pos = buffer->pos;
for (unsigned int idx = 0; idx < count;) for (unsigned int idx = 0; idx < count;)
{ {
OT::hb_apply_context_t::skipping_forward_iterator_t skippy_iter (&c, idx, 1); OT::hb_apply_context_t::skipping_forward_iterator_t skippy_iter (&c, idx, 1);

View File

@ -289,6 +289,8 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan,
hb_buffer_t *buffer, hb_buffer_t *buffer,
hb_font_t *font) hb_font_t *font)
{ {
_hb_buffer_assert_unicode_vars (buffer);
hb_ot_shape_normalization_mode_t mode = plan->shaper->normalization_preference; hb_ot_shape_normalization_mode_t mode = plan->shaper->normalization_preference;
const hb_ot_shape_normalize_context_t c = { const hb_ot_shape_normalize_context_t c = {
plan, plan,

View File

@ -44,6 +44,7 @@ struct hb_ot_shape_plan_t
hb_mask_t kern_mask; hb_mask_t kern_mask;
unsigned int has_frac : 1; unsigned int has_frac : 1;
unsigned int has_kern : 1; unsigned int has_kern : 1;
unsigned int has_mark : 1;
inline void collect_lookups (hb_tag_t table_tag, hb_set_t *lookups) const inline void collect_lookups (hb_tag_t table_tag, hb_set_t *lookups) const
{ {
@ -92,6 +93,7 @@ struct hb_ot_shape_planner_t
plan.has_frac = plan.frac_mask || (plan.numr_mask && plan.dnom_mask); plan.has_frac = plan.frac_mask || (plan.numr_mask && plan.dnom_mask);
plan.has_kern = !!plan.kern_mask; plan.has_kern = !!plan.kern_mask;
plan.has_mark = !!plan.map.get_1_mask (HB_TAG ('m','a','r','k'));
} }
private: private:

View File

@ -37,12 +37,12 @@
#include "hb-ot-shape-normalize-private.hh" #include "hb-ot-shape-normalize-private.hh"
#include "hb-ot-layout-private.hh" #include "hb-ot-layout-private.hh"
#include "hb-unicode-private.hh"
#include "hb-set-private.hh" #include "hb-set-private.hh"
static hb_tag_t common_features[] = { static hb_tag_t common_features[] = {
HB_TAG('c','c','m','p'), HB_TAG('c','c','m','p'),
HB_TAG('l','i','g','a'),
HB_TAG('l','o','c','l'), HB_TAG('l','o','c','l'),
HB_TAG('m','a','r','k'), HB_TAG('m','a','r','k'),
HB_TAG('m','k','m','k'), HB_TAG('m','k','m','k'),
@ -55,6 +55,7 @@ static hb_tag_t horizontal_features[] = {
HB_TAG('c','l','i','g'), HB_TAG('c','l','i','g'),
HB_TAG('c','u','r','s'), HB_TAG('c','u','r','s'),
HB_TAG('k','e','r','n'), HB_TAG('k','e','r','n'),
HB_TAG('l','i','g','a'),
HB_TAG('r','c','l','t'), HB_TAG('r','c','l','t'),
}; };
@ -226,23 +227,25 @@ static void
hb_set_unicode_props (hb_buffer_t *buffer) hb_set_unicode_props (hb_buffer_t *buffer)
{ {
unsigned int count = buffer->len; unsigned int count = buffer->len;
hb_glyph_info_t *info = buffer->info;
for (unsigned int i = 0; i < count; i++) for (unsigned int i = 0; i < count; i++)
_hb_glyph_info_set_unicode_props (&buffer->info[i], buffer->unicode); _hb_glyph_info_set_unicode_props (&info[i], buffer->unicode);
} }
static void static void
hb_insert_dotted_circle (hb_buffer_t *buffer, hb_font_t *font) hb_insert_dotted_circle (hb_buffer_t *buffer, hb_font_t *font)
{ {
if (!(buffer->flags & HB_BUFFER_FLAG_BOT) || if (!(buffer->flags & HB_BUFFER_FLAG_BOT) ||
buffer->context_len[0] ||
_hb_glyph_info_get_general_category (&buffer->info[0]) != _hb_glyph_info_get_general_category (&buffer->info[0]) !=
HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
return; return;
if (!font->has_glyph (0x25CC)) if (!font->has_glyph (0x25CCu))
return; return;
hb_glyph_info_t dottedcircle; hb_glyph_info_t dottedcircle = {0};
dottedcircle.codepoint = 0x25CC; dottedcircle.codepoint = 0x25CCu;
_hb_glyph_info_set_unicode_props (&dottedcircle, buffer->unicode); _hb_glyph_info_set_unicode_props (&dottedcircle, buffer->unicode);
buffer->clear_output (); buffer->clear_output ();
@ -262,8 +265,9 @@ static void
hb_form_clusters (hb_buffer_t *buffer) hb_form_clusters (hb_buffer_t *buffer)
{ {
unsigned int count = buffer->len; unsigned int count = buffer->len;
hb_glyph_info_t *info = buffer->info;
for (unsigned int i = 1; i < count; i++) for (unsigned int i = 1; i < count; i++)
if (HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&buffer->info[i]))) if (HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info[i])))
buffer->merge_clusters (i - 1, i + 1); buffer->merge_clusters (i - 1, i + 1);
} }
@ -321,7 +325,7 @@ hb_ot_shape_setup_masks_fraction (hb_ot_shape_context_t *c)
hb_glyph_info_t *info = buffer->info; hb_glyph_info_t *info = buffer->info;
for (unsigned int i = 0; i < count; i++) for (unsigned int i = 0; i < count; i++)
{ {
if (info[i].codepoint == 0x2044) /* FRACTION SLASH */ if (info[i].codepoint == 0x2044u) /* FRACTION SLASH */
{ {
unsigned int start = i, end = i + 1; unsigned int start = i, end = i + 1;
while (start && while (start &&
@ -381,8 +385,9 @@ hb_ot_map_glyphs_fast (hb_buffer_t *buffer)
{ {
/* Normalization process sets up glyph_index(), we just copy it. */ /* Normalization process sets up glyph_index(), we just copy it. */
unsigned int count = buffer->len; unsigned int count = buffer->len;
hb_glyph_info_t *info = buffer->info;
for (unsigned int i = 0; i < count; i++) for (unsigned int i = 0; i < count; i++)
buffer->info[i].codepoint = buffer->info[i].glyph_index(); info[i].codepoint = info[i].glyph_index();
} }
static inline void static inline void
@ -391,11 +396,24 @@ hb_synthesize_glyph_classes (hb_ot_shape_context_t *c)
unsigned int count = c->buffer->len; unsigned int count = c->buffer->len;
hb_glyph_info_t *info = c->buffer->info; hb_glyph_info_t *info = c->buffer->info;
for (unsigned int i = 0; i < count; i++) for (unsigned int i = 0; i < count; i++)
_hb_glyph_info_set_glyph_props (&info[i], {
_hb_glyph_info_get_general_category (&info[i]) hb_ot_layout_glyph_class_mask_t klass;
== HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK ?
HB_OT_LAYOUT_GLYPH_PROPS_MARK : /* Never mark default-ignorables as marks.
HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH); * They won't get in the way of lookups anyway,
* but having them as mark will cause them to be skipped
* over if the lookup-flag says so, but at least for the
* Mongolian variation selectors, looks like Uniscribe
* marks them as non-mark. Some Mongolian fonts without
* GDEF rely on this. Another notable character that
* this applies to is COMBINING GRAPHEME JOINER. */
klass = (_hb_glyph_info_get_general_category (&info[i]) !=
HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK ||
_hb_glyph_info_is_default_ignorable (&info[i])) ?
HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH :
HB_OT_LAYOUT_GLYPH_PROPS_MARK;
_hb_glyph_info_set_glyph_props (&info[i], klass);
}
} }
static inline void static inline void
@ -430,6 +448,7 @@ hb_ot_substitute_complex (hb_ot_shape_context_t *c)
{ {
hb_buffer_t *buffer = c->buffer; hb_buffer_t *buffer = c->buffer;
_hb_buffer_allocate_gsubgpos_vars (buffer);
hb_ot_layout_substitute_start (c->font, buffer); hb_ot_layout_substitute_start (c->font, buffer);
if (!hb_ot_layout_has_glyph_classes (c->face)) if (!hb_ot_layout_has_glyph_classes (c->face))
@ -469,8 +488,9 @@ static inline void
zero_mark_widths_by_unicode (hb_buffer_t *buffer, bool adjust_offsets) zero_mark_widths_by_unicode (hb_buffer_t *buffer, bool adjust_offsets)
{ {
unsigned int count = buffer->len; unsigned int count = buffer->len;
hb_glyph_info_t *info = buffer->info;
for (unsigned int i = 0; i < count; i++) for (unsigned int i = 0; i < count; i++)
if (_hb_glyph_info_get_general_category (&buffer->info[i]) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) if (_hb_glyph_info_get_general_category (&info[i]) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
{ {
if (adjust_offsets) if (adjust_offsets)
adjust_mark_offsets (&buffer->pos[i]); adjust_mark_offsets (&buffer->pos[i]);
@ -482,8 +502,9 @@ static inline void
zero_mark_widths_by_gdef (hb_buffer_t *buffer, bool adjust_offsets) zero_mark_widths_by_gdef (hb_buffer_t *buffer, bool adjust_offsets)
{ {
unsigned int count = buffer->len; unsigned int count = buffer->len;
hb_glyph_info_t *info = buffer->info;
for (unsigned int i = 0; i < count; i++) for (unsigned int i = 0; i < count; i++)
if (_hb_glyph_info_is_mark (&buffer->info[i])) if (_hb_glyph_info_is_mark (&info[i]))
{ {
if (adjust_offsets) if (adjust_offsets)
adjust_mark_offsets (&buffer->pos[i]); adjust_mark_offsets (&buffer->pos[i]);
@ -518,6 +539,15 @@ hb_ot_position_complex (hb_ot_shape_context_t *c)
bool ret = false; bool ret = false;
unsigned int count = c->buffer->len; unsigned int count = c->buffer->len;
bool has_positioning = hb_ot_layout_has_positioning (c->face); bool has_positioning = hb_ot_layout_has_positioning (c->face);
/* If the font has no GPOS, AND, no fallback positioning will
* happen, AND, direction is forward, then when zeroing mark
* widths, we shift the mark with it, such that the mark
* is positioned hanging over the previous glyph. When
* direction is backward we don't shift and it will end up
* hanging over the next glyph after the final reordering.
* If fallback positinoing happens or GPOS is present, we don't
* care.
*/
bool adjust_offsets_when_zeroing = !(has_positioning || c->plan->shaper->fallback_position || bool adjust_offsets_when_zeroing = !(has_positioning || c->plan->shaper->fallback_position ||
HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction)); HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction));
@ -607,6 +637,8 @@ hb_ot_position (hb_ot_shape_context_t *c)
if (fallback) if (fallback)
_hb_ot_shape_fallback_kern (c->plan, c->font, c->buffer); _hb_ot_shape_fallback_kern (c->plan, c->font, c->buffer);
_hb_buffer_deallocate_gsubgpos_vars (c->buffer);
} }
@ -750,8 +782,9 @@ hb_ot_shape_glyphs_closure (hb_font_t *font,
bool mirror = hb_script_get_horizontal_direction (buffer->props.script) == HB_DIRECTION_RTL; bool mirror = hb_script_get_horizontal_direction (buffer->props.script) == HB_DIRECTION_RTL;
unsigned int count = buffer->len; unsigned int count = buffer->len;
hb_glyph_info_t *info = buffer->info;
for (unsigned int i = 0; i < count; i++) for (unsigned int i = 0; i < count; i++)
add_char (font, buffer->unicode, mirror, buffer->info[i].codepoint, glyphs); add_char (font, buffer->unicode, mirror, info[i].codepoint, glyphs);
hb_set_t lookups; hb_set_t lookups;
lookups.init (); lookups.init ();

View File

@ -24,31 +24,30 @@
* Red Hat Author(s): Behdad Esfahbod * Red Hat Author(s): Behdad Esfahbod
*/ */
#ifndef HB_OT_H_IN
#error "Include <hb-ot.h> instead."
#endif
#ifndef HB_OT_SHAPE_H #ifndef HB_OT_SHAPE_H
#define HB_OT_SHAPE_H #define HB_OT_SHAPE_H
#define HB_OT_SHAPE_H_IN
#include "hb.h" #include "hb.h"
#include "hb-ot-layout.h"
#include "hb-ot-tag.h"
HB_BEGIN_DECLS HB_BEGIN_DECLS
/* TODO port to shape-plan / set. */ /* TODO port to shape-plan / set. */
void void
hb_ot_shape_glyphs_closure (hb_font_t *font, hb_ot_shape_glyphs_closure (hb_font_t *font,
hb_buffer_t *buffer, hb_buffer_t *buffer,
const hb_feature_t *features, const hb_feature_t *features,
unsigned int num_features, unsigned int num_features,
hb_set_t *glyphs); hb_set_t *glyphs);
void void
hb_ot_shape_plan_collect_lookups (hb_shape_plan_t *shape_plan, hb_ot_shape_plan_collect_lookups (hb_shape_plan_t *shape_plan,
hb_tag_t table_tag, hb_tag_t table_tag,
hb_set_t *lookup_indexes /* OUT */); hb_set_t *lookup_indexes /* OUT */);
HB_END_DECLS HB_END_DECLS
#undef HB_OT_SHAPE_H_IN
#endif /* HB_OT_SHAPE_H */ #endif /* HB_OT_SHAPE_H */

View File

@ -57,7 +57,7 @@ hb_ot_old_tag_from_script (hb_script_t script)
} }
/* Else, just change first char to lowercase and return */ /* Else, just change first char to lowercase and return */
return ((hb_tag_t) script) | 0x20000000; return ((hb_tag_t) script) | 0x20000000u;
} }
static hb_script_t static hb_script_t
@ -70,13 +70,13 @@ hb_ot_old_tag_to_script (hb_tag_t tag)
/* Any spaces at the end of the tag are replaced by repeating the last /* Any spaces at the end of the tag are replaced by repeating the last
* letter. Eg 'nko ' -> 'Nkoo' */ * letter. Eg 'nko ' -> 'Nkoo' */
if (unlikely ((tag & 0x0000FF00) == 0x00002000)) if (unlikely ((tag & 0x0000FF00u) == 0x00002000u))
tag |= (tag >> 8) & 0x0000FF00; /* Copy second letter to third */ tag |= (tag >> 8) & 0x0000FF00u; /* Copy second letter to third */
if (unlikely ((tag & 0x000000FF) == 0x00000020)) if (unlikely ((tag & 0x000000FFu) == 0x00000020u))
tag |= (tag >> 8) & 0x000000FF; /* Copy third letter to fourth */ tag |= (tag >> 8) & 0x000000FFu; /* Copy third letter to fourth */
/* Change first char to uppercase and return */ /* Change first char to uppercase and return */
return (hb_script_t) (tag & ~0x20000000); return (hb_script_t) (tag & ~0x20000000u);
} }
static hb_tag_t static hb_tag_t
@ -146,7 +146,7 @@ hb_ot_tags_from_script (hb_script_t script,
hb_script_t hb_script_t
hb_ot_tag_to_script (hb_tag_t tag) hb_ot_tag_to_script (hb_tag_t tag)
{ {
if (unlikely ((tag & 0x000000FF) == '2')) if (unlikely ((tag & 0x000000FFu) == '2'))
return hb_ot_new_tag_to_script (tag); return hb_ot_new_tag_to_script (tag);
return hb_ot_old_tag_to_script (tag); return hb_ot_old_tag_to_script (tag);
@ -156,7 +156,7 @@ hb_ot_tag_to_script (hb_tag_t tag)
/* hb_language_t */ /* hb_language_t */
typedef struct { typedef struct {
char language[6]; char language[4];
hb_tag_t tag; hb_tag_t tag;
} LangTag; } LangTag;
@ -763,12 +763,18 @@ static const LangTag ot_languages[] = {
/*{"??", HB_TAG('Z','H','P',' ')},*/ /* Chinese Phonetic */ /*{"??", HB_TAG('Z','H','P',' ')},*/ /* Chinese Phonetic */
}; };
static const LangTag ot_languages_zh[] = { typedef struct {
char language[8];
hb_tag_t tag;
} LangTagLong;
static const LangTagLong ot_languages_zh[] = {
{"zh-cn", HB_TAG('Z','H','S',' ')}, /* Chinese (China) */ {"zh-cn", HB_TAG('Z','H','S',' ')}, /* Chinese (China) */
{"zh-hk", HB_TAG('Z','H','H',' ')}, /* Chinese (Hong Kong) */ {"zh-hk", HB_TAG('Z','H','H',' ')}, /* Chinese (Hong Kong) */
{"zh-mo", HB_TAG('Z','H','T',' ')}, /* Chinese (Macao) */ {"zh-mo", HB_TAG('Z','H','T',' ')}, /* Chinese (Macao) */
{"zh-sg", HB_TAG('Z','H','S',' ')}, /* Chinese (Singapore) */ {"zh-sg", HB_TAG('Z','H','S',' ')}, /* Chinese (Singapore) */
{"zh-tw", HB_TAG('Z','H','T',' ')} /* Chinese (Taiwan) */ {"zh-tw", HB_TAG('Z','H','T',' ')}, /* Chinese (Taiwan) */
{"zh-hans", HB_TAG('Z','H','S',' ')}, /* Chinese (Simplified) */
{"zh-hant", HB_TAG('Z','H','T',' ')}, /* Chinese (Traditional) */
}; };
static int static int
@ -800,7 +806,6 @@ hb_tag_t
hb_ot_tag_from_language (hb_language_t language) hb_ot_tag_from_language (hb_language_t language)
{ {
const char *lang_str, *s; const char *lang_str, *s;
const LangTag *lang_tag;
if (language == HB_LANGUAGE_INVALID) if (language == HB_LANGUAGE_INVALID)
return HB_OT_TAG_DEFAULT_LANGUAGE; return HB_OT_TAG_DEFAULT_LANGUAGE;
@ -822,11 +827,14 @@ hb_ot_tag_from_language (hb_language_t language)
} }
/* Find a language matching in the first component */ /* Find a language matching in the first component */
lang_tag = (LangTag *) bsearch (lang_str, ot_languages, {
ARRAY_LENGTH (ot_languages), sizeof (LangTag), const LangTag *lang_tag;
(hb_compare_func_t) lang_compare_first_component); lang_tag = (LangTag *) bsearch (lang_str, ot_languages,
if (lang_tag) ARRAY_LENGTH (ot_languages), sizeof (LangTag),
return lang_tag->tag; (hb_compare_func_t) lang_compare_first_component);
if (lang_tag)
return lang_tag->tag;
}
/* Otherwise, check the Chinese ones */ /* Otherwise, check the Chinese ones */
if (0 == lang_compare_first_component (lang_str, "zh")) if (0 == lang_compare_first_component (lang_str, "zh"))
@ -835,8 +843,9 @@ hb_ot_tag_from_language (hb_language_t language)
for (i = 0; i < ARRAY_LENGTH (ot_languages_zh); i++) for (i = 0; i < ARRAY_LENGTH (ot_languages_zh); i++)
{ {
const LangTagLong *lang_tag;
lang_tag = &ot_languages_zh[i]; lang_tag = &ot_languages_zh[i];
if (lang_matches (lang_tag->language, lang_str)) if (lang_matches (lang_str, lang_tag->language))
return lang_tag->tag; return lang_tag->tag;
} }
@ -849,7 +858,7 @@ hb_ot_tag_from_language (hb_language_t language)
s = lang_str + strlen (lang_str); s = lang_str + strlen (lang_str);
if (s - lang_str == 3) { if (s - lang_str == 3) {
/* Assume it's ISO-639-3 and upper-case and use it. */ /* Assume it's ISO-639-3 and upper-case and use it. */
return hb_tag_from_string (lang_str, s - lang_str) & ~0x20202000; return hb_tag_from_string (lang_str, s - lang_str) & ~0x20202000u;
} }
return HB_OT_TAG_DEFAULT_LANGUAGE; return HB_OT_TAG_DEFAULT_LANGUAGE;
@ -868,21 +877,12 @@ hb_ot_tag_to_language (hb_tag_t tag)
return hb_language_from_string (ot_languages[i].language, -1); return hb_language_from_string (ot_languages[i].language, -1);
/* If tag starts with ZH, it's Chinese */ /* If tag starts with ZH, it's Chinese */
if ((tag & 0xFFFF0000) == 0x5A480000) { if ((tag & 0xFFFF0000u) == 0x5A480000u) {
switch (tag) { switch (tag) {
case HB_TAG('Z','H','H',' '): return hb_language_from_string ("zh-hk", -1); /* Hong Kong */ case HB_TAG('Z','H','H',' '): return hb_language_from_string ("zh-hk", -1); /* Hong Kong */
default: { case HB_TAG('Z','H','S',' '): return hb_language_from_string ("zh-Hans", -1); /* Simplified */
/* Encode the tag... */ case HB_TAG('Z','H','T',' '): return hb_language_from_string ("zh-Hant", -1); /* Traditional */
unsigned char buf[14] = "zh-x-hbot"; default: break; /* Fall through */
buf[9] = tag >> 24;
buf[10] = (tag >> 16) & 0xFF;
buf[11] = (tag >> 8) & 0xFF;
buf[12] = tag & 0xFF;
if (buf[12] == 0x20)
buf[12] = '\0';
buf[13] = '\0';
return hb_language_from_string ((char *) buf, -1);
}
} }
} }

View File

@ -30,6 +30,7 @@
#include "hb.h" #include "hb.h"
#include "hb-ot-font.h"
#include "hb-ot-layout.h" #include "hb-ot-layout.h"
#include "hb-ot-tag.h" #include "hb-ot-tag.h"
#include "hb-ot-shape.h" #include "hb-ot-shape.h"

View File

@ -54,23 +54,90 @@
#include <stdarg.h> #include <stdarg.h>
/* Compiler attributes */
/* Essentials */
#ifndef NULL #if defined(__GNUC__) && (__GNUC__ > 2) && defined(__OPTIMIZE__)
# define NULL ((void *) 0) #define _HB_BOOLEAN_EXPR(expr) ((expr) ? 1 : 0)
#define likely(expr) (__builtin_expect (_HB_BOOLEAN_EXPR(expr), 1))
#define unlikely(expr) (__builtin_expect (_HB_BOOLEAN_EXPR(expr), 0))
#else
#define likely(expr) (expr)
#define unlikely(expr) (expr)
#endif #endif
#ifndef __GNUC__
#undef __attribute__
#define __attribute__(x)
#endif
/* Void! */ #if __GNUC__ >= 3
struct _hb_void_t {}; #define HB_PURE_FUNC __attribute__((pure))
typedef const _hb_void_t &hb_void_t; #define HB_CONST_FUNC __attribute__((const))
#define HB_VOID (* (const _hb_void_t *) NULL) #define HB_PRINTF_FUNC(format_idx, arg_idx) __attribute__((__format__ (__printf__, format_idx, arg_idx)))
#else
#define HB_PURE_FUNC
#define HB_CONST_FUNC
#define HB_PRINTF_FUNC(format_idx, arg_idx)
#endif
#if __GNUC__ >= 4
#define HB_UNUSED __attribute__((unused))
#else
#define HB_UNUSED
#endif
#ifndef HB_INTERNAL
# if !defined(__MINGW32__) && !defined(__CYGWIN__)
# define HB_INTERNAL __attribute__((__visibility__("hidden")))
# else
# define HB_INTERNAL
# endif
#endif
#if (defined(__WIN32__) && !defined(__WINE__)) || defined(_MSC_VER)
#define snprintf _snprintf
#endif
#ifdef _MSC_VER
#undef inline
#define inline __inline
#endif
#ifdef __STRICT_ANSI__
#undef inline
#define inline __inline__
#endif
#if __GNUC__ >= 3
#define HB_FUNC __PRETTY_FUNCTION__
#elif defined(_MSC_VER)
#define HB_FUNC __FUNCSIG__
#else
#define HB_FUNC __func__
#endif
#if defined(_WIN32) || defined(__CYGWIN__)
/* We need Windows Vista for both Uniscribe backend and for
* MemoryBarrier. We don't support compiling on Windows XP,
* though we run on it fine. */
# if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0600
# undef _WIN32_WINNT
# endif
# ifndef _WIN32_WINNT
# define _WIN32_WINNT 0x0600
# endif
# define WIN32_LEAN_AND_MEAN
# define STRICT
#endif
/* Basics */ /* Basics */
#ifndef NULL
# define NULL ((void *) 0)
#endif
#undef MIN #undef MIN
template <typename Type> template <typename Type>
static inline Type MIN (const Type &a, const Type &b) { return a < b ? a : b; } static inline Type MIN (const Type &a, const Type &b) { return a < b ? a : b; }
@ -92,7 +159,7 @@ static inline unsigned int ARRAY_LENGTH (const Type (&)[n]) { return n; }
#define HB_STMT_START do #define HB_STMT_START do
#define HB_STMT_END while (0) #define HB_STMT_END while (0)
#define _ASSERT_STATIC1(_line, _cond) typedef int _static_assert_on_line_##_line##_failed[(_cond)?1:-1] #define _ASSERT_STATIC1(_line, _cond) HB_UNUSED typedef int _static_assert_on_line_##_line##_failed[(_cond)?1:-1]
#define _ASSERT_STATIC0(_line, _cond) _ASSERT_STATIC1 (_line, (_cond)) #define _ASSERT_STATIC0(_line, _cond) _ASSERT_STATIC1 (_line, (_cond))
#define ASSERT_STATIC(_cond) _ASSERT_STATIC0 (__LINE__, (_cond)) #define ASSERT_STATIC(_cond) _ASSERT_STATIC0 (__LINE__, (_cond))
@ -139,7 +206,7 @@ ASSERT_STATIC (sizeof (hb_var_int_t) == 4);
/* Check _assertion in a method environment */ /* Check _assertion in a method environment */
#define _ASSERT_POD1(_line) \ #define _ASSERT_POD1(_line) \
inline void _static_assertion_on_line_##_line (void) const \ HB_UNUSED inline void _static_assertion_on_line_##_line (void) const \
{ _ASSERT_INSTANCE_POD1 (_line, *this); /* Make sure it's POD. */ } { _ASSERT_INSTANCE_POD1 (_line, *this); /* Make sure it's POD. */ }
# define _ASSERT_POD0(_line) _ASSERT_POD1 (_line) # define _ASSERT_POD0(_line) _ASSERT_POD1 (_line)
# define ASSERT_POD() _ASSERT_POD0 (__LINE__) # define ASSERT_POD() _ASSERT_POD0 (__LINE__)
@ -148,68 +215,10 @@ ASSERT_STATIC (sizeof (hb_var_int_t) == 4);
/* Misc */ /* Misc */
/* Void! */
#if defined(__GNUC__) && (__GNUC__ > 2) && defined(__OPTIMIZE__) struct _hb_void_t {};
#define _HB_BOOLEAN_EXPR(expr) ((expr) ? 1 : 0) typedef const _hb_void_t &hb_void_t;
#define likely(expr) (__builtin_expect (_HB_BOOLEAN_EXPR(expr), 1)) #define HB_VOID (* (const _hb_void_t *) NULL)
#define unlikely(expr) (__builtin_expect (_HB_BOOLEAN_EXPR(expr), 0))
#else
#define likely(expr) (expr)
#define unlikely(expr) (expr)
#endif
#ifndef __GNUC__
#undef __attribute__
#define __attribute__(x)
#endif
#if __GNUC__ >= 3
#define HB_PURE_FUNC __attribute__((pure))
#define HB_CONST_FUNC __attribute__((const))
#define HB_PRINTF_FUNC(format_idx, arg_idx) __attribute__((__format__ (__printf__, format_idx, arg_idx)))
#else
#define HB_PURE_FUNC
#define HB_CONST_FUNC
#define HB_PRINTF_FUNC(format_idx, arg_idx)
#endif
#if __GNUC__ >= 4
#define HB_UNUSED __attribute__((unused))
#else
#define HB_UNUSED
#endif
#ifndef HB_INTERNAL
# ifndef __MINGW32__
# define HB_INTERNAL __attribute__((__visibility__("hidden")))
# else
# define HB_INTERNAL
# endif
#endif
#if (defined(__WIN32__) && !defined(__WINE__)) || defined(_MSC_VER)
#define snprintf _snprintf
#endif
#ifdef _MSC_VER
#undef inline
#define inline __inline
#endif
#ifdef __STRICT_ANSI__
#undef inline
#define inline __inline__
#endif
#if __GNUC__ >= 3
#define HB_FUNC __PRETTY_FUNCTION__
#elif defined(_MSC_VER)
#define HB_FUNC __FUNCSIG__
#else
#define HB_FUNC __func__
#endif
/* Return the number of 1 bits in mask. */ /* Return the number of 1 bits in mask. */
static inline HB_CONST_FUNC unsigned int static inline HB_CONST_FUNC unsigned int
@ -275,8 +284,8 @@ typedef int (*hb_compare_func_t) (const void *, const void *);
/* arrays and maps */ /* arrays and maps */
#define HB_PREALLOCED_ARRAY_INIT {0} #define HB_PREALLOCED_ARRAY_INIT {0, 0, NULL}
template <typename Type, unsigned int StaticSize> template <typename Type, unsigned int StaticSize=16>
struct hb_prealloced_array_t struct hb_prealloced_array_t
{ {
unsigned int len; unsigned int len;
@ -357,14 +366,14 @@ struct hb_prealloced_array_t
return NULL; return NULL;
} }
inline void sort (void) inline void qsort (void)
{ {
qsort (array, len, sizeof (Type), (hb_compare_func_t) Type::cmp); ::qsort (array, len, sizeof (Type), (hb_compare_func_t) Type::cmp);
} }
inline void sort (unsigned int start, unsigned int end) inline void qsort (unsigned int start, unsigned int end)
{ {
qsort (array + start, end - start, sizeof (Type), (hb_compare_func_t) Type::cmp); ::qsort (array + start, end - start, sizeof (Type), (hb_compare_func_t) Type::cmp);
} }
template <typename T> template <typename T>
@ -387,12 +396,11 @@ struct hb_prealloced_array_t
} }
}; };
#define HB_AUTO_ARRAY_PREALLOCED 16
template <typename Type> template <typename Type>
struct hb_auto_array_t : hb_prealloced_array_t <Type, HB_AUTO_ARRAY_PREALLOCED> struct hb_auto_array_t : hb_prealloced_array_t <Type>
{ {
hb_auto_array_t (void) { hb_prealloced_array_t<Type, HB_AUTO_ARRAY_PREALLOCED>::init (); } hb_auto_array_t (void) { hb_prealloced_array_t<Type>::init (); }
~hb_auto_array_t (void) { hb_prealloced_array_t<Type, HB_AUTO_ARRAY_PREALLOCED>::finish (); } ~hb_auto_array_t (void) { hb_prealloced_array_t<Type>::finish (); }
}; };
@ -725,7 +733,7 @@ static inline void _hb_warn_no_return (bool returned)
} }
} }
template <> template <>
inline void _hb_warn_no_return<hb_void_t> (bool returned HB_UNUSED) /*static*/ inline void _hb_warn_no_return<hb_void_t> (bool returned HB_UNUSED)
{} {}
template <int max_level, typename ret_t> template <int max_level, typename ret_t>
@ -791,20 +799,23 @@ struct hb_auto_trace_t<0, ret_t> {
/* Misc */ /* Misc */
template <typename T> class hb_assert_unsigned_t;
template <> class hb_assert_unsigned_t<unsigned char> {};
template <> class hb_assert_unsigned_t<unsigned short> {};
template <> class hb_assert_unsigned_t<unsigned int> {};
template <> class hb_assert_unsigned_t<unsigned long> {};
/* Pre-mature optimization:
* Checks for lo <= u <= hi but with an optimization if lo and hi
* are only different in a contiguous set of lower-most bits.
*/
template <typename T> static inline bool template <typename T> static inline bool
hb_in_range (T u, T lo, T hi) hb_in_range (T u, T lo, T hi)
{ {
if ( ((lo^hi) & lo) == 0 && /* The sizeof() is here to force template instantiation.
((lo^hi) & hi) == (lo^hi) && * I'm sure there are better ways to do this but can't think of
((lo^hi) & ((lo^hi) + 1)) == 0 ) * one right now. Declaring a variable won't work as HB_UNUSED
return (u & ~(lo^hi)) == lo; * is unsable on some platforms and unused types are less likely
else * to generate a warning than unused variables. */
return lo <= u && u <= hi; ASSERT_STATIC (sizeof (hb_assert_unsigned_t<T>) >= 0);
return (u - lo) <= (hi - lo);
} }
template <typename T> static inline bool template <typename T> static inline bool

View File

@ -104,8 +104,6 @@ hb_shape_plan_create (hb_face_t *face,
unsigned int num_user_features, unsigned int num_user_features,
const char * const *shaper_list) const char * const *shaper_list)
{ {
assert (props->direction != HB_DIRECTION_INVALID);
hb_shape_plan_t *shape_plan; hb_shape_plan_t *shape_plan;
hb_feature_t *features = NULL; hb_feature_t *features = NULL;
@ -120,6 +118,8 @@ hb_shape_plan_create (hb_face_t *face,
return hb_shape_plan_get_empty (); return hb_shape_plan_get_empty ();
} }
assert (props->direction != HB_DIRECTION_INVALID);
hb_face_make_immutable (face); hb_face_make_immutable (face);
shape_plan->default_shaper_list = shaper_list == NULL; shape_plan->default_shaper_list = shaper_list == NULL;
shape_plan->face_unsafe = face; shape_plan->face_unsafe = face;

View File

@ -34,15 +34,15 @@
#include "hb-font-private.hh" #include "hb-font-private.hh"
static void static bool
parse_space (const char **pp, const char *end) parse_space (const char **pp, const char *end)
{ {
char c; while (*pp < end && ISSPACE (**pp))
while (*pp < end && (c = **pp, ISSPACE (c)))
(*pp)++; (*pp)++;
return true;
} }
static hb_bool_t static bool
parse_char (const char **pp, const char *end, char c) parse_char (const char **pp, const char *end, char c)
{ {
parse_space (pp, end); parse_space (pp, end);
@ -54,7 +54,7 @@ parse_char (const char **pp, const char *end, char c)
return true; return true;
} }
static hb_bool_t static bool
parse_uint (const char **pp, const char *end, unsigned int *pv) parse_uint (const char **pp, const char *end, unsigned int *pv)
{ {
char buf[32]; char buf[32];
@ -78,7 +78,27 @@ parse_uint (const char **pp, const char *end, unsigned int *pv)
return true; return true;
} }
static hb_bool_t static bool
parse_bool (const char **pp, const char *end, unsigned int *pv)
{
parse_space (pp, end);
const char *p = *pp;
while (*pp < end && ISALPHA(**pp))
(*pp)++;
/* CSS allows on/off as aliases 1/0. */
if (*pp - p == 2 || 0 == strncmp (p, "on", 2))
*pv = 1;
else if (*pp - p == 3 || 0 == strncmp (p, "off", 2))
*pv = 0;
else
return false;
return true;
}
static bool
parse_feature_value_prefix (const char **pp, const char *end, hb_feature_t *feature) parse_feature_value_prefix (const char **pp, const char *end, hb_feature_t *feature)
{ {
if (parse_char (pp, end, '-')) if (parse_char (pp, end, '-'))
@ -91,32 +111,48 @@ parse_feature_value_prefix (const char **pp, const char *end, hb_feature_t *feat
return true; return true;
} }
static hb_bool_t static bool
parse_feature_tag (const char **pp, const char *end, hb_feature_t *feature) parse_feature_tag (const char **pp, const char *end, hb_feature_t *feature)
{ {
const char *p = *pp;
char c;
parse_space (pp, end); parse_space (pp, end);
#define ISALNUM(c) (('a' <= (c) && (c) <= 'z') || ('A' <= (c) && (c) <= 'Z') || ('0' <= (c) && (c) <= '9')) char quote = 0;
while (*pp < end && (c = **pp, ISALNUM(c)))
(*pp)++;
#undef ISALNUM
if (p == *pp) if (*pp < end && (**pp == '\'' || **pp == '"'))
{
quote = **pp;
(*pp)++;
}
const char *p = *pp;
while (*pp < end && ISALNUM(**pp))
(*pp)++;
if (p == *pp || *pp - p > 4)
return false; return false;
feature->tag = hb_tag_from_string (p, *pp - p); feature->tag = hb_tag_from_string (p, *pp - p);
if (quote)
{
/* CSS expects exactly four bytes. And we only allow quotations for
* CSS compatibility. So, enforce the length. */
if (*pp - p != 4)
return false;
if (*pp == end || **pp != quote)
return false;
(*pp)++;
}
return true; return true;
} }
static hb_bool_t static bool
parse_feature_indices (const char **pp, const char *end, hb_feature_t *feature) parse_feature_indices (const char **pp, const char *end, hb_feature_t *feature)
{ {
parse_space (pp, end); parse_space (pp, end);
hb_bool_t has_start; bool has_start;
feature->start = 0; feature->start = 0;
feature->end = (unsigned int) -1; feature->end = (unsigned int) -1;
@ -136,20 +172,27 @@ parse_feature_indices (const char **pp, const char *end, hb_feature_t *feature)
return parse_char (pp, end, ']'); return parse_char (pp, end, ']');
} }
static hb_bool_t static bool
parse_feature_value_postfix (const char **pp, const char *end, hb_feature_t *feature) parse_feature_value_postfix (const char **pp, const char *end, hb_feature_t *feature)
{ {
return !parse_char (pp, end, '=') || parse_uint (pp, end, &feature->value); bool had_equal = parse_char (pp, end, '=');
bool had_value = parse_uint (pp, end, &feature->value) ||
parse_bool (pp, end, &feature->value);
/* CSS doesn't use equal-sign between tag and value.
* If there was an equal-sign, then there *must* be a value.
* A value without an eqaul-sign is ok, but not required. */
return !had_equal || had_value;
} }
static hb_bool_t static bool
parse_one_feature (const char **pp, const char *end, hb_feature_t *feature) parse_one_feature (const char **pp, const char *end, hb_feature_t *feature)
{ {
return parse_feature_value_prefix (pp, end, feature) && return parse_feature_value_prefix (pp, end, feature) &&
parse_feature_tag (pp, end, feature) && parse_feature_tag (pp, end, feature) &&
parse_feature_indices (pp, end, feature) && parse_feature_indices (pp, end, feature) &&
parse_feature_value_postfix (pp, end, feature) && parse_feature_value_postfix (pp, end, feature) &&
parse_space (pp, end) &&
*pp == end; *pp == end;
} }
@ -157,7 +200,7 @@ parse_one_feature (const char **pp, const char *end, hb_feature_t *feature)
* hb_feature_from_string: * hb_feature_from_string:
* @str: (array length=len): * @str: (array length=len):
* @len: * @len:
* @feature: (out): * @feature: (out) (allow-none):
* *
* *
* *
@ -169,10 +212,21 @@ hb_bool_t
hb_feature_from_string (const char *str, int len, hb_feature_from_string (const char *str, int len,
hb_feature_t *feature) hb_feature_t *feature)
{ {
hb_feature_t feat;
if (len < 0) if (len < 0)
len = strlen (str); len = strlen (str);
return parse_one_feature (&str, str + len, feature); if (likely (parse_one_feature (&str, str + len, &feat)))
{
if (feature)
*feature = feat;
return true;
}
if (feature)
memset (feature, 0, sizeof (*feature));
return false;
} }
/** /**
@ -203,18 +257,18 @@ hb_feature_to_string (hb_feature_t *feature,
{ {
s[len++] = '['; s[len++] = '[';
if (feature->start) if (feature->start)
len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%d", feature->start)); len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->start));
if (feature->end != feature->start + 1) { if (feature->end != feature->start + 1) {
s[len++] = ':'; s[len++] = ':';
if (feature->end != (unsigned int) -1) if (feature->end != (unsigned int) -1)
len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%d", feature->end)); len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->end));
} }
s[len++] = ']'; s[len++] = ']';
} }
if (feature->value > 1) if (feature->value > 1)
{ {
s[len++] = '='; s[len++] = '=';
len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%d", feature->value)); len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->value));
} }
assert (len < ARRAY_LENGTH (s)); assert (len < ARRAY_LENGTH (s));
len = MIN (len, size - 1); len = MIN (len, size - 1);

View File

@ -34,17 +34,15 @@
/* Only picks up fonts that have a "Silf" table. */ /* Only picks up fonts that have a "Silf" table. */
HB_SHAPER_IMPLEMENT (graphite2) HB_SHAPER_IMPLEMENT (graphite2)
#endif #endif
#ifdef HAVE_CORETEXT
/* Only picks up fonts that have a "mort" or "morx" table. */
HB_SHAPER_IMPLEMENT (coretext_aat)
#endif
#ifdef HAVE_OT #ifdef HAVE_OT
HB_SHAPER_IMPLEMENT (ot) /* <--- This is our main OpenType shaper. */ HB_SHAPER_IMPLEMENT (ot) /* <--- This is our main OpenType shaper. */
#endif #endif
#ifdef HAVE_HB_OLD
HB_SHAPER_IMPLEMENT (old)
#endif
#ifdef HAVE_ICU_LE
HB_SHAPER_IMPLEMENT (icu_le)
#endif
#ifdef HAVE_UNISCRIBE #ifdef HAVE_UNISCRIBE
HB_SHAPER_IMPLEMENT (uniscribe) HB_SHAPER_IMPLEMENT (uniscribe)
#endif #endif

View File

@ -1,77 +0,0 @@
/*
* Copyright © 2011 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Behdad Esfahbod
*/
#include "hb-font-private.hh" /* Shall be first since may include windows.h */
#include "hb-open-type-private.hh"
#include "hb-ot-hhea-table.hh"
#include "hb-ot-hmtx-table.hh"
#include <string.h>
#if 0
struct hb_tt_font_t
{
const struct hhea *hhea;
hb_blob_t *hhea_blob;
};
static hb_tt_font_t *
_hb_tt_font_create (hb_font_t *font)
{
/* TODO Remove this object altogether */
hb_tt_font_t *tt = (hb_tt_font_t *) calloc (1, sizeof (hb_tt_font_t));
tt->hhea_blob = Sanitizer<hhea>::sanitize (font->face->reference_table (HB_OT_TAG_hhea));
tt->hhea = Sanitizer<hhea>::lock_instance (tt->hhea_blob);
return tt;
}
static void
_hb_tt_font_destroy (hb_tt_font_t *tt)
{
hb_blob_destroy (tt->hhea_blob);
free (tt);
}
static inline const hhea&
_get_hhea (hb_face_t *face)
{
return likely (face->tt && face->tt->hhea) ? *face->tt->hhea : Null(hhea);
}
/*
* hb_tt_font_funcs_t
*/
#endif

View File

@ -125,6 +125,29 @@ static const hb_script_t ucdn_script_translate[] =
HB_SCRIPT_SORA_SOMPENG, HB_SCRIPT_SORA_SOMPENG,
HB_SCRIPT_TAKRI, HB_SCRIPT_TAKRI,
HB_SCRIPT_UNKNOWN, HB_SCRIPT_UNKNOWN,
HB_SCRIPT_BASSA_VAH,
HB_SCRIPT_CAUCASIAN_ALBANIAN,
HB_SCRIPT_DUPLOYAN,
HB_SCRIPT_ELBASAN,
HB_SCRIPT_GRANTHA,
HB_SCRIPT_KHOJKI,
HB_SCRIPT_KHUDAWADI,
HB_SCRIPT_LINEAR_A,
HB_SCRIPT_MAHAJANI,
HB_SCRIPT_MANICHAEAN,
HB_SCRIPT_MENDE_KIKAKUI,
HB_SCRIPT_MODI,
HB_SCRIPT_MRO,
HB_SCRIPT_NABATAEAN,
HB_SCRIPT_OLD_NORTH_ARABIAN,
HB_SCRIPT_OLD_PERMIC,
HB_SCRIPT_PAHAWH_HMONG,
HB_SCRIPT_PALMYRENE,
HB_SCRIPT_PAU_CIN_HAU,
HB_SCRIPT_PSALTER_PAHLAVI,
HB_SCRIPT_SIDDHAM,
HB_SCRIPT_TIRHUTA,
HB_SCRIPT_WARANG_CITI,
}; };
static hb_unicode_combining_class_t static hb_unicode_combining_class_t

View File

@ -102,72 +102,70 @@ HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS_SIMPLE
} }
unsigned int inline unsigned int
modified_combining_class (hb_codepoint_t unicode) modified_combining_class (hb_codepoint_t unicode)
{ {
/* XXX This hack belongs to the Myanmar shaper. */ /* XXX This hack belongs to the Myanmar shaper. */
if (unlikely (unicode == 0x1037)) unicode = 0x103A; if (unlikely (unicode == 0x1037u)) unicode = 0x103Au;
/* XXX This hack belongs to the SEA shaper (for Tai Tham): /* XXX This hack belongs to the SEA shaper (for Tai Tham):
* Reorder SAKOT to ensure it comes after any tone marks. */ * Reorder SAKOT to ensure it comes after any tone marks. */
if (unlikely (unicode == 0x1A60)) return 254; if (unlikely (unicode == 0x1A60u)) return 254;
/* XXX This hack belongs to the Tibetan shaper:
* Reorder PADMA to ensure it comes after any vowel marks. */
if (unlikely (unicode == 0x0FC6u)) return 254;
return _hb_modified_combining_class[combining_class (unicode)]; return _hb_modified_combining_class[combining_class (unicode)];
} }
inline hb_bool_t static inline hb_bool_t
is_variation_selector (hb_codepoint_t unicode) is_variation_selector (hb_codepoint_t unicode)
{ {
return unlikely (hb_in_ranges<hb_codepoint_t> (unicode, /* U+180B..180D MONGOLIAN FREE VARIATION SELECTORs are handled in the
0x180B, 0x180D, /* MONGOLIAN FREE VARIATION SELECTOR ONE..THREE */ * Arabic shaper. No need to match them here. */
0xFE00, 0xFE0F, /* VARIATION SELECTOR-1..16 */ return unlikely (hb_in_ranges (unicode,
0xE0100, 0xE01EF)); /* VARIATION SELECTOR-17..256 */ 0xFE00u, 0xFE0Fu, /* VARIATION SELECTOR-1..16 */
0xE0100u, 0xE01EFu)); /* VARIATION SELECTOR-17..256 */
} }
/* Default_Ignorable codepoints: /* Default_Ignorable codepoints:
*
* Note that as of Oct 2012 (Unicode 6.2), U+180E MONGOLIAN VOWEL SEPARATOR
* is NOT Default_Ignorable, but it really behaves in a way that it should
* be. That has been reported to the Unicode Technical Committee for
* consideration. As such, we include it here, since Uniscribe removes it.
* It *is* in Unicode 6.3 however. U+061C ARABIC LETTER MARK from Unicode
* 6.3 is also added manually. The new Unicode 6.3 bidi formatting
* characters are encoded in a block that was Default_Ignorable already.
* *
* Note: While U+115F, U+1160, U+3164 and U+FFA0 are Default_Ignorable, * Note: While U+115F, U+1160, U+3164 and U+FFA0 are Default_Ignorable,
* we do NOT want to hide them, as the way Uniscribe has implemented them * we do NOT want to hide them, as the way Uniscribe has implemented them
* is with regular spacing glyphs, and that's the way fonts are made to work. * is with regular spacing glyphs, and that's the way fonts are made to work.
* As such, we make exceptions for those four. * As such, we make exceptions for those four.
* *
* Gathered from: * Unicode 7.0:
* http://unicode.org/cldr/utility/list-unicodeset.jsp?a=[:DI:]&abb=on&ucd=on&esc=on * $ grep '; Default_Ignorable_Code_Point ' DerivedCoreProperties.txt | sed 's/;.*#/#/'
* * 00AD # Cf SOFT HYPHEN
* Last updated to the page with the following versions: * 034F # Mn COMBINING GRAPHEME JOINER
* Version 3.6; ICU version: 50.0.1.0; Unicode version: 6.1.0.0 * 061C # Cf ARABIC LETTER MARK
* * 115F..1160 # Lo [2] HANGUL CHOSEONG FILLER..HANGUL JUNGSEONG FILLER
* 4,167 Code Points * 17B4..17B5 # Mn [2] KHMER VOWEL INHERENT AQ..KHMER VOWEL INHERENT AA
* * 180B..180D # Mn [3] MONGOLIAN FREE VARIATION SELECTOR ONE..MONGOLIAN FREE VARIATION SELECTOR THREE
* [\u00AD\u034F\u115F\u1160\u17B4\u17B5\u180B-\u180D\u200B-\u200F\u202A-\u202E\u2060-\u206F\u3164\uFE00-\uFE0F\uFEFF\uFFA0\uFFF0-\uFFF8\U0001D173-\U0001D17A\U000E0000-\U000E0FFF] * 180E # Cf MONGOLIAN VOWEL SEPARATOR
* * 200B..200F # Cf [5] ZERO WIDTH SPACE..RIGHT-TO-LEFT MARK
* 00AD ;SOFT HYPHEN * 202A..202E # Cf [5] LEFT-TO-RIGHT EMBEDDING..RIGHT-TO-LEFT OVERRIDE
* 034F ;COMBINING GRAPHEME JOINER * 2060..2064 # Cf [5] WORD JOINER..INVISIBLE PLUS
* #115F ;HANGUL CHOSEONG FILLER * 2065 # Cn <reserved-2065>
* #1160 ;HANGUL JUNGSEONG FILLER * 2066..206F # Cf [10] LEFT-TO-RIGHT ISOLATE..NOMINAL DIGIT SHAPES
* 17B4 ;KHMER VOWEL INHERENT AQ * 3164 # Lo HANGUL FILLER
* 17B5 ;KHMER VOWEL INHERENT AA * FE00..FE0F # Mn [16] VARIATION SELECTOR-1..VARIATION SELECTOR-16
* 180B..180D ;MONGOLIAN FREE VARIATION SELECTOR THREE * FEFF # Cf ZERO WIDTH NO-BREAK SPACE
* 200B..200F ;RIGHT-TO-LEFT MARK * FFA0 # Lo HALFWIDTH HANGUL FILLER
* 202A..202E ;RIGHT-TO-LEFT OVERRIDE * FFF0..FFF8 # Cn [9] <reserved-FFF0>..<reserved-FFF8>
* 2060..206F ;NOMINAL DIGIT SHAPES * 1BCA0..1BCA3 # Cf [4] SHORTHAND FORMAT LETTER OVERLAP..SHORTHAND FORMAT UP STEP
* #3164 ;HANGUL FILLER * 1D173..1D17A # Cf [8] MUSICAL SYMBOL BEGIN BEAM..MUSICAL SYMBOL END PHRASE
* FE00..FE0F ;VARIATION SELECTOR-16 * E0000 # Cn <reserved-E0000>
* FEFF ;ZERO WIDTH NO-BREAK SPACE * E0001 # Cf LANGUAGE TAG
* #FFA0 ;HALFWIDTH HANGUL FILLER * E0002..E001F # Cn [30] <reserved-E0002>..<reserved-E001F>
* FFF0..FFF8 ;<unassigned-FFF8> * E0020..E007F # Cf [96] TAG SPACE..CANCEL TAG
* 1D173..1D17A ;MUSICAL SYMBOL END PHRASE * E0080..E00FF # Cn [128] <reserved-E0080>..<reserved-E00FF>
* E0000..E0FFF ;<unassigned-E0FFF> * E0100..E01EF # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-256
* E01F0..E0FFF # Cn [3600] <reserved-E01F0>..<reserved-E0FFF>
*/ */
inline hb_bool_t static inline hb_bool_t
is_default_ignorable (hb_codepoint_t ch) is_default_ignorable (hb_codepoint_t ch)
{ {
hb_codepoint_t plane = ch >> 16; hb_codepoint_t plane = ch >> 16;
@ -176,16 +174,16 @@ HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS_SIMPLE
/* BMP */ /* BMP */
hb_codepoint_t page = ch >> 8; hb_codepoint_t page = ch >> 8;
switch (page) { switch (page) {
case 0x00: return unlikely (ch == 0x00AD); case 0x00: return unlikely (ch == 0x00ADu);
case 0x03: return unlikely (ch == 0x034F); case 0x03: return unlikely (ch == 0x034Fu);
case 0x06: return unlikely (ch == 0x061C); case 0x06: return unlikely (ch == 0x061Cu);
case 0x17: return hb_in_range<hb_codepoint_t> (ch, 0x17B4, 0x17B5); case 0x17: return hb_in_range (ch, 0x17B4u, 0x17B5u);
case 0x18: return hb_in_range<hb_codepoint_t> (ch, 0x180B, 0x180E); case 0x18: return hb_in_range (ch, 0x180Bu, 0x180Eu);
case 0x20: return hb_in_ranges<hb_codepoint_t> (ch, 0x200B, 0x200F, case 0x20: return hb_in_ranges (ch, 0x200Bu, 0x200Fu,
0x202A, 0x202E, 0x202Au, 0x202Eu,
0x2060, 0x206F); 0x2060u, 0x206Fu);
case 0xFE: return hb_in_range<hb_codepoint_t> (ch, 0xFE00, 0xFE0F) || ch == 0xFEFF; case 0xFE: return hb_in_range (ch, 0xFE00u, 0xFE0Fu) || ch == 0xFEFFu;
case 0xFF: return hb_in_range<hb_codepoint_t> (ch, 0xFFF0, 0xFFF8); case 0xFF: return hb_in_range (ch, 0xFFF0u, 0xFFF8u);
default: return false; default: return false;
} }
} }
@ -193,8 +191,9 @@ HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS_SIMPLE
{ {
/* Other planes */ /* Other planes */
switch (plane) { switch (plane) {
case 0x01: return hb_in_range<hb_codepoint_t> (ch, 0x0001D173, 0x0001D17A); case 0x01: return hb_in_ranges (ch, 0x1BCA0u, 0x1BCA3u,
case 0x0E: return hb_in_range<hb_codepoint_t> (ch, 0x000E0000, 0x000E0FFF); 0x1D173u, 0x1D17Au);
case 0x0E: return hb_in_range (ch, 0xE0000u, 0xE0FFFu);
default: return false; default: return false;
} }
} }

View File

@ -133,7 +133,7 @@ hb_unicode_funcs_get_default (void)
#ifdef HAVE_GLIB #ifdef HAVE_GLIB
HB_UNICODE_FUNCS_IMPLEMENT(glib) HB_UNICODE_FUNCS_IMPLEMENT(glib)
#elif 0 && defined(HAVE_ICU) #elif defined(HAVE_ICU) && defined(HAVE_ICU_BUILTIN)
HB_UNICODE_FUNCS_IMPLEMENT(icu) HB_UNICODE_FUNCS_IMPLEMENT(icu)
#elif defined(HAVE_UCDN) #elif defined(HAVE_UCDN)
HB_UNICODE_FUNCS_IMPLEMENT(ucdn) HB_UNICODE_FUNCS_IMPLEMENT(ucdn)
@ -146,8 +146,13 @@ hb_unicode_funcs_get_default (void)
} }
#if !defined(HB_NO_UNICODE_FUNCS) && defined(HB_UNICODE_FUNCS_NIL) #if !defined(HB_NO_UNICODE_FUNCS) && defined(HB_UNICODE_FUNCS_NIL)
#pragma message("Could not find any Unicode functions implementation, you have to provide your own.") #ifdef _MSC_VER
#pragma message("To suppress this warnings, define HB_NO_UNICODE_FUNCS.") #pragma message("Could not find any Unicode functions implementation, you have to provide your own")
#pragma message("To suppress this warnings, define HB_NO_UNICODE_FUNCS")
#else
#warning "Could not find any Unicode functions implementation, you have to provide your own"
#warning "To suppress this warning, define HB_NO_UNICODE_FUNCS"
#endif
#endif #endif
/** /**
@ -305,7 +310,7 @@ hb_unicode_funcs_get_user_data (hb_unicode_funcs_t *ufuncs,
void void
hb_unicode_funcs_make_immutable (hb_unicode_funcs_t *ufuncs) hb_unicode_funcs_make_immutable (hb_unicode_funcs_t *ufuncs)
{ {
if (hb_object_is_inert (ufuncs)) if (unlikely (hb_object_is_inert (ufuncs)))
return; return;
ufuncs->immutable = true; ufuncs->immutable = true;

View File

@ -24,9 +24,6 @@
* Google Author(s): Behdad Esfahbod * Google Author(s): Behdad Esfahbod
*/ */
#define _WIN32_WINNT 0x0600
#define WIN32_LEAN_AND_MEAN
#define HB_SHAPER uniscribe #define HB_SHAPER uniscribe
#include "hb-shaper-impl-private.hh" #include "hb-shaper-impl-private.hh"
@ -313,6 +310,7 @@ _hb_generate_unique_face_name (wchar_t *face_name, unsigned int *plen)
const char *enc = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-"; const char *enc = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-";
UUID id; UUID id;
UuidCreate ((UUID*) &id); UuidCreate ((UUID*) &id);
ASSERT_STATIC (2 + 3 * (16/2) < LF_FACESIZE);
unsigned int name_str_len = 0; unsigned int name_str_len = 0;
face_name[name_str_len++] = 'F'; face_name[name_str_len++] = 'F';
face_name[name_str_len++] = '_'; face_name[name_str_len++] = '_';
@ -379,7 +377,7 @@ _hb_rename_font (hb_blob_t *blob, wchar_t *new_name)
OT::NameRecord &record = name.nameRecord[i]; OT::NameRecord &record = name.nameRecord[i];
record.platformID.set (3); record.platformID.set (3);
record.encodingID.set (1); record.encodingID.set (1);
record.languageID.set (0x0409); /* English */ record.languageID.set (0x0409u); /* English */
record.nameID.set (name_IDs[i]); record.nameID.set (name_IDs[i]);
record.length.set (name_str_len * 2); record.length.set (name_str_len * 2);
record.offset.set (0); record.offset.set (0);
@ -631,7 +629,7 @@ _hb_uniscribe_shape (hb_shape_plan_t *shape_plan,
event->start = false; event->start = false;
event->feature = feature; event->feature = feature;
} }
feature_events.sort (); feature_events.qsort ();
/* Add a strategic final event. */ /* Add a strategic final event. */
{ {
active_feature_t feature; active_feature_t feature;
@ -663,7 +661,7 @@ _hb_uniscribe_shape (hb_shape_plan_t *shape_plan,
unsigned int offset = feature_records.len; unsigned int offset = feature_records.len;
active_features.sort (); active_features.qsort ();
for (unsigned int j = 0; j < active_features.len; j++) for (unsigned int j = 0; j < active_features.len; j++)
{ {
if (!j || active_features[j].rec.tagFeature != feature_records[feature_records.len - 1].tagFeature) if (!j || active_features[j].rec.tagFeature != feature_records[feature_records.len - 1].tagFeature)
@ -749,13 +747,13 @@ retry:
{ {
hb_codepoint_t c = buffer->info[i].codepoint; hb_codepoint_t c = buffer->info[i].codepoint;
buffer->info[i].utf16_index() = chars_len; buffer->info[i].utf16_index() = chars_len;
if (likely (c < 0x10000)) if (likely (c <= 0xFFFFu))
pchars[chars_len++] = c; pchars[chars_len++] = c;
else if (unlikely (c >= 0x110000)) else if (unlikely (c > 0x10FFFFu))
pchars[chars_len++] = 0xFFFD; pchars[chars_len++] = 0xFFFDu;
else { else {
pchars[chars_len++] = 0xD800 + ((c - 0x10000) >> 10); pchars[chars_len++] = 0xD800u + ((c - 0x10000u) >> 10);
pchars[chars_len++] = 0xDC00 + ((c - 0x10000) & ((1 << 10) - 1)); pchars[chars_len++] = 0xDC00u + ((c - 0x10000u) & ((1 << 10) - 1));
} }
} }
@ -771,7 +769,7 @@ retry:
hb_codepoint_t c = buffer->info[i].codepoint; hb_codepoint_t c = buffer->info[i].codepoint;
unsigned int cluster = buffer->info[i].cluster; unsigned int cluster = buffer->info[i].cluster;
log_clusters[chars_len++] = cluster; log_clusters[chars_len++] = cluster;
if (c >= 0x10000 && c < 0x110000) if (hb_in_range (c, 0x10000u, 0x10FFFFu))
log_clusters[chars_len++] = cluster; /* Surrogates. */ log_clusters[chars_len++] = cluster; /* Surrogates. */
} }
} }

View File

@ -29,9 +29,6 @@
#include "hb.h" #include "hb.h"
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0600
#endif
#include <windows.h> #include <windows.h>
HB_BEGIN_DECLS HB_BEGIN_DECLS

View File

@ -1,5 +1,5 @@
/* /*
* Copyright © 2011,2012 Google, Inc. * Copyright © 2011,2012,2014 Google, Inc.
* *
* This is part of HarfBuzz, a text shaping library. * This is part of HarfBuzz, a text shaping library.
* *
@ -29,176 +29,221 @@
#include "hb-private.hh" #include "hb-private.hh"
template <typename T, bool validate=true> struct hb_utf_t;
/* UTF-8 */ /* UTF-8 */
#define HB_UTF8_COMPUTE(Char, Mask, Len) \ template <>
if (Char < 128) { Len = 1; Mask = 0x7f; } \ struct hb_utf_t<uint8_t, true>
else if ((Char & 0xe0) == 0xc0) { Len = 2; Mask = 0x1f; } \
else if ((Char & 0xf0) == 0xe0) { Len = 3; Mask = 0x0f; } \
else if ((Char & 0xf8) == 0xf0) { Len = 4; Mask = 0x07; } \
else Len = 0;
static inline const uint8_t *
hb_utf_next (const uint8_t *text,
const uint8_t *end,
hb_codepoint_t *unicode)
{ {
hb_codepoint_t c = *text, mask; static inline const uint8_t *
unsigned int len; next (const uint8_t *text,
const uint8_t *end,
hb_codepoint_t *unicode,
hb_codepoint_t replacement)
{
/* Written to only accept well-formed sequences.
* Based on ideas from ICU's U8_NEXT.
* Generates one "replacement" for each ill-formed byte. */
/* TODO check for overlong sequences? */ hb_codepoint_t c = *text++;
HB_UTF8_COMPUTE (c, mask, len); if (c > 0x7Fu)
if (unlikely (!len || (unsigned int) (end - text) < len)) { {
*unicode = -1; if (hb_in_range (c, 0xC2u, 0xDFu)) /* Two-byte */
return text + 1;
} else {
hb_codepoint_t result;
unsigned int i;
result = c & mask;
for (i = 1; i < len; i++)
{ {
if (unlikely ((text[i] & 0xc0) != 0x80)) unsigned int t1;
{ if (likely (text < end &&
*unicode = -1; (t1 = text[0] - 0x80u) <= 0x3Fu))
return text + 1; {
} c = ((c&0x1Fu)<<6) | t1;
result <<= 6; text++;
result |= (text[i] & 0x3f); }
else
goto error;
} }
*unicode = result; else if (hb_in_range (c, 0xE0u, 0xEFu)) /* Three-byte */
return text + len;
}
}
static inline const uint8_t *
hb_utf_prev (const uint8_t *text,
const uint8_t *start,
hb_codepoint_t *unicode)
{
const uint8_t *end = text--;
while (start < text && (*text & 0xc0) == 0x80 && end - text < 4)
text--;
hb_codepoint_t c = *text, mask;
unsigned int len;
/* TODO check for overlong sequences? */
HB_UTF8_COMPUTE (c, mask, len);
if (unlikely (!len || (unsigned int) (end - text) != len)) {
*unicode = -1;
return end - 1;
} else {
hb_codepoint_t result;
unsigned int i;
result = c & mask;
for (i = 1; i < len; i++)
{ {
result <<= 6; unsigned int t1, t2;
result |= (text[i] & 0x3f); if (likely (1 < end - text &&
(t1 = text[0] - 0x80u) <= 0x3Fu &&
(t2 = text[1] - 0x80u) <= 0x3Fu))
{
c = ((c&0xFu)<<12) | (t1<<6) | t2;
if (unlikely (c < 0x0800u || hb_in_range (c, 0xD800u, 0xDFFFu)))
goto error;
text += 2;
}
else
goto error;
} }
*unicode = result; else if (hb_in_range (c, 0xF0u, 0xF4u)) /* Four-byte */
{
unsigned int t1, t2, t3;
if (likely (2 < end - text &&
(t1 = text[0] - 0x80u) <= 0x3Fu &&
(t2 = text[1] - 0x80u) <= 0x3Fu &&
(t3 = text[2] - 0x80u) <= 0x3Fu))
{
c = ((c&0x7u)<<18) | (t1<<12) | (t2<<6) | t3;
if (unlikely (!hb_in_range (c, 0x10000u, 0x10FFFFu)))
goto error;
text += 3;
}
else
goto error;
}
else
goto error;
}
*unicode = c;
return text;
error:
*unicode = replacement;
return text; return text;
} }
}
static inline const uint8_t *
prev (const uint8_t *text,
const uint8_t *start,
hb_codepoint_t *unicode,
hb_codepoint_t replacement)
{
const uint8_t *end = text--;
while (start < text && (*text & 0xc0) == 0x80 && end - text < 4)
text--;
static inline unsigned int if (likely (next (text, end, unicode, replacement) == end))
hb_utf_strlen (const uint8_t *text) return text;
{
return strlen ((const char *) text); *unicode = replacement;
} return end - 1;
}
static inline unsigned int
strlen (const uint8_t *text)
{
return ::strlen ((const char *) text);
}
};
/* UTF-16 */ /* UTF-16 */
static inline const uint16_t * template <>
hb_utf_next (const uint16_t *text, struct hb_utf_t<uint16_t, true>
const uint16_t *end,
hb_codepoint_t *unicode)
{ {
hb_codepoint_t c = *text++; static inline const uint16_t *
next (const uint16_t *text,
if (unlikely (hb_in_range<hb_codepoint_t> (c, 0xd800, 0xdbff))) const uint16_t *end,
hb_codepoint_t *unicode,
hb_codepoint_t replacement)
{ {
/* high surrogate */ hb_codepoint_t c = *text++;
hb_codepoint_t l;
if (text < end && ((l = *text), likely (hb_in_range<hb_codepoint_t> (l, 0xdc00, 0xdfff)))) if (likely (!hb_in_range (c, 0xD800u, 0xDFFFu)))
{ {
/* low surrogate */ *unicode = c;
*unicode = (c << 10) + l - ((0xd800 << 10) - 0x10000 + 0xdc00); return text;
text++; }
} else
*unicode = -1;
} else
*unicode = c;
return text; if (likely (hb_in_range (c, 0xD800u, 0xDBFFu)))
} {
/* High-surrogate in c */
hb_codepoint_t l;
if (text < end && ((l = *text), likely (hb_in_range (l, 0xDC00u, 0xDFFFu))))
{
/* Low-surrogate in l */
*unicode = (c << 10) + l - ((0xD800u << 10) - 0x10000u + 0xDC00u);
text++;
return text;
}
}
static inline const uint16_t * /* Lonely / out-of-order surrogate. */
hb_utf_prev (const uint16_t *text, *unicode = replacement;
const uint16_t *start, return text;
hb_codepoint_t *unicode) }
{
hb_codepoint_t c = *--text;
if (unlikely (hb_in_range<hb_codepoint_t> (c, 0xdc00, 0xdfff))) static inline const uint16_t *
prev (const uint16_t *text,
const uint16_t *start,
hb_codepoint_t *unicode,
hb_codepoint_t replacement)
{ {
/* low surrogate */ const uint16_t *end = text--;
hb_codepoint_t h; hb_codepoint_t c = *text;
if (start < text && ((h = *(text - 1)), likely (hb_in_range<hb_codepoint_t> (h, 0xd800, 0xdbff))))
if (likely (!hb_in_range (c, 0xD800u, 0xDFFFu)))
{ {
/* high surrogate */ *unicode = c;
*unicode = (h << 10) + c - ((0xd800 << 10) - 0x10000 + 0xdc00); return text;
text--; }
} else
*unicode = -1;
} else
*unicode = c;
return text; if (likely (start < text && hb_in_range (c, 0xDC00u, 0xDFFFu)))
} text--;
if (likely (next (text, end, unicode, replacement) == end))
return text;
*unicode = replacement;
return end - 1;
}
static inline unsigned int static inline unsigned int
hb_utf_strlen (const uint16_t *text) strlen (const uint16_t *text)
{ {
unsigned int l = 0; unsigned int l = 0;
while (*text++) l++; while (*text++) l++;
return l; return l;
} }
};
/* UTF-32 */ /* UTF-32 */
static inline const uint32_t * template <bool validate>
hb_utf_next (const uint32_t *text, struct hb_utf_t<uint32_t, validate>
const uint32_t *end HB_UNUSED,
hb_codepoint_t *unicode)
{ {
*unicode = *text++; static inline const uint32_t *
return text; next (const uint32_t *text,
} const uint32_t *end HB_UNUSED,
hb_codepoint_t *unicode,
hb_codepoint_t replacement)
{
hb_codepoint_t c = *text++;
if (validate && unlikely (c > 0x10FFFFu || hb_in_range (c, 0xD800u, 0xDFFFu)))
goto error;
*unicode = c;
return text;
static inline const uint32_t * error:
hb_utf_prev (const uint32_t *text, *unicode = replacement;
const uint32_t *start HB_UNUSED, return text;
hb_codepoint_t *unicode) }
{
*unicode = *--text;
return text;
}
static inline unsigned int static inline const uint32_t *
hb_utf_strlen (const uint32_t *text) prev (const uint32_t *text,
{ const uint32_t *start HB_UNUSED,
unsigned int l = 0; hb_codepoint_t *unicode,
while (*text++) l++; hb_codepoint_t replacement)
return l; {
} next (text - 1, text, unicode, replacement);
return text - 1;
}
static inline unsigned int
strlen (const uint32_t *text)
{
unsigned int l = 0;
while (*text++) l++;
return l;
}
};
#endif /* HB_UTF_PRIVATE_HH */ #endif /* HB_UTF_PRIVATE_HH */

View File

@ -38,12 +38,12 @@ HB_BEGIN_DECLS
#define HB_VERSION_MAJOR 0 #define HB_VERSION_MAJOR 0
#define HB_VERSION_MINOR 9 #define HB_VERSION_MINOR 9
#define HB_VERSION_MICRO 25 #define HB_VERSION_MICRO 34
#define HB_VERSION_STRING "0.9.25" #define HB_VERSION_STRING "0.9.34"
#define HB_VERSION_CHECK(major,minor,micro) \ #define HB_VERSION_ATLEAST(major,minor,micro) \
((major)*10000+(minor)*100+(micro) >= \ ((major)*10000+(minor)*100+(micro) <= \
HB_VERSION_MAJOR*10000+HB_VERSION_MINOR*100+HB_VERSION_MICRO) HB_VERSION_MAJOR*10000+HB_VERSION_MINOR*100+HB_VERSION_MICRO)
@ -56,9 +56,9 @@ const char *
hb_version_string (void); hb_version_string (void);
hb_bool_t hb_bool_t
hb_version_check (unsigned int major, hb_version_atleast (unsigned int major,
unsigned int minor, unsigned int minor,
unsigned int micro); unsigned int micro);
HB_END_DECLS HB_END_DECLS

View File

@ -42,8 +42,8 @@ HB_BEGIN_DECLS
#define HB_VERSION_STRING "@HB_VERSION@" #define HB_VERSION_STRING "@HB_VERSION@"
#define HB_VERSION_CHECK(major,minor,micro) \ #define HB_VERSION_ATLEAST(major,minor,micro) \
((major)*10000+(minor)*100+(micro) >= \ ((major)*10000+(minor)*100+(micro) <= \
HB_VERSION_MAJOR*10000+HB_VERSION_MINOR*100+HB_VERSION_MICRO) HB_VERSION_MAJOR*10000+HB_VERSION_MINOR*100+HB_VERSION_MICRO)
@ -56,9 +56,9 @@ const char *
hb_version_string (void); hb_version_string (void);
hb_bool_t hb_bool_t
hb_version_check (unsigned int major, hb_version_atleast (unsigned int major,
unsigned int minor, unsigned int minor,
unsigned int micro); unsigned int micro);
HB_END_DECLS HB_END_DECLS

View File

@ -53,14 +53,3 @@
#endif #endif
#include "hb-unicode-private.hh"
#if !defined(HB_NO_UNICODE_FUNCS) && defined(HB_UNICODE_FUNCS_NIL)
#ifdef _MSC_VER
#pragma message("Could not find any Unicode functions implementation, you have to provide your own")
#pragma message("To suppress this warnings, define HB_NO_UNICODE_FUNCS")
#else
#warning "Could not find any Unicode functions implementation, you have to provide your own"
#warning "To suppress this warning, define HB_NO_UNICODE_FUNCS"
#endif
#endif

View File

@ -131,8 +131,11 @@ main (int argc, char **argv)
else else
printf (" Language System %2d of %2d: %.4s\n", n_langsys, num_langsys, printf (" Language System %2d of %2d: %.4s\n", n_langsys, num_langsys,
(const char *)script.get_lang_sys_tag (n_langsys)); (const char *)script.get_lang_sys_tag (n_langsys));
if (langsys.get_required_feature_index () == Index::NOT_FOUND_INDEX) if (!langsys.has_required_feature ())
printf (" No required feature\n"); printf (" No required feature\n");
else
printf (" Required feature index: %d\n",
langsys.get_required_feature_index ());
int num_features = langsys.get_feature_count (); int num_features = langsys.get_feature_count ();
printf (" %d feature(s) found in language system\n", num_features); printf (" %d feature(s) found in language system\n", num_features);
@ -147,11 +150,10 @@ main (int argc, char **argv)
printf (" %d feature(s) found in table\n", num_features); printf (" %d feature(s) found in table\n", num_features);
for (int n_feature = 0; n_feature < num_features; n_feature++) { for (int n_feature = 0; n_feature < num_features; n_feature++) {
const Feature &feature = g.get_feature (n_feature); const Feature &feature = g.get_feature (n_feature);
printf (" Feature %2d of %2d: %.4s; %d lookup(s)\n", n_feature, num_features,
(const char *)g.get_feature_tag(n_feature),
feature.get_lookup_count());
int num_lookups = feature.get_lookup_count (); int num_lookups = feature.get_lookup_count ();
printf (" Feature %2d of %2d: %c%c%c%c\n", n_feature, num_features,
HB_UNTAG(g.get_feature_tag(n_feature)));
printf (" %d lookup(s) found in feature\n", num_lookups); printf (" %d lookup(s) found in feature\n", num_lookups);
for (int n_lookup = 0; n_lookup < num_lookups; n_lookup++) { for (int n_lookup = 0; n_lookup < num_lookups; n_lookup++) {
printf (" Lookup index %2d of %2d: %d\n", n_lookup, num_lookups, printf (" Lookup index %2d of %2d: %d\n", n_lookup, num_lookups,

View File

@ -11,6 +11,7 @@ EXPORTS.harfbuzz += [
'hb-deprecated.h', 'hb-deprecated.h',
'hb-face.h', 'hb-face.h',
'hb-font.h', 'hb-font.h',
'hb-ot-font.h',
'hb-ot-layout.h', 'hb-ot-layout.h',
'hb-ot-shape.h', 'hb-ot-shape.h',
'hb-ot-tag.h', 'hb-ot-tag.h',