[use] Prohibit visually ambiguous vowel sequences

This commit is contained in:
David Corbett 2018-10-12 16:54:54 -04:00 committed by Behdad Esfahbod
parent 48ed598a35
commit 205737acdc
9 changed files with 827 additions and 274 deletions

View File

@ -295,6 +295,7 @@ GENERATORS = \
gen-os2-unicode-ranges.py \ gen-os2-unicode-ranges.py \
gen-tag-table.py \ gen-tag-table.py \
gen-use-table.py \ gen-use-table.py \
gen-vowel-constraints.py \
$(NULL) $(NULL)
EXTRA_DIST += $(GENERATORS) EXTRA_DIST += $(GENERATORS)
@ -316,13 +317,17 @@ use-table: gen-use-table.py IndicSyllabicCategory.txt IndicPositionalCategory.tx
$(AM_V_GEN) $(builddir)/$^ > $(srcdir)/hb-ot-shape-complex-use-table.cc \ $(AM_V_GEN) $(builddir)/$^ > $(srcdir)/hb-ot-shape-complex-use-table.cc \
|| ($(RM) $(srcdir)/hb-ot-shape-complex-use-table.cc; false) || ($(RM) $(srcdir)/hb-ot-shape-complex-use-table.cc; false)
vowel-constraints: gen-vowel-constraints.py use Scripts.txt
$(AM_V_GEN) $(builddir)/$^ > $(srcdir)/hb-ot-shape-complex-vowel-constraints.hh \
|| ($(RM) $(srcdir)/hb-ot-shape-complex-vowel-constraints.hh; false)
emoji-table: gen-emoji-table.py emoji-data.txt emoji-table: gen-emoji-table.py emoji-data.txt
$(AM_V_GEN) $(builddir)/$^ > $(srcdir)/hb-unicode-emoji-table.hh \ $(AM_V_GEN) $(builddir)/$^ > $(srcdir)/hb-unicode-emoji-table.hh \
|| ($(RM) $(srcdir)/hb-unicode-emoji-table.hh; false) || ($(RM) $(srcdir)/hb-unicode-emoji-table.hh; false)
built-sources: $(BUILT_SOURCES) built-sources: $(BUILT_SOURCES)
.PHONY: unicode-tables arabic-table indic-table tag-table use-table emoji-table built-sources .PHONY: unicode-tables arabic-table indic-table tag-table use-table vowel-constraints emoji-table built-sources
RAGEL_GENERATED = \ RAGEL_GENERATED = \
$(patsubst %,$(srcdir)/%,$(HB_BASE_RAGEL_GENERATED_sources)) \ $(patsubst %,$(srcdir)/%,$(HB_BASE_RAGEL_GENERATED_sources)) \

View File

@ -142,6 +142,7 @@ HB_OT_sources = \
hb-ot-shape-complex-use.cc \ hb-ot-shape-complex-use.cc \
hb-ot-shape-complex-use.hh \ hb-ot-shape-complex-use.hh \
hb-ot-shape-complex-use-table.cc \ hb-ot-shape-complex-use-table.cc \
hb-ot-shape-complex-vowel-constraints.hh \
hb-ot-shape-complex.hh \ hb-ot-shape-complex.hh \
hb-ot-shape-normalize.hh \ hb-ot-shape-normalize.hh \
hb-ot-shape-normalize.cc \ hb-ot-shape-normalize.cc \

286
src/gen-vowel-constraints.py Executable file
View File

@ -0,0 +1,286 @@
#!/usr/bin/python
"""Generator of the function to prohibit certain vowel sequences.
It creates ``preprocess_text_vowel_constraints``, which inserts dotted
circles into sequences prohibited by the USE script development spec.
This function should be used as the ``preprocess_text`` of an
``hb_ot_complex_shaper_t``.
It also creates the helper function ``_output_with_dotted_circle``.
"""
from __future__ import absolute_import, division, print_function, unicode_literals
import collections
try:
from HTMLParser import HTMLParser
def write (s):
print (s.encode ('utf-8'), end='')
except ImportError:
from html.parser import HTMLParser
def write (s):
sys.stdout.flush ()
sys.stdout.buffer.write (s.encode ('utf-8'))
import itertools
import io
import sys
if len (sys.argv) != 3:
print ('usage: ./gen-vowel-constraints.py use Scripts.txt', file=sys.stderr)
sys.exit (1)
try:
from html import unescape
def html_unescape (parser, entity):
return unescape (entity)
except ImportError:
def html_unescape (parser, entity):
return parser.unescape (entity)
def expect (condition, message=None):
if not condition:
if message is None:
raise AssertionError
raise AssertionError (message)
with io.open (sys.argv[2], encoding='utf-8') as f:
scripts_header = [f.readline () for i in range (2)]
scripts = {}
script_order = {}
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)
script = fields[1]
for u in range (start, end + 1):
scripts[u] = script
if script not in script_order:
script_order[script] = start
class ConstraintSet (object):
"""A set of prohibited code point sequences.
Args:
constraint (List[int]): A prohibited code point sequence.
"""
def __init__ (self, constraint):
# Either a list or a dictionary. As a list of code points, it
# represents a prohibited code point sequence. As a dictionary,
# it represents a set of prohibited sequences, where each item
# represents the set of prohibited sequences starting with the
# key (a code point) concatenated with any of the values
# (ConstraintSets).
self._c = constraint
def add (self, constraint):
"""Add a constraint to this set."""
if not constraint:
return
first = constraint[0]
rest = constraint[1:]
if isinstance (self._c, list):
if constraint == self._c[:len (constraint)]:
self._c = constraint
elif self._c != constraint[:len (self._c)]:
self._c = {self._c[0]: ConstraintSet (self._c[1:])}
if isinstance (self._c, dict):
if first in self._c:
self._c[first].add (rest)
else:
self._c[first] = ConstraintSet (rest)
def _indent (self, depth):
return (' ' * depth).replace (' ', '\t')
def __str__ (self, index=0, depth=4):
s = []
indent = self._indent (depth)
if isinstance (self._c, list):
if len (self._c) == 0:
s.append ('{}matched = true;\n'.format (indent))
elif len (self._c) == 1:
s.append ('{}matched = 0x{:04X}u == buffer->cur ({}).codepoint;\n'.format (indent, next (iter (self._c)), index or ''))
else:
s.append ('{}if (0x{:04X}u == buffer->cur ({}).codepoint &&\n'.format (indent, self._c[0], index))
s.append ('{}buffer->idx + {} < count &&\n'.format (self._indent (depth + 2), len (self._c)))
for i, cp in enumerate (self._c[1:], start=1):
s.append ('{}0x{:04X}u == buffer->cur ({}).codepoint{}\n'.format (
self._indent (depth + 2), cp, index + i, ')' if i == len (self._c) - 1 else ' &&'))
s.append ('{}{{\n'.format (indent))
for i in range (len (self._c)):
s.append ('{}buffer->next_glyph ();\n'.format (self._indent (depth + 1)))
s.append ('{}buffer->output_glyph (0x25CCu);\n'.format (self._indent (depth + 1)))
s.append ('{}}}\n'.format (indent))
else:
s.append ('{}switch (buffer->cur ({}).codepoint)\n'.format(indent, index or ''))
s.append ('{}{{\n'.format (indent))
cases = collections.defaultdict (set)
for first, rest in sorted (self._c.items ()):
cases[rest.__str__ (index + 1, depth + 2)].add (first)
for body, labels in sorted (cases.items (), key=lambda b_ls: sorted (b_ls[1])[0]):
for i, cp in enumerate (sorted (labels)):
if i % 4 == 0:
s.append (self._indent (depth + 1))
else:
s.append (' ')
s.append ('case 0x{:04X}u:{}'.format (cp, '\n' if i % 4 == 3 else ''))
if len (labels) % 4 != 0:
s.append ('\n')
s.append (body)
s.append ('{}break;\n'.format (self._indent (depth + 2)))
s.append ('{}}}\n'.format (indent))
return ''.join (s)
class USESpecParser (HTMLParser):
"""A parser for the USE script development spec.
Attributes:
header (str): The ``updated_at`` timestamp of the spec.
constraints (Mapping[str, ConstraintSet]): A map of script names
to the scripts' prohibited sequences.
"""
def __init__ (self):
HTMLParser.__init__ (self)
self.header = ''
self.constraints = {}
# Whether the next <code> contains the vowel constraints.
self._primed = False
# Whether the parser is in the <code> element with the constraints.
self._in_constraints = False
# The text of the constraints.
self._constraints = ''
def handle_starttag (self, tag, attrs):
if tag == 'meta':
for attr, value in attrs:
if attr == 'name' and value == 'updated_at':
self.header = self.get_starttag_text ()
break
elif tag == 'a':
for attr, value in attrs:
if attr == 'id' and value == 'ivdvconstraints':
self._primed = True
break
elif self._primed and tag == 'code':
self._primed = False
self._in_constraints = True
def handle_endtag (self, tag):
self._in_constraints = False
def handle_data (self, data):
if self._in_constraints:
self._constraints += data
def handle_charref (self, name):
self.handle_data (html_unescape (self, '&#%s;' % name))
def handle_entityref (self, name):
self.handle_data (html_unescape (self, '&%s;' % name))
def parse (self, filename):
"""Parse the USE script development spec.
Args:
filename (str): The file name of the spec.
"""
with io.open (filename, encoding='utf-8') as f:
self.feed (f.read ())
expect (self.header, 'No header found')
for line in self._constraints.splitlines ():
constraint = [int (cp, 16) for cp in line.split (';')[0].strip ().split (' ')]
expect (2 <= len (constraint), 'Prohibited sequence is too short: {}'.format (constraint))
script = scripts[constraint[0]]
if script in self.constraints:
self.constraints[script].add (constraint)
else:
self.constraints[script] = ConstraintSet (constraint)
expect (self.constraints, 'No constraints found')
use_parser = USESpecParser ()
use_parser.parse (sys.argv[1])
print ('/* == Start of generated functions == */')
print ('/*')
print (' * The following functions are generated by running:')
print (' *')
print (' * %s use Scripts.txt' % sys.argv[0])
print (' *')
print (' * on files with these headers:')
print (' *')
print (' * %s' % use_parser.header.strip ())
for line in scripts_header:
print (' * %s' % line.strip ())
print (' */')
print ()
print ('#ifndef HB_OT_SHAPE_COMPLEX_VOWEL_CONSTRAINTS_HH')
print ('#define HB_OT_SHAPE_COMPLEX_VOWEL_CONSTRAINTS_HH')
print ()
print ('static void')
print ('_output_with_dotted_circle (hb_buffer_t *buffer)')
print ('{')
print (' hb_glyph_info_t &dottedcircle = buffer->output_glyph (0x25CCu);')
print (' _hb_glyph_info_reset_continuation (&dottedcircle);')
print ()
print (' buffer->next_glyph ();')
print ('}')
print ()
print ('static void')
print ('preprocess_text_vowel_constraints (const hb_ot_shape_plan_t *plan,')
print ('\t\t\t\t hb_buffer_t *buffer,')
print ('\t\t\t\t hb_font_t *font)')
print ('{')
print (' /* UGLY UGLY UGLY business of adding dotted-circle in the middle of')
print (' * vowel-sequences that look like another vowel. Data for each script')
print (' * collected from the USE script development spec.')
print (' *')
print (' * https://github.com/harfbuzz/harfbuzz/issues/1019')
print (' */')
print (' bool processed = false;')
print (' buffer->clear_output ();')
print (' unsigned int count = buffer->len;')
print (' switch ((unsigned) buffer->props.script)')
print (' {')
for script, constraints in sorted (use_parser.constraints.items (), key=lambda s_c: script_order[s_c[0]]):
print (' case HB_SCRIPT_{}:'.format (script.upper ()))
print (' for (buffer->idx = 0; buffer->idx + 1 < count && buffer->successful;)')
print (' {')
print ('\tbool matched = false;')
write (str (constraints))
print ('\tbuffer->next_glyph ();')
print ('\tif (matched) _output_with_dotted_circle (buffer);')
print (' }')
print (' processed = true;')
print (' break;')
print ()
print (' default:')
print (' break;')
print (' }')
print (' if (processed)')
print (' {')
print (' if (buffer->idx < count)')
print (' buffer->next_glyph ();')
print (' if (likely (buffer->successful))')
print (' buffer->swap_buffers ();')
print (' }')
print ('}')
print ()
print ('#endif /* HB_OT_SHAPE_COMPLEX_VOWEL_CONSTRAINTS_HH */')
print ()
print ('/* == End of generated functions == */')

View File

@ -25,6 +25,7 @@
*/ */
#include "hb-ot-shape-complex-indic.hh" #include "hb-ot-shape-complex-indic.hh"
#include "hb-ot-shape-complex-vowel-constraints.hh"
#include "hb-ot-layout.hh" #include "hb-ot-layout.hh"
@ -331,275 +332,6 @@ data_destroy_indic (void *data)
free (data); free (data);
} }
static void
_output_with_dotted_circle (hb_buffer_t *buffer)
{
hb_glyph_info_t &dottedcircle = buffer->output_glyph (0x25CCu);
_hb_glyph_info_reset_continuation (&dottedcircle);
buffer->next_glyph ();
}
static void
preprocess_text_indic (const hb_ot_shape_plan_t *plan,
hb_buffer_t *buffer,
hb_font_t *font)
{
/* UGLY UGLY UGLY business of adding dotted-circle in the middle of
* vowel-sequences that look like another vowel. Data for each script
* collected from Unicode 11 book, tables named "Vowel Letters" with
* "Use" and "Do Not Use" columns.
*
* https://github.com/harfbuzz/harfbuzz/issues/1019
*/
bool processed = false;
buffer->clear_output ();
unsigned int count = buffer->len;
switch ((unsigned) buffer->props.script)
{
case HB_SCRIPT_DEVANAGARI:
for (buffer->idx = 0; buffer->idx + 1 < count && buffer->successful;)
{
bool matched = false;
switch (buffer->cur().codepoint)
{
case 0x0905u:
switch (buffer->cur(1).codepoint)
{
case 0x093Au: case 0x093Bu: case 0x093Eu: case 0x0945u:
case 0x0946u: case 0x0949u: case 0x094Au: case 0x094Bu:
case 0x094Cu: case 0x094Fu: case 0x0956u: case 0x0957u:
matched = true;
break;
}
break;
case 0x0906u:
switch (buffer->cur(1).codepoint)
{
case 0x093Au: case 0x0945u: case 0x0946u: case 0x0947u:
case 0x0948u:
matched = true;
break;
}
break;
case 0x0909u:
switch (buffer->cur(1).codepoint)
{
case 0x0941u:
matched = true;
break;
}
break;
case 0x090Fu:
switch (buffer->cur(1).codepoint)
{
case 0x0945u: case 0x0946u: case 0x0947u:
matched = true;
break;
}
break;
case 0x0930u:
if (0x094Du == buffer->cur(1).codepoint &&
buffer->idx + 2 < count &&
0x0907u == buffer->cur(2).codepoint)
{
buffer->next_glyph ();
buffer->next_glyph ();
buffer->output_glyph (0x25CCu);
}
break;
}
buffer->next_glyph ();
if (matched) _output_with_dotted_circle (buffer);
}
processed = true;
break;
case HB_SCRIPT_BENGALI:
for (buffer->idx = 0; buffer->idx + 1 < count && buffer->successful;)
{
bool matched = false;
switch (buffer->cur().codepoint)
{
case 0x0985u:
matched = 0x09BE == buffer->cur(1).codepoint;
break;
case 0x098Bu:
matched = 0x09C3 == buffer->cur(1).codepoint;
break;
case 0x098Cu:
matched = 0x09E2 == buffer->cur(1).codepoint;
break;
}
buffer->next_glyph ();
if (matched) _output_with_dotted_circle (buffer);
}
processed = true;
break;
case HB_SCRIPT_GURMUKHI:
for (buffer->idx = 0; buffer->idx + 1 < count && buffer->successful;)
{
bool matched = false;
switch (buffer->cur().codepoint)
{
case 0x0A05u:
switch (buffer->cur(1).codepoint)
{
case 0x0A3Eu: case 0x0A48u: case 0x0A4Cu:
matched = true;
break;
}
break;
case 0x0A72u:
switch (buffer->cur(1).codepoint)
{
case 0x0A3Fu: case 0x0A40u: case 0x0A47u:
matched = true;
break;
}
break;
case 0x0A73u:
switch (buffer->cur(1).codepoint)
{
case 0x0A41u: case 0x0A42u: case 0x0A4Bu:
matched = true;
break;
}
break;
}
buffer->next_glyph ();
if (matched) _output_with_dotted_circle (buffer);
}
processed = true;
break;
case HB_SCRIPT_GUJARATI:
for (buffer->idx = 0; buffer->idx + 1 < count && buffer->successful;)
{
bool matched = false;
switch (buffer->cur().codepoint)
{
case 0x0A85u:
switch (buffer->cur(1).codepoint)
{
case 0x0ABEu: case 0x0AC5u: case 0x0AC7u: case 0x0AC8u:
case 0x0AC9u: case 0x0ACBu: case 0x0ACCu:
matched = true;
break;
}
break;
case 0x0AC5u:
matched = 0x0ABE == buffer->cur(1).codepoint;
break;
}
buffer->next_glyph ();
if (matched) _output_with_dotted_circle (buffer);
}
processed = true;
break;
case HB_SCRIPT_ORIYA:
for (buffer->idx = 0; buffer->idx + 1 < count && buffer->successful;)
{
bool matched = false;
switch (buffer->cur().codepoint)
{
case 0x0B05u:
matched = 0x0B3E == buffer->cur(1).codepoint;
break;
case 0x0B0Fu: case 0x0B13u:
matched = 0x0B57 == buffer->cur(1).codepoint;
break;
}
buffer->next_glyph ();
if (matched) _output_with_dotted_circle (buffer);
}
processed = true;
break;
case HB_SCRIPT_TELUGU:
for (buffer->idx = 0; buffer->idx + 1 < count && buffer->successful;)
{
bool matched = false;
switch (buffer->cur().codepoint)
{
case 0x0C12u:
switch (buffer->cur(1).codepoint)
{
case 0x0C4Cu: case 0x0C55u:
matched = true;
break;
}
break;
case 0x0C3Fu: case 0x0C46u: case 0xC4Au:
matched = 0x0C55 == buffer->cur(1).codepoint;
break;
}
buffer->next_glyph ();
if (matched) _output_with_dotted_circle (buffer);
}
processed = true;
break;
case HB_SCRIPT_KANNADA:
for (buffer->idx = 0; buffer->idx + 1 < count && buffer->successful;)
{
bool matched = false;
switch (buffer->cur().codepoint)
{
case 0x0C89u: case 0x0C8Bu:
matched = 0x0CBE == buffer->cur(1).codepoint;
break;
case 0x0C92u:
matched = 0x0CCC == buffer->cur(1).codepoint;
break;
}
buffer->next_glyph ();
if (matched) _output_with_dotted_circle (buffer);
}
processed = true;
break;
case HB_SCRIPT_MALAYALAM:
for (buffer->idx = 0; buffer->idx + 1 < count && buffer->successful;)
{
bool matched = false;
switch (buffer->cur().codepoint)
{
case 0x0D07u: case 0x0D09u:
matched = 0x0D57 == buffer->cur(1).codepoint;
break;
case 0x0D0Eu:
matched = 0x0D46 == buffer->cur(1).codepoint;
break;
case 0x0D12u:
switch (buffer->cur(1).codepoint)
{
case 0x0D3Eu: case 0x0D57u:
matched = true;
break;
}
break;
}
buffer->next_glyph ();
if (matched) _output_with_dotted_circle (buffer);
}
processed = true;
break;
default:
break;
}
if (processed)
{
if (buffer->idx < count)
buffer->next_glyph ();
if (likely (buffer->successful))
buffer->swap_buffers ();
}
}
static indic_position_t static indic_position_t
consonant_position_from_face (const indic_shape_plan_t *indic_plan, consonant_position_from_face (const indic_shape_plan_t *indic_plan,
const hb_codepoint_t consonant, const hb_codepoint_t consonant,
@ -1884,7 +1616,7 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_indic =
override_features_indic, override_features_indic,
data_create_indic, data_create_indic,
data_destroy_indic, data_destroy_indic,
preprocess_text_indic, preprocess_text_vowel_constraints,
nullptr, /* postprocess_glyphs */ nullptr, /* postprocess_glyphs */
HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT, HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT,
decompose_indic, decompose_indic,

View File

@ -28,6 +28,7 @@
#include "hb-ot-shape-complex-use.hh" #include "hb-ot-shape-complex-use.hh"
#include "hb-ot-shape-complex-arabic.hh" #include "hb-ot-shape-complex-arabic.hh"
#include "hb-ot-shape-complex-vowel-constraints.hh"
/* buffer var allocations */ /* buffer var allocations */
#define use_category() complex_var_u8_0() #define use_category() complex_var_u8_0()
@ -591,7 +592,7 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_use =
nullptr, /* override_features */ nullptr, /* override_features */
data_create_use, data_create_use,
data_destroy_use, data_destroy_use,
nullptr, /* preprocess_text */ preprocess_text_vowel_constraints,
nullptr, /* postprocess_glyphs */ nullptr, /* postprocess_glyphs */
HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT, HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT,
nullptr, /* decompose */ nullptr, /* decompose */

View File

@ -0,0 +1,434 @@
/* == Start of generated functions == */
/*
* The following functions are generated by running:
*
* ./gen-vowel-constraints.py use Scripts.txt
*
* on files with these headers:
*
* <meta name="updated_at" content="2018-03-27 12:21 AM" />
* # Scripts-11.0.0.txt
* # Date: 2018-02-21, 05:34:31 GMT
*/
#ifndef HB_OT_SHAPE_COMPLEX_VOWEL_CONSTRAINTS_HH
#define HB_OT_SHAPE_COMPLEX_VOWEL_CONSTRAINTS_HH
static void
_output_with_dotted_circle (hb_buffer_t *buffer)
{
hb_glyph_info_t &dottedcircle = buffer->output_glyph (0x25CCu);
_hb_glyph_info_reset_continuation (&dottedcircle);
buffer->next_glyph ();
}
static void
preprocess_text_vowel_constraints (const hb_ot_shape_plan_t *plan,
hb_buffer_t *buffer,
hb_font_t *font)
{
/* UGLY UGLY UGLY business of adding dotted-circle in the middle of
* vowel-sequences that look like another vowel. Data for each script
* collected from the USE script development spec.
*
* https://github.com/harfbuzz/harfbuzz/issues/1019
*/
bool processed = false;
buffer->clear_output ();
unsigned int count = buffer->len;
switch ((unsigned) buffer->props.script)
{
case HB_SCRIPT_DEVANAGARI:
for (buffer->idx = 0; buffer->idx + 1 < count && buffer->successful;)
{
bool matched = false;
switch (buffer->cur ().codepoint)
{
case 0x0905u:
switch (buffer->cur (1).codepoint)
{
case 0x093Au: case 0x093Bu: case 0x093Eu: case 0x0945u:
case 0x0946u: case 0x0949u: case 0x094Au: case 0x094Bu:
case 0x094Cu: case 0x094Fu: case 0x0956u: case 0x0957u:
matched = true;
break;
}
break;
case 0x0906u:
switch (buffer->cur (1).codepoint)
{
case 0x093Au: case 0x0945u: case 0x0946u: case 0x0947u:
case 0x0948u:
matched = true;
break;
}
break;
case 0x0909u:
matched = 0x0941u == buffer->cur (1).codepoint;
break;
case 0x090Fu:
switch (buffer->cur (1).codepoint)
{
case 0x0945u: case 0x0946u: case 0x0947u:
matched = true;
break;
}
break;
case 0x0930u:
if (0x094Du == buffer->cur (1).codepoint &&
buffer->idx + 2 < count &&
0x0907u == buffer->cur (2).codepoint)
{
buffer->next_glyph ();
buffer->next_glyph ();
buffer->output_glyph (0x25CCu);
}
break;
}
buffer->next_glyph ();
if (matched) _output_with_dotted_circle (buffer);
}
processed = true;
break;
case HB_SCRIPT_BENGALI:
for (buffer->idx = 0; buffer->idx + 1 < count && buffer->successful;)
{
bool matched = false;
switch (buffer->cur ().codepoint)
{
case 0x0985u:
matched = 0x09BEu == buffer->cur (1).codepoint;
break;
case 0x098Bu:
matched = 0x09C3u == buffer->cur (1).codepoint;
break;
case 0x098Cu:
matched = 0x09E2u == buffer->cur (1).codepoint;
break;
}
buffer->next_glyph ();
if (matched) _output_with_dotted_circle (buffer);
}
processed = true;
break;
case HB_SCRIPT_GURMUKHI:
for (buffer->idx = 0; buffer->idx + 1 < count && buffer->successful;)
{
bool matched = false;
switch (buffer->cur ().codepoint)
{
case 0x0A05u:
switch (buffer->cur (1).codepoint)
{
case 0x0A3Eu: case 0x0A48u: case 0x0A4Cu:
matched = true;
break;
}
break;
case 0x0A72u:
switch (buffer->cur (1).codepoint)
{
case 0x0A3Fu: case 0x0A40u: case 0x0A47u:
matched = true;
break;
}
break;
case 0x0A73u:
switch (buffer->cur (1).codepoint)
{
case 0x0A41u: case 0x0A42u: case 0x0A4Bu:
matched = true;
break;
}
break;
}
buffer->next_glyph ();
if (matched) _output_with_dotted_circle (buffer);
}
processed = true;
break;
case HB_SCRIPT_GUJARATI:
for (buffer->idx = 0; buffer->idx + 1 < count && buffer->successful;)
{
bool matched = false;
switch (buffer->cur ().codepoint)
{
case 0x0A85u:
switch (buffer->cur (1).codepoint)
{
case 0x0ABEu: case 0x0AC5u: case 0x0AC7u: case 0x0AC8u:
case 0x0AC9u: case 0x0ACBu: case 0x0ACCu:
matched = true;
break;
}
break;
case 0x0AC5u:
matched = 0x0ABEu == buffer->cur (1).codepoint;
break;
}
buffer->next_glyph ();
if (matched) _output_with_dotted_circle (buffer);
}
processed = true;
break;
case HB_SCRIPT_ORIYA:
for (buffer->idx = 0; buffer->idx + 1 < count && buffer->successful;)
{
bool matched = false;
switch (buffer->cur ().codepoint)
{
case 0x0B05u:
matched = 0x0B3Eu == buffer->cur (1).codepoint;
break;
case 0x0B0Fu: case 0x0B13u:
matched = 0x0B57u == buffer->cur (1).codepoint;
break;
}
buffer->next_glyph ();
if (matched) _output_with_dotted_circle (buffer);
}
processed = true;
break;
case HB_SCRIPT_TELUGU:
for (buffer->idx = 0; buffer->idx + 1 < count && buffer->successful;)
{
bool matched = false;
switch (buffer->cur ().codepoint)
{
case 0x0C12u:
switch (buffer->cur (1).codepoint)
{
case 0x0C4Cu: case 0x0C55u:
matched = true;
break;
}
break;
case 0x0C3Fu: case 0x0C46u: case 0x0C4Au:
matched = 0x0C55u == buffer->cur (1).codepoint;
break;
}
buffer->next_glyph ();
if (matched) _output_with_dotted_circle (buffer);
}
processed = true;
break;
case HB_SCRIPT_KANNADA:
for (buffer->idx = 0; buffer->idx + 1 < count && buffer->successful;)
{
bool matched = false;
switch (buffer->cur ().codepoint)
{
case 0x0C89u: case 0x0C8Bu:
matched = 0x0CBEu == buffer->cur (1).codepoint;
break;
case 0x0C92u:
matched = 0x0CCCu == buffer->cur (1).codepoint;
break;
}
buffer->next_glyph ();
if (matched) _output_with_dotted_circle (buffer);
}
processed = true;
break;
case HB_SCRIPT_MALAYALAM:
for (buffer->idx = 0; buffer->idx + 1 < count && buffer->successful;)
{
bool matched = false;
switch (buffer->cur ().codepoint)
{
case 0x0D07u: case 0x0D09u:
matched = 0x0D57u == buffer->cur (1).codepoint;
break;
case 0x0D0Eu:
matched = 0x0D46u == buffer->cur (1).codepoint;
break;
case 0x0D12u:
switch (buffer->cur (1).codepoint)
{
case 0x0D3Eu: case 0x0D57u:
matched = true;
break;
}
break;
}
buffer->next_glyph ();
if (matched) _output_with_dotted_circle (buffer);
}
processed = true;
break;
case HB_SCRIPT_SINHALA:
for (buffer->idx = 0; buffer->idx + 1 < count && buffer->successful;)
{
bool matched = false;
switch (buffer->cur ().codepoint)
{
case 0x0D85u:
switch (buffer->cur (1).codepoint)
{
case 0x0DCFu: case 0x0DD0u: case 0x0DD1u:
matched = true;
break;
}
break;
case 0x0D8Bu: case 0x0D8Fu: case 0x0D94u:
matched = 0x0DDFu == buffer->cur (1).codepoint;
break;
case 0x0D8Du:
matched = 0x0DD8u == buffer->cur (1).codepoint;
break;
case 0x0D91u:
switch (buffer->cur (1).codepoint)
{
case 0x0DCAu: case 0x0DD9u: case 0x0DDAu: case 0x0DDCu:
case 0x0DDDu:
matched = true;
break;
}
break;
}
buffer->next_glyph ();
if (matched) _output_with_dotted_circle (buffer);
}
processed = true;
break;
case HB_SCRIPT_BRAHMI:
for (buffer->idx = 0; buffer->idx + 1 < count && buffer->successful;)
{
bool matched = false;
switch (buffer->cur ().codepoint)
{
case 0x11005u:
matched = 0x11038u == buffer->cur (1).codepoint;
break;
case 0x1100Bu:
matched = 0x1103Eu == buffer->cur (1).codepoint;
break;
case 0x1100Fu:
matched = 0x11042u == buffer->cur (1).codepoint;
break;
}
buffer->next_glyph ();
if (matched) _output_with_dotted_circle (buffer);
}
processed = true;
break;
case HB_SCRIPT_KHUDAWADI:
for (buffer->idx = 0; buffer->idx + 1 < count && buffer->successful;)
{
bool matched = false;
switch (buffer->cur ().codepoint)
{
case 0x112B0u:
switch (buffer->cur (1).codepoint)
{
case 0x112E0u: case 0x112E5u: case 0x112E6u: case 0x112E7u:
case 0x112E8u:
matched = true;
break;
}
break;
}
buffer->next_glyph ();
if (matched) _output_with_dotted_circle (buffer);
}
processed = true;
break;
case HB_SCRIPT_TIRHUTA:
for (buffer->idx = 0; buffer->idx + 1 < count && buffer->successful;)
{
bool matched = false;
switch (buffer->cur ().codepoint)
{
case 0x11481u:
matched = 0x114B0u == buffer->cur (1).codepoint;
break;
case 0x1148Bu: case 0x1148Du:
matched = 0x114BAu == buffer->cur (1).codepoint;
break;
case 0x114AAu:
switch (buffer->cur (1).codepoint)
{
case 0x114B5u: case 0x114B6u:
matched = true;
break;
}
break;
}
buffer->next_glyph ();
if (matched) _output_with_dotted_circle (buffer);
}
processed = true;
break;
case HB_SCRIPT_MODI:
for (buffer->idx = 0; buffer->idx + 1 < count && buffer->successful;)
{
bool matched = false;
switch (buffer->cur ().codepoint)
{
case 0x11600u: case 0x11601u:
switch (buffer->cur (1).codepoint)
{
case 0x11639u: case 0x1163Au:
matched = true;
break;
}
break;
}
buffer->next_glyph ();
if (matched) _output_with_dotted_circle (buffer);
}
processed = true;
break;
case HB_SCRIPT_TAKRI:
for (buffer->idx = 0; buffer->idx + 1 < count && buffer->successful;)
{
bool matched = false;
switch (buffer->cur ().codepoint)
{
case 0x11680u:
switch (buffer->cur (1).codepoint)
{
case 0x116ADu: case 0x116B4u: case 0x116B5u:
matched = true;
break;
}
break;
case 0x11686u:
matched = 0x116B2u == buffer->cur (1).codepoint;
break;
}
buffer->next_glyph ();
if (matched) _output_with_dotted_circle (buffer);
}
processed = true;
break;
default:
break;
}
if (processed)
{
if (buffer->idx < count)
buffer->next_glyph ();
if (likely (buffer->successful))
buffer->swap_buffers ();
}
}
#endif /* HB_OT_SHAPE_COMPLEX_VOWEL_CONSTRAINTS_HH */
/* == End of generated functions == */

View File

@ -25,10 +25,10 @@ what this does is:
* If the outputs differ, recording fails. Otherwise, it will move the * If the outputs differ, recording fails. Otherwise, it will move the
subset font file into `data/in-house/fonts` and name it after its subset font file into `data/in-house/fonts` and name it after its
hash, and print out the test case input, which you can then redirect hash, and print out the test case input, which you can then redirect
to an existing or new test file in `data/in-house/tests` using `-o=`, to an existing or new test file in `data/in-house/tests` using `-o`,
e.g.: e.g.:
```sh ```sh
$ ./hb-unicode-encode 41 42 43 627 | ./record-test.sh -o=data/in-house/tests/test-name.test ../../util/hb-shape font.ttf $ ./hb-unicode-encode 41 42 43 627 | ./record-test.sh -o data/in-house/tests/test-name.test ../../util/hb-shape font.ttf
``` ```
If you created a new test file, add it to `data/in-house/Makefile.sources` If you created a new test file, add it to `data/in-house/Makefile.sources`

View File

@ -0,0 +1,94 @@
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0905,U+093A:[uni0905=0+500|uni25CC=0+500|uni093A=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0905,U+093B:[uni0905=0+500|uni25CC=0+500|uni093B=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0905,U+093E:[uni0905=0+500|uni25CC=0+500|uni093E=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0905,U+0945:[uni0905=0+500|uni25CC=0+500|uni0945=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0905,U+0946:[uni0905=0+500|uni25CC=0+500|uni0946=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0905,U+0949:[uni0905=0+500|uni25CC=0+500|uni0949=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0905,U+094A:[uni0905=0+500|uni25CC=0+500|uni094A=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0905,U+094B:[uni0905=0+500|uni25CC=0+500|uni094B=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0905,U+094C:[uni0905=0+500|uni25CC=0+500|uni094C=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0905,U+094F:[uni0905=0+500|uni25CC=0+500|uni094F=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0905,U+0956:[uni0905=0+500|uni25CC=0+500|uni0956=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0905,U+0957:[uni0905=0+500|uni25CC=0+500|uni0957=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0906,U+093A:[uni0906=0+500|uni25CC=0+500|uni093A=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0906,U+0945:[uni0906=0+500|uni25CC=0+500|uni0945=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0906,U+0946:[uni0906=0+500|uni25CC=0+500|uni0946=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0906,U+0947:[uni0906=0+500|uni25CC=0+500|uni0947=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0906,U+0948:[uni0906=0+500|uni25CC=0+500|uni0948=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0909,U+0941:[uni0909=0+500|uni25CC=0+500|uni0941=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+090F,U+0945:[uni090F=0+500|uni25CC=0+500|uni0945=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+090F,U+0946:[uni090F=0+500|uni25CC=0+500|uni0946=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+090F,U+0947:[uni090F=0+500|uni25CC=0+500|uni0947=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0930,U+094D,U+0907:[uni0930=0+500|uni094D=0+500|uni25CC=2+500|uni0907=2+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0985,U+09BE:[uni0985=0+500|uni25CC=0+500|.notdef=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+098B,U+09C3:[uni098B=0+500|uni25CC=0+500|uni09C3=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+098C,U+09E2:[uni098C=0+500|uni25CC=0+500|uni09E2=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0A05,U+0A3E:[uni0A05=0+500|uni25CC=0+500|uni0A3E=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0A05,U+0A48:[uni0A05=0+500|uni25CC=0+500|uni0A48=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0A05,U+0A4C:[uni0A05=0+500|uni25CC=0+500|uni0A4C=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0A72,U+0A3F:[uni0A72=0+500|uni0A3F=0+500|uni25CC=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0A72,U+0A40:[uni0A72=0+500|uni25CC=0+500|uni0A40=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0A72,U+0A47:[uni0A72=0+500|uni25CC=0+500|uni0A47=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0A73,U+0A41:[uni0A73=0+500|uni25CC=0+500|uni0A41=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0A73,U+0A42:[uni0A73=0+500|uni25CC=0+500|uni0A42=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0A73,U+0A4B:[uni0A73=0+500|uni25CC=0+500|uni0A4B=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0A85,U+0ABE,U+0AC5:[uni0A85=0+500|uni25CC=0+500|uni0ABE=0+500|uni25CC=0+500|uni0AC5=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0A85,U+0ABE,U+0AC8:[uni0A85=0+500|uni25CC=0+500|uni0ABE=0+500|uni25CC=0+500|uni0AC8=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0A85,U+0ABE:[uni0A85=0+500|uni25CC=0+500|uni0ABE=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0A85,U+0AC5:[uni0A85=0+500|uni25CC=0+500|uni0AC5=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0A85,U+0AC7:[uni0A85=0+500|uni25CC=0+500|uni0AC7=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0A85,U+0AC8:[uni0A85=0+500|uni25CC=0+500|uni0AC8=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0A85,U+0AC9:[uni0A85=0+500|uni25CC=0+500|uni0AC9=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0A85,U+0ACB:[uni0A85=0+500|uni25CC=0+500|uni0ACB=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0A85,U+0ACC:[uni0A85=0+500|uni25CC=0+500|uni0ACC=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0AC5,U+0ABE:[uni25CC=0+500|uni0AC5=0+500|uni25CC=0+500|uni0ABE=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0B05,U+0B3E:[uni0B05=0+500|uni25CC=0+500|uni0B3E=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0B0F,U+0B57:[uni0B0F=0+500|uni25CC=0+500|uni0B57=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0B13,U+0B57:[uni0B13=0+500|uni25CC=0+500|uni0B57=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0C12,U+0C4C:[uni0C12=0+500|uni25CC=0+500|uni0C4C=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0C12,U+0C55:[uni0C12=0+500|uni25CC=0+500|uni0C55=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0C3F,U+0C55:[uni25CC=0+500|uni0C3F=0+500|uni25CC=0+500|uni0C55=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0C46,U+0C55:[uni25CC=0+500|uni0C46=0+500|uni25CC=0+500|uni0C55=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0C4A,U+0C55:[uni25CC=0+500|uni0C4A=0+500|uni25CC=0+500|uni0C55=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0C89,U+0CBE:[uni0C89=0+500|uni25CC=0+500|uni0CBE=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0C8B,U+0CBE:[uni0C8B=0+500|uni25CC=0+500|uni0CBE=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0C92,U+0CCC:[uni0C92=0+500|uni25CC=0+500|uni0CCC=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0D07,U+0D57:[uni0D07=0+500|uni25CC=0+500|uni0D57=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0D09,U+0D57:[uni0D09=0+500|uni25CC=0+500|uni0D57=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0D0E,U+0D46:[uni0D0E=0+500|uni0D46=0+500|uni25CC=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0D12,U+0D3E:[uni0D12=0+500|uni25CC=0+500|uni0D3E=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0D12,U+0D57:[uni0D12=0+500|uni25CC=0+500|uni0D57=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0D85,U+0DCF:[uni0D85=0+500|uni25CC=0+500|uni0DCF=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0D85,U+0DD0:[uni0D85=0+500|uni25CC=0+500|uni0DD0=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0D85,U+0DD1:[uni0D85=0+500|uni25CC=0+500|uni0DD1=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0D8B,U+0DDF:[uni0D8B=0+500|uni25CC=0+500|uni0DDF=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0D8D,U+0DD8:[uni0D8D=0+500|uni25CC=0+500|uni0DD8=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0D8F,U+0DDF:[uni0D8F=0+500|uni25CC=0+500|uni0DDF=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0D91,U+0DCA:[uni0D91=0+500|uni25CC=0+500|uni0DCA=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0D91,U+0DD9:[uni0D91=0+500|uni0DD9=0+500|uni25CC=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0D91,U+0DDA:[uni0D91=0+500|uni0DD9=0+500|uni25CC=0+500|uni0DCA=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0D91,U+0DDC:[uni0D91=0+500|uni0DD9=0+500|uni25CC=0+500|uni0DCF=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0D91,U+0DDD:[uni0D91=0+500|uni0DD9=0+500|uni25CC=0+500|uni0DCF=0+500|uni0DCA=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0D91,U+0DDD:[uni0D91=0+500|uni0DD9=0+500|uni25CC=0+500|uni0DCF=0+500|uni0DCA=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+0D94,U+0DDF:[uni0D94=0+500|uni25CC=0+500|uni0DDF=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+11005,U+11038:[u11005=0+500|uni25CC=0+500|u11038=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+1100B,U+1103E:[u1100B=0+500|uni25CC=0+500|u1103E=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+1100F,U+11042:[u1100F=0+500|uni25CC=0+500|u11042=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+112B0,U+112E0:[u112B0=0+500|uni25CC=0+500|u112E0=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+112B0,U+112E5:[u112B0=0+500|uni25CC=0+500|u112E5=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+112B0,U+112E6:[u112B0=0+500|uni25CC=0+500|u112E6=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+112B0,U+112E7:[u112B0=0+500|uni25CC=0+500|u112E7=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+112B0,U+112E8:[u112B0=0+500|uni25CC=0+500|u112E8=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+11481,U+114B0:[u11481=0+500|uni25CC=0+500|u114B0=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+1148B,U+114BA:[u1148B=0+500|uni25CC=0+500|u114BA=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+1148D,U+114BA:[u1148D=0+500|uni25CC=0+500|u114BA=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+114AA,U+114B5:[u114AA=0+500|uni25CC=0+500|u114B5=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+114AA,U+114B6:[u114AA=0+500|uni25CC=0+500|u114B6=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+11600,U+11639:[u11600=0+500|uni25CC=0+500|u11639=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+11600,U+1163A:[u11600=0+500|uni25CC=0+500|u1163A=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+11601,U+11639:[u11601=0+500|uni25CC=0+500|u11639=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+11601,U+1163A:[u11601=0+500|uni25CC=0+500|u1163A=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+11680,U+116AD:[u11680=0+500|uni25CC=0+500|u116AD=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+11680,U+116B4:[u11680=0+500|uni25CC=0+500|u116B4=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+11680,U+116B5:[u11680=0+500|uni25CC=0+500|u116B5=0+500]
../fonts/46669c8860cbfea13562a6ca0d83130ee571137b.ttf::U+11686,U+116B2:[u11686=0+500|uni25CC=0+500|u116B2=0+500]