Merge pull request #3437 from matthiasclasen/synthesize-missing-baselines
[BASE] Synthesize missing baselines
diff --git a/BUILD.md b/BUILD.md
index f64f868..47681ec 100644
--- a/BUILD.md
+++ b/BUILD.md
@@ -18,7 +18,8 @@
On Windows, meson can build the project like above if a working MSVC's cl.exe (`vcvarsall.bat`)
or gcc/clang is already on your path, and if you use something like `meson build --wrap-mode=default`
-it fetches and compiles most of the dependencies also.
+it fetches and compiles most of the dependencies also. It is recommended to install CMake either
+manually or via the Visual Studio installer when building with MSVC when building with meson.
Our CI configurations is also a good source of learning how to build HarfBuzz.
diff --git a/docs/harfbuzz-sections.txt b/docs/harfbuzz-sections.txt
index f81058b..0f44e9a 100644
--- a/docs/harfbuzz-sections.txt
+++ b/docs/harfbuzz-sections.txt
@@ -565,12 +565,6 @@
hb_ot_layout_table_select_script
hb_ot_shape_plan_collect_lookups
hb_ot_layout_language_get_required_feature_index
-<SUBSECTION Private>
-Xhb_ot_layout_lookup_enumerate_sequences
-Xhb_ot_layout_lookup_position
-Xhb_ot_layout_lookup_substitute
-hb_ot_layout_glyph_sequence_t
-hb_ot_layout_glyph_sequence_func_t
</SECTION>
<SECTION>
diff --git a/meson.build b/meson.build
index 8a9400c..e22859a 100644
--- a/meson.build
+++ b/meson.build
@@ -83,50 +83,25 @@
m_dep = cpp.find_library('m', required: false)
-freetype_dep = null_dep
-if not get_option('freetype').disabled()
- freetype_dep = dependency('freetype2', required: false)
-
- if (not freetype_dep.found() and
- cpp.get_id() == 'msvc' and
- cpp.has_header('ft2build.h'))
- freetype_dep = cpp.find_library('freetype', required: false)
- endif
-
- if not freetype_dep.found()
- # https://github.com/harfbuzz/harfbuzz/pull/2498
- freetype_dep = dependency('freetype2', required: get_option('freetype'),
- default_options: ['harfbuzz=disabled'])
- endif
-endif
+# https://github.com/harfbuzz/harfbuzz/pull/2498
+freetype_dep = dependency(cpp.get_argument_syntax() == 'msvc' ? 'freetype' : 'freetype2',
+ required: get_option('freetype'),
+ default_options: ['harfbuzz=disabled'])
glib_dep = dependency('glib-2.0', required: get_option('glib'))
gobject_dep = dependency('gobject-2.0', required: get_option('gobject'))
graphite2_dep = dependency('graphite2', required: get_option('graphite2'))
graphite_dep = dependency('graphite2', required: get_option('graphite'))
-icu_dep = null_dep
-if not get_option('icu').disabled()
- icu_dep = dependency('icu-uc', required: false)
-
- if (not icu_dep.found() and
- cpp.get_id() == 'msvc' and
- cpp.has_header('unicode/uchar.h') and
- cpp.has_header('unicode/unorm2.h') and
- cpp.has_header('unicode/ustring.h') and
- cpp.has_header('unicode/utf16.h') and
- cpp.has_header('unicode/uversion.h') and
- cpp.has_header('unicode/uscript.h'))
- if get_option('buildtype') == 'debug'
- icu_dep = cpp.find_library('icuucd', required: false)
- else
- icu_dep = cpp.find_library('icuuc', required: false)
- endif
- endif
-
- if not icu_dep.found()
- icu_dep = dependency('icu-uc', required: get_option('icu'))
- endif
+if cpp.get_argument_syntax() == 'msvc'
+ icu_dep = dependency('ICU',
+ required: get_option('icu'),
+ components: 'uc',
+ method: 'cmake')
+else
+ icu_dep = dependency('icu-uc',
+ required: get_option('icu'),
+ method: 'pkg-config')
endif
if icu_dep.found() and icu_dep.type_name() == 'pkgconfig'
diff --git a/src/hb-algs.hh b/src/hb-algs.hh
index 23bb42e..c40a55c 100644
--- a/src/hb-algs.hh
+++ b/src/hb-algs.hh
@@ -226,14 +226,8 @@
template <typename T> constexpr auto
impl (const T& v, hb_priority<2>) const HB_RETURN (uint32_t, hb_deref (v).hash ())
-/* Sadly, we must give further hints to VS2015 to build the following template item */
-#if !defined (_MSC_VER) || defined (__clang__) || (_MSC_VER >= 1910)
template <typename T> constexpr auto
impl (const T& v, hb_priority<1>) const HB_RETURN (uint32_t, std::hash<hb_decay<decltype (hb_deref (v))>>{} (hb_deref (v)))
-#else
- template <typename T> constexpr auto
- impl (const T& v, hb_priority<1>) const HB_RETURN (uint32_t, std::hash<hb_decay<decltype (hb_deref (v).hash ())>>{} (hb_deref (v)))
-#endif
template <typename T,
hb_enable_if (std::is_integral<T>::value)> constexpr auto
diff --git a/src/hb-config.hh b/src/hb-config.hh
index 5141ad8..4b46dea 100644
--- a/src/hb-config.hh
+++ b/src/hb-config.hh
@@ -85,6 +85,7 @@
#ifdef HB_MINI
#define HB_NO_AAT
#define HB_NO_LEGACY
+#define HB_NO_BORING_EXPANSION
#endif
#if defined(HAVE_CONFIG_OVERRIDE_H) || defined(HB_CONFIG_OVERRIDE_H)
diff --git a/src/hb-machinery.hh b/src/hb-machinery.hh
index b529173..e52a6a4 100644
--- a/src/hb-machinery.hh
+++ b/src/hb-machinery.hh
@@ -273,14 +273,19 @@
hb_face_lazy_loader_t<T, WheresFace>,
hb_face_t, WheresFace> {};
-template <typename T, unsigned int WheresFace>
+template <typename T, unsigned int WheresFace, bool core=false>
struct hb_table_lazy_loader_t : hb_lazy_loader_t<T,
- hb_table_lazy_loader_t<T, WheresFace>,
+ hb_table_lazy_loader_t<T, WheresFace, core>,
hb_face_t, WheresFace,
hb_blob_t>
{
static hb_blob_t *create (hb_face_t *face)
- { return hb_sanitize_context_t ().reference_table<T> (face); }
+ {
+ auto c = hb_sanitize_context_t ();
+ if (core)
+ c.set_num_glyphs (0); // So we don't recurse ad infinitum...
+ return c.reference_table<T> (face);
+ }
static void destroy (hb_blob_t *p) { hb_blob_destroy (p); }
static const hb_blob_t *get_null ()
diff --git a/src/hb-ot-face-table-list.hh b/src/hb-ot-face-table-list.hh
index eff0983..c05034b 100644
--- a/src/hb-ot-face-table-list.hh
+++ b/src/hb-ot-face-table-list.hh
@@ -32,6 +32,11 @@
#define HB_OT_FACE_TABLE_LIST_HH
#endif /* HB_OT_FACE_TABLE_LIST_HH */ /* Dummy header guards */
+#ifndef HB_OT_CORE_TABLE
+#define HB_OT_CORE_TABLE(Namespace, Type) HB_OT_TABLE (Namespace, Type)
+#define _HB_OT_CORE_TABLE_UNDEF
+#endif
+
#ifndef HB_OT_ACCELERATOR
#define HB_OT_ACCELERATOR(Namespace, Type) HB_OT_TABLE (Namespace, Type)
#define _HB_OT_ACCELERATOR_UNDEF
@@ -46,7 +51,8 @@
/* OpenType fundamentals. */
-HB_OT_TABLE (OT, head)
+HB_OT_CORE_TABLE (OT, head)
+HB_OT_CORE_TABLE (OT, maxp)
#if !defined(HB_NO_FACE_COLLECT_UNICODES) || !defined(HB_NO_OT_FONT)
HB_OT_ACCELERATOR (OT, cmap)
#endif
@@ -74,6 +80,7 @@
#endif
/* TrueType outlines. */
+HB_OT_CORE_TABLE (OT, loca) // Also used to determine number of glyphs
HB_OT_ACCELERATOR (OT, glyf)
/* CFF outlines. */
@@ -138,3 +145,7 @@
#ifdef _HB_OT_ACCELERATOR_UNDEF
#undef HB_OT_ACCELERATOR
#endif
+
+#ifdef _HB_OT_CORE_TABLE_UNDEF
+#undef HB_OT_CORE_TABLE
+#endif
diff --git a/src/hb-ot-face.hh b/src/hb-ot-face.hh
index e24d380..415dae8 100644
--- a/src/hb-ot-face.hh
+++ b/src/hb-ot-face.hh
@@ -63,10 +63,13 @@
hb_face_t *face; /* MUST be JUST before the lazy loaders. */
#define HB_OT_TABLE(Namespace, Type) \
hb_table_lazy_loader_t<Namespace::Type, HB_OT_TABLE_ORDER (Namespace, Type)> Type;
+#define HB_OT_CORE_TABLE(Namespace, Type) \
+ hb_table_lazy_loader_t<Namespace::Type, HB_OT_TABLE_ORDER (Namespace, Type), true> Type;
#define HB_OT_ACCELERATOR(Namespace, Type) \
hb_face_lazy_loader_t<Namespace::Type##_accelerator_t, HB_OT_TABLE_ORDER (Namespace, Type)> Type;
#include "hb-ot-face-table-list.hh"
#undef HB_OT_ACCELERATOR
+#undef HB_OT_CORE_TABLE
#undef HB_OT_TABLE
};
diff --git a/src/hb-ot-glyf-table.hh b/src/hb-ot-glyf-table.hh
index 2c26a8d..066e152 100644
--- a/src/hb-ot-glyf-table.hh
+++ b/src/hb-ot-glyf-table.hh
@@ -936,7 +936,7 @@
return;
short_offset = 0 == head.indexToLocFormat;
- loca_table = hb_sanitize_context_t ().reference_table<loca> (face);
+ loca_table = face->table.loca.get_blob (); // Needs no destruct!
glyf_table = hb_sanitize_context_t ().reference_table<glyf> (face);
#ifndef HB_NO_VAR
gvar = face->table.gvar;
@@ -951,7 +951,6 @@
}
~accelerator_t ()
{
- loca_table.destroy ();
glyf_table.destroy ();
}
diff --git a/src/hb-ot-hmtx-table.hh b/src/hb-ot-hmtx-table.hh
index 739474f..7487e40 100644
--- a/src/hb-ot-hmtx-table.hh
+++ b/src/hb-ot-hmtx-table.hh
@@ -28,6 +28,7 @@
#define HB_OT_HMTX_TABLE_HH
#include "hb-open-type.hh"
+#include "hb-ot-maxp-table.hh"
#include "hb-ot-hhea-table.hh"
#include "hb-ot-var-hvar-table.hh"
#include "hb-ot-metrics.hh"
@@ -98,12 +99,12 @@
hb_requires (hb_is_iterator (Iterator))>
void serialize (hb_serialize_context_t *c,
Iterator it,
- unsigned num_advances)
+ unsigned num_long_metrics)
{
unsigned idx = 0;
for (auto _ : it)
{
- if (idx < num_advances)
+ if (idx < num_long_metrics)
{
LongMetric lm;
lm.advance = _.first;
@@ -128,17 +129,17 @@
if (unlikely (!table_prime)) return_trace (false);
accelerator_t _mtx (c->plan->source);
- unsigned num_advances;
+ unsigned num_long_metrics;
{
- /* Determine num_advances to encode. */
+ /* Determine num_long_metrics to encode. */
auto& plan = c->plan;
- num_advances = plan->num_output_glyphs ();
+ num_long_metrics = plan->num_output_glyphs ();
hb_codepoint_t old_gid = 0;
- unsigned int last_advance = plan->old_gid_for_new_gid (num_advances - 1, &old_gid) ? _mtx.get_advance (old_gid) : 0;
- while (num_advances > 1 &&
- last_advance == (plan->old_gid_for_new_gid (num_advances - 2, &old_gid) ? _mtx.get_advance (old_gid) : 0))
+ unsigned int last_advance = plan->old_gid_for_new_gid (num_long_metrics - 1, &old_gid) ? _mtx.get_advance (old_gid) : 0;
+ while (num_long_metrics > 1 &&
+ last_advance == (plan->old_gid_for_new_gid (num_long_metrics - 2, &old_gid) ? _mtx.get_advance (old_gid) : 0))
{
- num_advances--;
+ num_long_metrics--;
}
}
@@ -153,13 +154,13 @@
})
;
- table_prime->serialize (c->serializer, it, num_advances);
+ table_prime->serialize (c->serializer, it, num_long_metrics);
if (unlikely (c->serializer->in_error ()))
return_trace (false);
// Amend header num hmetrics
- if (unlikely (!subset_update_header (c->plan, num_advances)))
+ if (unlikely (!subset_update_header (c->plan, num_long_metrics)))
return_trace (false);
return_trace (true);
@@ -172,35 +173,46 @@
accelerator_t (hb_face_t *face,
unsigned int default_advance_ = 0)
{
+ table = hb_sanitize_context_t ().reference_table<hmtxvmtx> (face, T::tableTag);
+ var_table = hb_sanitize_context_t ().reference_table<HVARVVAR> (face, T::variationsTag);
+
default_advance = default_advance_ ? default_advance_ : hb_face_get_upem (face);
- num_advances = T::is_horizontal ?
- face->table.hhea->numberOfLongMetrics :
-#ifndef HB_NO_VERTICAL
- face->table.vhea->numberOfLongMetrics
-#else
- 0
-#endif
- ;
+ /* Populate count variables and sort them out as we go */
- table = hb_sanitize_context_t ().reference_table<hmtxvmtx> (face, T::tableTag);
-
- /* Cap num_metrics() and num_advances() based on table length. */
unsigned int len = table.get_length ();
- if (unlikely (num_advances * 4 > len))
- num_advances = len / 4;
- num_metrics = num_advances + (len - 4 * num_advances) / 2;
+ if (len & 1)
+ len--;
- /* We MUST set num_metrics to zero if num_advances is zero.
+ num_long_metrics = T::is_horizontal ?
+ face->table.hhea->numberOfLongMetrics :
+#ifndef HB_NO_VERTICAL
+ face->table.vhea->numberOfLongMetrics
+#else
+ 0
+#endif
+ ;
+ if (unlikely (num_long_metrics * 4 > len))
+ num_long_metrics = len / 4;
+ len -= num_long_metrics * 4;
+
+ num_bearings = face->table.maxp->get_num_glyphs ();
+
+ if (unlikely (num_bearings < num_long_metrics))
+ num_bearings = num_long_metrics;
+ if (unlikely ((num_bearings - num_long_metrics) * 2 > len))
+ num_bearings = num_long_metrics + len / 2;
+ len -= (num_bearings - num_long_metrics) * 2;
+
+ /* We MUST set num_bearings to zero if num_long_metrics is zero.
* Our get_advance() depends on that. */
- if (unlikely (!num_advances))
- {
- num_metrics = num_advances = 0;
- table.destroy ();
- table = hb_blob_get_empty ();
- }
+ if (unlikely (!num_long_metrics))
+ num_bearings = num_long_metrics = 0;
- var_table = hb_sanitize_context_t ().reference_table<HVARVVAR> (face, T::variationsTag);
+ num_advances = num_bearings + len / 2;
+ num_glyphs = face->get_num_glyphs ();
+ if (num_glyphs < num_advances)
+ num_glyphs = num_advances;
}
~accelerator_t ()
{
@@ -210,14 +222,14 @@
int get_side_bearing (hb_codepoint_t glyph) const
{
- if (glyph < num_advances)
+ if (glyph < num_long_metrics)
return table->longMetricZ[glyph].sb;
- if (unlikely (glyph >= num_metrics))
+ if (unlikely (glyph >= num_bearings))
return 0;
- const FWORD *bearings = (const FWORD *) &table->longMetricZ[num_advances];
- return bearings[glyph - num_advances];
+ const FWORD *bearings = (const FWORD *) &table->longMetricZ[num_long_metrics];
+ return bearings[glyph - num_long_metrics];
}
int get_side_bearing (hb_font_t *font, hb_codepoint_t glyph) const
@@ -225,7 +237,7 @@
int side_bearing = get_side_bearing (glyph);
#ifndef HB_NO_VAR
- if (unlikely (glyph >= num_metrics) || !font->num_coords)
+ if (unlikely (glyph >= num_bearings) || !font->num_coords)
return side_bearing;
if (var_table.get_length ())
@@ -239,18 +251,35 @@
unsigned int get_advance (hb_codepoint_t glyph) const
{
- if (unlikely (glyph >= num_metrics))
- {
- /* If num_metrics is zero, it means we don't have the metrics table
- * for this direction: return default advance. Otherwise, it means that the
- * glyph index is out of bound: return zero. */
- if (num_metrics)
- return 0;
- else
- return default_advance;
- }
+ /* OpenType case. */
+ if (glyph < num_bearings)
+ return table->longMetricZ[hb_min (glyph, (uint32_t) num_long_metrics - 1)].advance;
- return table->longMetricZ[hb_min (glyph, (uint32_t) num_advances - 1)].advance;
+ /* If num_advances is zero, it means we don't have the metrics table
+ * for this direction: return default advance. Otherwise, there's a
+ * well-defined answer. */
+ if (unlikely (!num_advances))
+ return default_advance;
+
+#ifdef HB_NO_BORING_EXPANSION
+ return 0;
+#endif
+
+ if (unlikely (glyph >= num_glyphs))
+ return 0;
+
+ /* num_bearings <= glyph < num_glyphs;
+ * num_bearings <= num_advances */
+
+ /* TODO Optimize */
+
+ if (num_bearings == num_advances)
+ return get_advance (num_bearings - 1);
+
+ const FWORD *bearings = (const FWORD *) &table->longMetricZ[num_long_metrics];
+ const UFWORD *advances = (const UFWORD *) &bearings[num_bearings - num_long_metrics];
+
+ return advances[hb_min (glyph - num_bearings, num_advances - num_bearings - 1)];
}
unsigned int get_advance (hb_codepoint_t glyph,
@@ -259,7 +288,7 @@
unsigned int advance = get_advance (glyph);
#ifndef HB_NO_VAR
- if (unlikely (glyph >= num_metrics) || !font->num_coords)
+ if (unlikely (glyph >= num_bearings) || !font->num_coords)
return advance;
if (var_table.get_length ())
@@ -272,8 +301,12 @@
}
protected:
- unsigned int num_metrics;
- unsigned int num_advances;
+ // 0 <= num_long_metrics <= num_bearings <= num_advances <= num_glyphs
+ unsigned num_long_metrics;
+ unsigned num_bearings;
+ unsigned num_advances;
+ unsigned num_glyphs;
+
unsigned int default_advance;
private:
@@ -305,6 +338,8 @@
* the end. This allows a monospaced
* font to vary the side bearing
* values for each glyph. */
+/*UnsizedArrayOf<UFWORD>advancesX;*/
+ /* TODO Document. */
public:
DEFINE_SIZE_ARRAY (0, longMetricZ);
};
diff --git a/src/hb-ot-layout.h b/src/hb-ot-layout.h
index ca94b59..6bc44e7 100644
--- a/src/hb-ot-layout.h
+++ b/src/hb-ot-layout.h
@@ -332,31 +332,6 @@
hb_set_t *glyphs_after, /* OUT. May be NULL */
hb_set_t *glyphs_output /* OUT. May be NULL */);
-#ifdef HB_NOT_IMPLEMENTED
-typedef struct
-{
- const hb_codepoint_t *before,
- unsigned int before_length,
- const hb_codepoint_t *input,
- unsigned int input_length,
- const hb_codepoint_t *after,
- unsigned int after_length,
-} hb_ot_layout_glyph_sequence_t;
-
-typedef hb_bool_t
-(*hb_ot_layout_glyph_sequence_func_t) (hb_font_t *font,
- hb_tag_t table_tag,
- unsigned int lookup_index,
- const hb_ot_layout_glyph_sequence_t *sequence,
- void *user_data);
-
-HB_EXTERN void
-Xhb_ot_layout_lookup_enumerate_sequences (hb_face_t *face,
- hb_tag_t table_tag,
- unsigned int lookup_index,
- hb_ot_layout_glyph_sequence_func_t callback,
- void *user_data);
-#endif
/* Variations support */
@@ -411,19 +386,6 @@
hb_set_t *glyphs);
-#ifdef HB_NOT_IMPLEMENTED
-/* Note: You better have GDEF when using this API, or marks won't do much. */
-HB_EXTERN hb_bool_t
-Xhb_ot_layout_lookup_substitute (hb_font_t *font,
- unsigned int lookup_index,
- const hb_ot_layout_glyph_sequence_t *sequence,
- unsigned int out_size,
- hb_codepoint_t *glyphs_out, /* OUT */
- unsigned int *clusters_out, /* OUT */
- unsigned int *out_length /* OUT */);
-#endif
-
-
/*
* GPOS
*/
@@ -431,15 +393,6 @@
HB_EXTERN hb_bool_t
hb_ot_layout_has_positioning (hb_face_t *face);
-#ifdef HB_NOT_IMPLEMENTED
-/* Note: You better have GDEF when using this API, or marks won't do much. */
-HB_EXTERN hb_bool_t
-Xhb_ot_layout_lookup_position (hb_font_t *font,
- unsigned int lookup_index,
- const hb_ot_layout_glyph_sequence_t *sequence,
- hb_glyph_position_t *positions /* IN / OUT */);
-#endif
-
/* Optical 'size' feature info. Returns true if found.
* https://docs.microsoft.com/en-us/typography/opentype/spec/features_pt#size */
HB_EXTERN hb_bool_t
diff --git a/src/hb-static.cc b/src/hb-static.cc
index ec4b241..bd69881 100644
--- a/src/hb-static.cc
+++ b/src/hb-static.cc
@@ -33,6 +33,7 @@
#include "hb-aat-layout-feat-table.hh"
#include "hb-ot-layout-common.hh"
#include "hb-ot-cmap-table.hh"
+#include "hb-ot-glyf-table.hh"
#include "hb-ot-head-table.hh"
#include "hb-ot-maxp-table.hh"
@@ -55,17 +56,41 @@
/* hb_face_t */
+static inline unsigned
+load_num_glyphs_from_loca (const hb_face_t *face)
+{
+ unsigned ret = 0;
+
+ unsigned indexToLocFormat = face->table.head->indexToLocFormat;
+
+ if (indexToLocFormat <= 1)
+ {
+ bool short_offset = 0 == indexToLocFormat;
+ hb_blob_t *loca_blob = face->table.loca.get_blob ();
+ ret = hb_max (1u, loca_blob->length / (short_offset ? 2 : 4)) - 1;
+ }
+
+ return ret;
+}
+
+static inline unsigned
+load_num_glyphs_from_maxp (const hb_face_t *face)
+{
+ return face->table.maxp->get_num_glyphs ();
+}
+
unsigned int
hb_face_t::load_num_glyphs () const
{
- hb_sanitize_context_t c = hb_sanitize_context_t ();
- c.set_num_glyphs (0); /* So we don't recurse ad infinitum. */
- hb_blob_t *maxp_blob = c.reference_table<OT::maxp> (this);
- const OT::maxp *maxp_table = maxp_blob->as<OT::maxp> ();
+ unsigned ret = 0;
- unsigned int ret = maxp_table->get_num_glyphs ();
+#ifndef HB_NO_BORING_EXPANSION
+ ret = hb_max (ret, load_num_glyphs_from_loca (this));
+#endif
+
+ ret = hb_max (ret, load_num_glyphs_from_maxp (this));
+
num_glyphs.set_relaxed (ret);
- hb_blob_destroy (maxp_blob);
return ret;
}
diff --git a/subprojects/freetype2.wrap b/subprojects/freetype2.wrap
index cf8f307..43ab8fa 100644
--- a/subprojects/freetype2.wrap
+++ b/subprojects/freetype2.wrap
@@ -5,3 +5,4 @@
[provide]
freetype2 = freetype_dep
+freetype = freetype_dep
diff --git a/test/api/Makefile.am b/test/api/Makefile.am
index ee662cd..a2412f9 100644
--- a/test/api/Makefile.am
+++ b/test/api/Makefile.am
@@ -30,6 +30,8 @@
TEST_PROGS = \
test-aat-layout \
test-baseline \
+ test-be-glyph-advance \
+ test-be-num-glyphs \
test-blob \
test-buffer \
test-c \
diff --git a/test/api/hb-test.h b/test/api/hb-test.h
index 7390e57..840637a 100644
--- a/test/api/hb-test.h
+++ b/test/api/hb-test.h
@@ -52,6 +52,17 @@
((const char *) s)[2], \
((const char *) s)[3]))
+#define HB_FACE_ADD_TABLE(face, tag, data) \
+ do { \
+ hb_blob_t *blob = hb_blob_create_or_fail ((data), \
+ sizeof (data), \
+ HB_MEMORY_MODE_READONLY, \
+ NULL, NULL); \
+ hb_face_builder_add_table ((face), \
+ HB_TAG_CHAR4(tag), \
+ blob); \
+ hb_blob_destroy (blob); \
+ } while (0)
static inline const char *
srcdir (void)
diff --git a/test/api/meson.build b/test/api/meson.build
index 7ea2954..ab64338 100644
--- a/test/api/meson.build
+++ b/test/api/meson.build
@@ -6,6 +6,8 @@
tests = [
'test-aat-layout.c',
'test-baseline.c',
+ 'test-be-glyph-advance.c',
+ 'test-be-num-glyphs.c',
'test-blob.c',
'test-buffer.c',
'test-c.c',
diff --git a/test/api/test-be-glyph-advance.c b/test/api/test-be-glyph-advance.c
new file mode 100644
index 0000000..77fdee1
--- /dev/null
+++ b/test/api/test-be-glyph-advance.c
@@ -0,0 +1,101 @@
+/*
+ * Copyright © 2022 Behdad Esfahbod
+ *
+ * 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.
+ */
+
+#include "hb-test.h"
+
+#include <hb.h>
+
+static void
+test_maxp_and_hmtx (void)
+{
+ hb_face_t *face;
+ hb_font_t *font;
+
+ const char maxp_data[] = "\x00\x00\x50\x00" // version
+ "\x00\x05" // numGlyphs
+ ;
+ const char loca_data[18] = "";
+ const char hhea_data[36] =
+ "\x00\x01\x00\x00" /* FixedVersion<>version; * 0x00010000u for version 1.0. */
+ "\x02\x00" /* FWORD ascender; * Typographic ascent. */
+ "\x00\x10" /* FWORD descender; * Typographic descent. */
+ "\x00\x00" /* FWORD lineGap; * Typographic line gap. */
+ "\x00\x00" /* UFWORD advanceMax; * Maximum advance width/height value in metrics table. */
+ "\x00\x00" /* FWORD minLeadingBearing; * Minimum left/top sidebearing value in metrics table. */
+ "\x00\x00" /* FWORD minTrailingBearing; * Minimum right/bottom sidebearing value; */
+ "\x01\x00" /* FWORD maxExtent; * horizontal: Max(lsb + (xMax - xMin)), */
+ "\x00\x00" /* HBINT16 caretSlopeRise; * Used to calculate the slope of the,*/
+ "\x00\x00" /* HBINT16 caretSlopeRun; * 0 for vertical caret, 1 for horizontal. */
+ "\x00\x00" /* HBINT16 caretOffset; * The amount by which a slanted */
+ "\x00\x00" /* HBINT16 reserved1; * Set to 0. */
+ "\x00\x00" /* HBINT16 reserved2; * Set to 0. */
+ "\x00\x00" /* HBINT16 reserved3; * Set to 0. */
+ "\x00\x00" /* HBINT16 reserved4; * Set to 0. */
+ "\x00\x00" /* HBINT16 metricDataFormat; * 0 for current format. */
+ "\x00\x02" /* HBUINT16 numberOfLongMetrics; * Number of LongMetric entries in metric table. */
+ ;
+ const char hmtx_data[18] =
+ "\x00\x01\x00\x02" /* glyph 0 advance lsb */
+ "\x00\x03\x00\x04" /* glyph 1 advance lsb */
+ "\x00\x05" /* glyph 2 lsb */
+ "\x00\x06" /* glyph 3 lsb */
+ "\x00\x07" /* glyph 4 lsb */
+ "\x00\x08" /* glyph 5 advance */
+ "\x00\x09" /* glyph 6 advance */
+ ;
+
+ face = hb_face_builder_create ();
+ HB_FACE_ADD_TABLE (face, "maxp", maxp_data);
+ HB_FACE_ADD_TABLE (face, "loca", loca_data);
+ HB_FACE_ADD_TABLE (face, "hhea", hhea_data);
+ HB_FACE_ADD_TABLE (face, "hmtx", hmtx_data);
+ font = hb_font_create (face);
+ hb_face_destroy (face);
+ g_assert_cmpuint (hb_font_get_glyph_h_advance (font, 0), ==, 1);
+ g_assert_cmpuint (hb_font_get_glyph_h_advance (font, 1), ==, 3);
+ g_assert_cmpuint (hb_font_get_glyph_h_advance (font, 2), ==, 3);
+ g_assert_cmpuint (hb_font_get_glyph_h_advance (font, 3), ==, 3);
+ g_assert_cmpuint (hb_font_get_glyph_h_advance (font, 4), ==, 3);
+#ifndef HB_NO_BORING_EXPANSION
+ g_assert_cmpuint (hb_font_get_glyph_h_advance (font, 5), ==, 8);
+ g_assert_cmpuint (hb_font_get_glyph_h_advance (font, 6), ==, 9);
+ g_assert_cmpuint (hb_font_get_glyph_h_advance (font, 7), ==, 9);
+#endif
+ g_assert_cmpuint (hb_font_get_glyph_h_advance (font, 8), ==, 0);
+ g_assert_cmpuint (hb_font_get_glyph_h_advance (font, 9), ==, 0);
+ g_assert_cmpuint (hb_font_get_glyph_h_advance (font,10), ==, 0);
+ g_assert_cmpuint (hb_font_get_glyph_h_advance (font,11), ==, 0);
+ hb_font_destroy (font);
+}
+
+
+int
+main (int argc, char **argv)
+{
+ hb_test_init (&argc, &argv);
+
+ hb_test_add (test_maxp_and_hmtx);
+
+ return hb_test_run();
+}
diff --git a/test/api/test-be-num-glyphs.c b/test/api/test-be-num-glyphs.c
new file mode 100644
index 0000000..ab8d110
--- /dev/null
+++ b/test/api/test-be-num-glyphs.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright © 2022 Behdad Esfahbod
+ *
+ * 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.
+ */
+
+#include "hb-test.h"
+
+#include <hb.h>
+
+static void
+test_maxp_and_loca (void)
+{
+ hb_face_t *face;
+
+ const char maxp_data[] = "\x00\x00\x50\x00" // version
+ "\x00\x05" // numGlyphs
+ ;
+ const char loca_data[18] = "";
+
+ face = hb_face_builder_create ();
+ g_assert_cmpuint (hb_face_get_glyph_count (face), ==, 0);
+ hb_face_destroy (face);
+
+ face = hb_face_builder_create ();
+ HB_FACE_ADD_TABLE (face, "maxp", maxp_data);
+ g_assert_cmpuint (hb_face_get_glyph_count (face), ==, 5);
+ hb_face_destroy (face);
+
+#ifndef HB_NO_BORING_EXPANSION
+ face = hb_face_builder_create ();
+ HB_FACE_ADD_TABLE (face, "maxp", maxp_data);
+ HB_FACE_ADD_TABLE (face, "loca", loca_data);
+ g_assert_cmpuint (hb_face_get_glyph_count (face), ==, 8);
+ hb_face_destroy (face);
+
+ face = hb_face_builder_create ();
+ HB_FACE_ADD_TABLE (face, "loca", loca_data);
+ g_assert_cmpuint (hb_face_get_glyph_count (face), ==, 8);
+ hb_face_destroy (face);
+#endif
+}
+
+
+int
+main (int argc, char **argv)
+{
+ hb_test_init (&argc, &argv);
+
+ hb_test_add (test_maxp_and_loca);
+
+ return hb_test_run();
+}