-General fixes:
-=============
-
-- Implement 'rand' feature.
-
-
API issues:
===========
- Add hb-cairo glue
-- Add sanitize API (and a cached version, that saves result on blob user-data)
+- Add sanitize API.
- BCP 47 language handling / API (language_matches?)
-- Add hb_font_create_unscaled()?
-
- Add query / enumeration API for aalt-like features?
- Add segmentation API
AM_INIT_AUTOMAKE([1.13.0 gnits tar-ustar dist-bzip2 no-dist-gzip -Wall no-define color-tests -Wno-portability])
AM_SILENT_RULES([yes])
AX_CODE_COVERAGE
+AC_USE_SYSTEM_EXTENSIONS
# Initialize libtool
m4_ifdef([AM_PROG_AR], [AM_PROG_AR])
LT_INIT([disable-static])
# Check for programs
-AC_USE_SYSTEM_EXTENSIONS
AC_PROG_CC
AC_PROG_CC_C99
AM_PROG_CC_C_O
template <typename context_t>
inline void drive (context_t *c)
{
- hb_glyph_info_t *info = buffer->info;
-
if (!c->in_place)
buffer->clear_output ();
for (buffer->idx = 0;;)
{
unsigned int klass = buffer->idx < buffer->len ?
- machine.get_class (info[buffer->idx].codepoint, num_glyphs) :
+ machine.get_class (buffer->info[buffer->idx].codepoint, num_glyphs) :
(unsigned) StateTable<EntryData>::CLASS_END_OF_TEXT;
const Entry<EntryData> *entry = machine.get_entryZ (state, klass);
if (unlikely (!entry))
hb_aat_apply_context_t *c_) :
ret (false),
c (c_),
+ mark_set (false),
mark (0),
insertionAction (table+table->insertionAction) {}
hb_buffer_t *buffer = driver->buffer;
unsigned int flags = entry->flags;
- if (entry->data.markedInsertIndex != 0xFFFF)
+ if (entry->data.markedInsertIndex != 0xFFFF && mark_set)
{
unsigned int count = (flags & MarkedInsertCount);
unsigned int start = entry->data.markedInsertIndex;
}
if (flags & SetMark)
+ {
+ mark_set = true;
mark = buffer->out_len;
+ }
return true;
}
bool ret;
private:
hb_aat_apply_context_t *c;
+ bool mark_set;
unsigned int mark;
const UnsizedArrayOf<GlyphID> &insertionAction;
};
{
static const hb_tag_t tableTag = HB_AAT_TAG_morx;
+ inline bool has_data (void) const { return version != 0; }
+
inline void apply (hb_aat_apply_context_t *c) const
{
if (unlikely (!c->buffer->successful)) return;
return morx;
}
+hb_bool_t
+hb_aat_layout_has_substitution (hb_face_t *face)
+{
+ return _get_morx (face).has_data ();
+}
+
void
hb_aat_layout_substitute (hb_font_t *font, hb_buffer_t *buffer)
{
#include "hb-buffer.hh"
#include "hb-open-type.hh"
+HB_INTERNAL hb_bool_t
+hb_aat_layout_has_substitution (hb_face_t *face);
HB_INTERNAL void
hb_aat_layout_substitute (hb_font_t *font, hb_buffer_t *buffer);
unsigned int face_length = table_count * 16 + 12;
for (unsigned int i = 0; i < table_count; i++)
- face_length += hb_ceil_to_4 (hb_blob_get_length (data->tables.arrayZ[i].blob));
+ face_length += hb_ceil_to_4 (hb_blob_get_length (data->tables[i].blob));
char *buf = (char *) malloc (face_length);
if (unlikely (!buf))
}
inline Supplier (const hb_vector_t<Type> *v)
{
- head = v->arrayZ;
+ head = v->arrayZ();
len = v->len;
stride = sizeof (Type);
}
{
TRACE_SERIALIZE (this);
if (unlikely (!c->extend_min (*this))) return_trace (false);
- Supplier<CmapSubtableLongGroup> supplier (group_data.arrayZ, group_data.len);
+ Supplier<CmapSubtableLongGroup> supplier (group_data.arrayZ(), group_data.len);
if (unlikely (!groups.serialize (c, supplier, group_data.len))) return_trace (false);
return true;
}
if (index >= index_to_offset.len)
return hb_bytes_t ();
- unsigned int offset = index_to_offset.arrayZ[index];
+ unsigned int offset = index_to_offset[index];
const uint8_t *data = pool + offset;
unsigned int name_length = *data;
plan.kerning_requested = !!plan.kern_mask;
plan.has_gpos_mark = !!plan.map.get_1_mask (HB_TAG ('m','a','r','k'));
+ plan.apply_morx = !hb_ot_layout_has_substitution (face) &&
+ hb_aat_layout_has_substitution (face);
+
bool disable_gpos = plan.shaper->gpos_tag &&
plan.shaper->gpos_tag != plan.map.chosen_script[1];
- plan.fallback_positioning = disable_gpos || !hb_ot_layout_has_positioning (face);
+ plan.apply_gpos = !disable_gpos && hb_ot_layout_has_positioning (face);
+
+ plan.fallback_positioning = !plan.apply_gpos;
plan.fallback_glyph_classes = !hb_ot_layout_has_glyph_classes (face);
}
/* Random! */
map->enable_feature (HB_TAG ('r','a','n','d'), F_RANDOM, HB_OT_MAP_MAX_VALUE);
+ map->enable_feature (HB_TAG('H','A','R','F'));
+
if (planner->shaper->collect_features)
planner->shaper->collect_features (planner);
+ map->enable_feature (HB_TAG('B','U','Z','Z'));
+
for (unsigned int i = 0; i < ARRAY_LENGTH (common_features); i++)
map->add_feature (common_features[i]);
hb_ot_shape_planner_t planner (shape_plan);
- planner.shaper = hb_ot_shape_complex_categorize (&planner);
+ /* Ugly that we have to do this here...
+ * If we are going to apply morx, choose default shaper. */
+ if (!hb_ot_layout_has_substitution (planner.face) &&
+ hb_aat_layout_has_substitution (planner.face))
+ planner.shaper = &_hb_ot_complex_shaper_default;
+ else
+ planner.shaper = hb_ot_shape_complex_categorize (&planner);
hb_ot_shape_collect_features (&planner, &shape_plan->props,
user_features, num_user_features);
if (c->plan->fallback_glyph_classes)
hb_synthesize_glyph_classes (c);
- c->plan->substitute (c->font, buffer);
-
- if (0) /* XXX Call morx instead. */
+ if (unlikely (c->plan->apply_morx))
hb_aat_layout_substitute (c->font, c->buffer);
+ else
+ c->plan->substitute (c->font, buffer);
}
static inline void
break;
}
- if (likely (!c->plan->fallback_positioning))
+ if (c->plan->apply_gpos)
c->plan->position (c->font, c->buffer);
switch (c->plan->shaper->zero_width_marks)
bool fallback_positioning : 1;
bool fallback_glyph_classes : 1;
+ bool apply_morx : 1;
+
+ bool apply_gpos : 1;
+
+
inline void collect_lookups (hb_tag_t table_tag, hb_set_t *lookups) const
{
unsigned int table_index;
if (!resize (count))
return;
population = other->population;
- memcpy (pages.arrayZ, other->pages.arrayZ, count * sizeof (pages.arrayZ[0]));
- memcpy (page_map.arrayZ, other->page_map.arrayZ, count * sizeof (page_map.arrayZ[0]));
+ memcpy (pages.arrayZ(), other->pages.arrayZ(), count * sizeof (pages.arrayZ()[0]));
+ memcpy (page_map.arrayZ(), other->page_map.arrayZ(), count * sizeof (page_map.arrayZ()[0]));
}
inline bool is_equal (const hb_set_t *other) const
return false;
}
retry:
- hb_serialize_context_t serializer (buf.arrayZ, buf_size);
+ hb_serialize_context_t serializer (buf.arrayZ(), buf_size);
hb_subset_context_t c (plan, &serializer);
result = table->subset (&c);
if (serializer.ran_out_of_room)
struct hb_vector_t
{
unsigned int len;
+ private:
unsigned int allocated; /* == 0 means allocation failed. */
- Type *arrayZ;
+ Type *arrayZ_;
Type static_array[StaticSize];
+ public:
void init (void)
{
len = 0;
allocated = ARRAY_LENGTH (static_array);
- arrayZ = static_array;
+ arrayZ_ = nullptr;
}
+ inline Type * arrayZ (void)
+ { return arrayZ_ ? arrayZ_ : static_array; }
+ inline const Type * arrayZ (void) const
+ { return arrayZ_ ? arrayZ_ : static_array; }
+
inline Type& operator [] (unsigned int i)
{
if (unlikely (i >= len))
return Crap (Type);
- return arrayZ[i];
+ return arrayZ()[i];
}
inline const Type& operator [] (unsigned int i) const
{
if (unlikely (i >= len))
return Null(Type);
- return arrayZ[i];
+ return arrayZ()[i];
}
inline Type *push (void)
{
if (unlikely (!resize (len + 1)))
return &Crap(Type);
- return &arrayZ[len - 1];
+ return &arrayZ()[len - 1];
}
inline Type *push (const Type& v)
{
Type *new_array = nullptr;
- if (arrayZ == static_array)
+ if (!arrayZ_)
{
new_array = (Type *) calloc (new_allocated, sizeof (Type));
if (new_array)
- memcpy (new_array, arrayZ, len * sizeof (Type));
+ memcpy (new_array, static_array, len * sizeof (Type));
}
else
{
bool overflows = (new_allocated < allocated) || hb_unsigned_mul_overflows (new_allocated, sizeof (Type));
if (likely (!overflows))
- new_array = (Type *) realloc (arrayZ, new_allocated * sizeof (Type));
+ new_array = (Type *) realloc (arrayZ_, new_allocated * sizeof (Type));
}
if (unlikely (!new_array))
return false;
}
- arrayZ = new_array;
+ arrayZ_ = new_array;
allocated = new_allocated;
return true;
return false;
if (size > len)
- memset (arrayZ + len, 0, (size - len) * sizeof (*arrayZ));
+ memset (arrayZ() + len, 0, (size - len) * sizeof (*arrayZ()));
len = size;
return true;
inline void remove (unsigned int i)
{
- if (unlikely (i >= len))
- return;
- memmove (static_cast<void *> (&arrayZ[i]),
- static_cast<void *> (&arrayZ[i + 1]),
- (len - i - 1) * sizeof (Type));
- len--;
+ if (unlikely (i >= len))
+ return;
+ Type *array = arrayZ();
+ memmove (static_cast<void *> (&array[i]),
+ static_cast<void *> (&array[i + 1]),
+ (len - i - 1) * sizeof (Type));
+ len--;
}
inline void shrink (int size_)
}
template <typename T>
- inline Type *find (T v) {
+ inline Type *find (T v)
+ {
+ Type *array = arrayZ();
for (unsigned int i = 0; i < len; i++)
- if (arrayZ[i] == v)
- return &arrayZ[i];
+ if (array[i] == v)
+ return &array[i];
return nullptr;
}
template <typename T>
- inline const Type *find (T v) const {
+ inline const Type *find (T v) const
+ {
+ const Type *array = arrayZ();
for (unsigned int i = 0; i < len; i++)
- if (arrayZ[i] == v)
- return &arrayZ[i];
+ if (array[i] == v)
+ return &array[i];
return nullptr;
}
inline void qsort (int (*cmp)(const void*, const void*))
{
- ::qsort (arrayZ, len, sizeof (Type), cmp);
+ ::qsort (arrayZ(), len, sizeof (Type), cmp);
}
inline void qsort (void)
{
- ::qsort (arrayZ, len, sizeof (Type), Type::cmp);
+ ::qsort (arrayZ(), len, sizeof (Type), Type::cmp);
}
inline void qsort (unsigned int start, unsigned int end)
{
- ::qsort (arrayZ + start, end - start, sizeof (Type), Type::cmp);
+ ::qsort (arrayZ() + start, end - start, sizeof (Type), Type::cmp);
}
template <typename T>
inline Type *lsearch (const T &x)
{
+ Type *array = arrayZ();
for (unsigned int i = 0; i < len; i++)
- if (0 == this->arrayZ[i].cmp (&x))
- return &arrayZ[i];
+ if (0 == array[i].cmp (&x))
+ return &array[i];
+ return nullptr;
+ }
+ template <typename T>
+ inline const Type *lsearch (const T &x) const
+ {
+ const Type *array = arrayZ();
+ for (unsigned int i = 0; i < len; i++)
+ if (0 == array[i].cmp (&x))
+ return &array[i];
return nullptr;
}
inline Type *bsearch (const T &x)
{
unsigned int i;
- return bfind (x, &i) ? &arrayZ[i] : nullptr;
+ return bfind (x, &i) ? &arrayZ()[i] : nullptr;
}
template <typename T>
inline const Type *bsearch (const T &x) const
{
unsigned int i;
- return bfind (x, &i) ? &arrayZ[i] : nullptr;
+ return bfind (x, &i) ? &arrayZ()[i] : nullptr;
}
template <typename T>
inline bool bfind (const T &x, unsigned int *i) const
{
int min = 0, max = (int) this->len - 1;
+ const Type *array = this->arrayZ();
while (min <= max)
{
int mid = (min + max) / 2;
- int c = this->arrayZ[mid].cmp (&x);
+ int c = array[mid].cmp (&x);
if (c < 0)
max = mid - 1;
else if (c > 0)
return true;
}
}
- if (max < 0 || (max < (int) this->len && this->arrayZ[max].cmp (&x) > 0))
+ if (max < 0 || (max < (int) this->len && array[max].cmp (&x) > 0))
max++;
*i = max;
return false;
}
+ inline void fini_deep (void)
+ {
+ Type *array = arrayZ();
+ unsigned int count = len;
+ for (unsigned int i = 0; i < count; i++)
+ array[i].fini ();
+ fini ();
+ }
+
inline void fini (void)
{
- if (arrayZ != static_array)
- free (arrayZ);
- arrayZ = nullptr;
+ if (arrayZ_)
+ free (arrayZ_);
+ arrayZ_ = nullptr;
allocated = len = 0;
}
};
+# https://github.com/harfbuzz/harfbuzz/issues/1224
+tests/MORX-35.tests
+
# Non-Unicode cmap
tests/CMAP-3.tests
-# Not hooked up
-tests/MORX-1.tests
-tests/MORX-2.tests
-tests/MORX-3.tests
-tests/MORX-4.tests
-tests/MORX-5.tests
-tests/MORX-6.tests
-tests/MORX-7.tests
-tests/MORX-8.tests
-tests/MORX-9.tests
-tests/MORX-10.tests
-tests/MORX-11.tests
-tests/MORX-12.tests
-tests/MORX-13.tests
-tests/MORX-14.tests
-tests/MORX-16.tests
-tests/MORX-17.tests
-tests/MORX-18.tests
-tests/MORX-19.tests
-tests/MORX-20.tests
-tests/MORX-21.tests
-tests/MORX-22.tests
-tests/MORX-23.tests
-tests/MORX-25.tests
-tests/MORX-26.tests
-tests/MORX-27.tests
-tests/MORX-28.tests
-tests/MORX-29.tests
-tests/MORX-30.tests
-tests/MORX-31.tests
-tests/MORX-32.tests
-
# Rounding differences
tests/SHARAN-1.tests
tests/SHBALI-1.tests
tests/GPOS-5.tests \
tests/GSUB-1.tests \
tests/GSUB-2.tests \
+ tests/GSUB-3.tests \
tests/GVAR-1.tests \
tests/GVAR-2.tests \
tests/GVAR-3.tests \
tests/HVAR-2.tests \
tests/KERN-1.tests \
tests/KERN-2.tests \
- tests/SHBALI-3.tests \
- tests/SHKNDA-1.tests \
- $(NULL)
-
-DISBALED_TESTS = \
- tests/CMAP-3.tests \
tests/MORX-10.tests \
tests/MORX-11.tests \
tests/MORX-12.tests \
tests/MORX-21.tests \
tests/MORX-22.tests \
tests/MORX-23.tests \
+ tests/MORX-24.tests \
tests/MORX-25.tests \
tests/MORX-26.tests \
tests/MORX-27.tests \
tests/MORX-30.tests \
tests/MORX-31.tests \
tests/MORX-32.tests \
+ tests/MORX-33.tests \
+ tests/MORX-34.tests \
+ tests/MORX-36.tests \
tests/MORX-3.tests \
tests/MORX-4.tests \
tests/MORX-5.tests \
tests/MORX-7.tests \
tests/MORX-8.tests \
tests/MORX-9.tests \
+ tests/SHBALI-3.tests \
+ tests/SHKNDA-1.tests \
+ $(NULL)
+
+DISBALED_TESTS = \
+ tests/MORX-35.tests \
+ tests/CMAP-3.tests \
tests/SHARAN-1.tests \
tests/SHBALI-1.tests \
tests/SHBALI-2.tests \
html = ET.fromstring(sys.stdin.read())
found = False
+
for elt in html.findall(".//*[@class='expected'][@ft:id]", namespaces):
found = True
name = elt.get(ns('ft:id'))
text = elt.get(ns('ft:render'))
font = elt.get(ns('ft:font'))
- vars = elt.get(ns('ft:var'), '').replace(':', '=').replace(';', ',')
+ variations = elt.get(ns('ft:var'), '').replace(':', '=').replace(';', ',')
glyphs = []
for use in elt.findall(".//use"):
x = int(use.get('x'))
glyphname = '.'.join(href[1:].split('/')[1].split('.')[1:])
glyphs.append((glyphname, x, y))
opts = '--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft'
- if vars:
- opts = opts + ' --variations=%s' % vars
+ if variations:
+ opts = opts + ' --variations=%s' % variations
print ("../fonts/%s:%s:%s:%s" % (font, opts, unistr(text), glyphstr(glyphs)))
+for elt in html.findall(".//*[@class='should-not-crash'][@ft:id]", namespaces):
+ found = True
+ name = elt.get(ns('ft:id'))
+ text = elt.get(ns('ft:render'))
+ font = elt.get(ns('ft:font'))
+ variations = elt.get(ns('ft:var'), '').replace(':', '=').replace(';', ',')
+ opts = ''
+ if variations:
+ opts = '--variations=%s' % variations
+ print ("../fonts/%s:%s:%s:*" % (font, opts, unistr(text)))
+
sys.exit(0 if found else 1)
--- /dev/null
+../fonts/TestGSUBThree.ttf::U+006C,U+006F,U+006C:*
--- /dev/null
+../fonts/TestMORXTwentyfour.ttf::U+0041,U+0042,U+0043,U+0044,U+0045:*
-../fonts/TestMORXThirtytwo.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041:[I|N@830,0|S@1660,0|A@2490,0]
-../fonts/TestMORXThirtytwo.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0058,U+0041,U+0059:[I|N@830,0|S@1660,0|X@2490,0|A@2854,0|Y@3684,0]
-../fonts/TestMORXThirtytwo.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0042:[B|I@830,0|N@1660,0|S@2490,0]
-../fonts/TestMORXThirtytwo.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0058,U+0042,U+0059:[X|I@364,0|N@1194,0|S@2024,0|B@2854,0|Y@3684,0]
+../fonts/TestMORXThirtytwo.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041:[A]
+../fonts/TestMORXThirtytwo.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0058,U+0041,U+0059:[X|A@364,0|Y@1194,0]
+../fonts/TestMORXThirtytwo.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0042:[B]
+../fonts/TestMORXThirtytwo.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0058,U+0042,U+0059:[X|B@364,0|Y@1194,0]
--- /dev/null
+../fonts/TestMORXThirtythree.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0068,U+0061:[h|a@618,0|h@1179,0|a@1797,0]
+../fonts/TestMORXThirtythree.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0068,U+0061,U+0068,U+0061:[h|a@618,0|h@1179,0|a@1797,0|h@2358,0|a@2976,0|h@3537,0|a@4155,0]
+../fonts/TestMORXThirtythree.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0061,U+0068:[a|h@561,0]
--- /dev/null
+../fonts/TestMORXThirtyfour.ttf::U+0068,U+0061:*
--- /dev/null
+../fonts/TestMORXThirtyfive.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041:[A|B@639,0|C@1265,0]
+../fonts/TestMORXThirtyfive.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0058,U+0041,U+0059:[X|A@586,0|B@1225,0|C@1851,0|E@2447,0|Y@3003,0]
--- /dev/null
+../fonts/TestMORXThirtysix.ttf::U+0041:*
sys.exit (1)
hb_shape, args = args[0], args[1:]
-extra_options = "--verify"
-
fails = 0
reference = False
cwd = os.path.dirname(filename)
fontfile = os.path.normpath (os.path.join (cwd, fontfile))
+ extra_options = ["--shaper=ot"]
+ glyphs_expected = glyphs_expected.strip()
+ if glyphs_expected != '*':
+ extra_options.append("--verify")
+
if line.startswith ("#"):
if not reference:
print ("# %s %s --unicodes %s" % (hb_shape, fontfile, unicodes))
if not reference:
print ("%s %s %s %s --unicodes %s" %
- (hb_shape, fontfile, extra_options, options, unicodes))
+ (hb_shape, fontfile, ' '.join(extra_options), options, unicodes))
glyphs1, returncode = cmd ([hb_shape, "--font-funcs=ft",
- fontfile, extra_options, "--unicodes",
+ fontfile] + extra_options + ["--unicodes",
unicodes] + (options.split (' ') if options else []))
if returncode:
- print ("hb-shape --font-funcs=ft failed.") # file=sys.stderr
+ print ("ERROR: hb-shape --font-funcs=ft failed.") # file=sys.stderr
fails = fails + 1
#continue
glyphs2, returncode = cmd ([hb_shape, "--font-funcs=ot",
- fontfile, extra_options, "--unicodes",
+ fontfile] + extra_options + ["--unicodes",
unicodes] + (options.split (' ') if options else []))
if returncode:
fails = fails + 1
#continue
- if glyphs1 != glyphs2:
+ if glyphs1 != glyphs2 and glyphs_expected != '*':
print ("FT funcs: " + glyphs1) # file=sys.stderr
print ("OT funcs: " + glyphs2) # file=sys.stderr
fails = fails + 1
print (":".join ([fontfile, options, unicodes, glyphs1]))
continue
- if glyphs1.strip() != glyphs_expected.strip() and glyphs_expected.strip() != '*':
+ if glyphs1.strip() != glyphs_expected and glyphs_expected != '*':
print ("Actual: " + glyphs1) # file=sys.stderr
print ("Expected: " + glyphs_expected) # file=sys.stderr
fails = fails + 1
void init (hb_buffer_t *buffer, const font_options_t *font_opts)
{
lines = g_array_new (false, false, sizeof (helper_cairo_line_t));
- scale_bits = -font_opts->subpixel_bits;
+ scale_bits = - (int) font_opts->subpixel_bits;
}
void new_line (void)
{