src/hb-buffer-private.hh | 10 +++++ src/hb-buffer.cc | 2 + src/hb-ot-layout-common-private.hh | 5 ++ src/hb-ot-layout-private.hh | 8 ++-- src/hb-ot-map-private.hh | 16 -------- src/hb-ot-shape-fallback-private.hh | 4 ++ src/hb-ot-shape-fallback.cc | 67 ++++++++++++++++++++++++++++++++++++ src/hb-ot-shape-normalize.cc | 1 src/hb-ot-shape.cc | 5 ++ src/hb-private.hh | 14 +++++++ src/hb-unicode-private.hh | 56 ++++++++++++++++-------------- test/shaping/tests/spaces.tests | 24 ++++++------ 12 files changed, 155 insertions(+), 57 deletions(-)
New commits: commit 49ef630936325b2e56a870fcef9aa8473a8f8526 Author: Behdad Esfahbod <[email protected]> Date: Wed Nov 4 17:27:07 2015 -0800 Adjust the width of various spaces if font does not cover them See discussion here: https://github.com/behdad/harfbuzz/commit/81ef4f407d9c7bd98cf62cef951dc538b13442eb There's no way to disable this fallback, but I don't think it would be needed. Let's hope for the best! Fixes https://github.com/behdad/harfbuzz/issues/153 diff --git a/src/hb-buffer-private.hh b/src/hb-buffer-private.hh index 8e33fc8..c5a116d 100644 --- a/src/hb-buffer-private.hh +++ b/src/hb-buffer-private.hh @@ -41,6 +41,12 @@ ASSERT_STATIC (sizeof (hb_glyph_info_t) == sizeof (hb_glyph_position_t)); template <> class hb_mark_as_flags_t<hb_buffer_flags_t> {}; template <> class hb_mark_as_flags_t<hb_buffer_serialize_flags_t> {}; +enum hb_buffer_scratch_flags_t { + HB_BUFFER_SCRATCH_FLAG_DEFAULT = 0x00000000u, + HB_BUFFER_SCRATCH_FLAG_HAS_SPACE_FALLBACK = 0x00000001u, +}; +template <> class hb_mark_as_flags_t<hb_buffer_scratch_flags_t> {}; + /* * hb_buffer_t @@ -55,6 +61,7 @@ struct hb_buffer_t { hb_buffer_flags_t flags; /* BOT / EOT / etc. */ hb_buffer_cluster_level_t cluster_level; hb_codepoint_t replacement; /* U+FFFD or something else. */ + hb_buffer_scratch_flags_t scratch_flags; /* Have space-flallback, etc. */ /* Buffer contents */ hb_buffer_content_type_t content_type; diff --git a/src/hb-buffer.cc b/src/hb-buffer.cc index 50710dd..f690769 100644 --- a/src/hb-buffer.cc +++ b/src/hb-buffer.cc @@ -198,6 +198,7 @@ hb_buffer_t::clear (void) hb_segment_properties_t default_props = HB_SEGMENT_PROPERTIES_DEFAULT; props = default_props; + scratch_flags = HB_BUFFER_SCRATCH_FLAG_DEFAULT; content_type = HB_BUFFER_CONTENT_TYPE_INVALID; in_error = false; @@ -738,6 +739,7 @@ hb_buffer_get_empty (void) HB_BUFFER_FLAG_DEFAULT, HB_BUFFER_CLUSTER_LEVEL_DEFAULT, HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT, + HB_BUFFER_SCRATCH_FLAG_DEFAULT, HB_BUFFER_CONTENT_TYPE_INVALID, HB_SEGMENT_PROPERTIES_DEFAULT, diff --git a/src/hb-ot-shape-fallback-private.hh b/src/hb-ot-shape-fallback-private.hh index ec65351..e134224 100644 --- a/src/hb-ot-shape-fallback-private.hh +++ b/src/hb-ot-shape-fallback-private.hh @@ -45,5 +45,9 @@ HB_INTERNAL void _hb_ot_shape_fallback_kern (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer); +HB_INTERNAL void _hb_ot_shape_fallback_spaces (const hb_ot_shape_plan_t *plan, + hb_font_t *font, + hb_buffer_t *buffer); + #endif /* HB_OT_SHAPE_FALLBACK_PRIVATE_HH */ diff --git a/src/hb-ot-shape-fallback.cc b/src/hb-ot-shape-fallback.cc index 3cb3456..c9cf737 100644 --- a/src/hb-ot-shape-fallback.cc +++ b/src/hb-ot-shape-fallback.cc @@ -484,3 +484,70 @@ _hb_ot_shape_fallback_kern (const hb_ot_shape_plan_t *plan, idx = skippy_iter.idx; } } + + +/* Adjusts width of various spaces. */ +void +_hb_ot_shape_fallback_spaces (const hb_ot_shape_plan_t *plan, + hb_font_t *font, + hb_buffer_t *buffer) +{ + if (!HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction)) + return; + + hb_glyph_info_t *info = buffer->info; + hb_glyph_position_t *pos = buffer->pos; + unsigned int count = buffer->len; + for (unsigned int i = 0; i < count; i++) + if (_hb_glyph_info_is_unicode_space (&info[i]) && !_hb_glyph_info_ligated (&info[i])) + { + hb_unicode_funcs_t::space_t space_type = _hb_glyph_info_get_unicode_space_fallback_type (&info[i]); + hb_codepoint_t glyph; + typedef hb_unicode_funcs_t t; + switch (space_type) + { + case t::NOT_SPACE: /* Shouldn't happen. */ + case t::SPACE: + break; + + case t::SPACE_EM: + case t::SPACE_EM_2: + case t::SPACE_EM_3: + case t::SPACE_EM_4: + case t::SPACE_EM_5: + case t::SPACE_EM_6: + case t::SPACE_EM_16: + pos[i].x_advance = (font->x_scale + ((int) space_type)/2) / (int) space_type; + break; + + case t::SPACE_4_EM_18: + pos[i].x_advance = font->x_scale * 4 / 18; + break; + + case t::SPACE_FIGURE: + for (char u = '0'; u <= '9'; u++) + if (font->get_glyph (u, 0, &glyph)) + { + pos[i].x_advance = font->get_glyph_h_advance (glyph); + break; + } + break; + + case t::SPACE_PUNCTUATION: + if (font->get_glyph ('.', 0, &glyph)) + pos[i].x_advance = font->get_glyph_h_advance (glyph); + else if (font->get_glyph (',', 0, &glyph)) + pos[i].x_advance = font->get_glyph_h_advance (glyph); + break; + + case t::SPACE_NARROW: + /* Half-space? + * Unicode doc http://www.unicode.org/charts/PDF/U2000.pdf says ~1/4 or 1/5 of EM. + * However, in my testing, many fonts have their regular space being about that + * size. To me, a percentage of the space width makes more sense. Half is as + * good as any. */ + pos[i].x_advance /= 2; + break; + } + } +} diff --git a/src/hb-ot-shape-normalize.cc b/src/hb-ot-shape-normalize.cc index c86c634..31376b3 100644 --- a/src/hb-ot-shape-normalize.cc +++ b/src/hb-ot-shape-normalize.cc @@ -180,6 +180,7 @@ decompose_current_character (const hb_ot_shape_normalize_context_t *c, bool shor { _hb_glyph_info_set_unicode_space_fallback_type (&buffer->cur(), space_type); next_char (buffer, space_glyph); + buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_SPACE_FALLBACK; } else next_char (buffer, glyph); /* glyph is initialized in earlier branches. */ diff --git a/src/hb-ot-shape.cc b/src/hb-ot-shape.cc index 205be0a..0b14172 100644 --- a/src/hb-ot-shape.cc +++ b/src/hb-ot-shape.cc @@ -659,6 +659,8 @@ hb_ot_position_default (hb_ot_shape_context_t *c) &pos[i].y_offset); } + if (c->buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_SPACE_FALLBACK) + _hb_ot_shape_fallback_spaces (c->plan, c->font, c->buffer); } static inline bool @@ -778,6 +780,7 @@ static void hb_ot_shape_internal (hb_ot_shape_context_t *c) { c->buffer->deallocate_var_all (); + c->buffer->scratch_flags = HB_BUFFER_SCRATCH_FLAG_DEFAULT; /* Save the original direction, we use it later. */ c->target_direction = c->buffer->props.direction; diff --git a/src/hb-unicode-private.hh b/src/hb-unicode-private.hh index 43bbed6..1290453 100644 --- a/src/hb-unicode-private.hh +++ b/src/hb-unicode-private.hh @@ -199,21 +199,24 @@ HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS_SIMPLE } } + /* Space estimates based on: + * http://www.unicode.org/charts/PDF/U2000.pdf + * https://www.microsoft.com/typography/developers/fdsspec/spaces.aspx + */ enum space_t { NOT_SPACE = 0, - SPACE_NBSP, - SPACE_EN, - SPACE_EM, - SPACE_EM_3, - SPACE_EM_4, - SPACE_EM_6, + SPACE_EM = 1, + SPACE_EM_2 = 2, + SPACE_EM_3 = 3, + SPACE_EM_4 = 4, + SPACE_EM_5 = 5, + SPACE_EM_6 = 6, + SPACE_EM_16 = 16, + SPACE_4_EM_18, /* 4/18th of an EM! */ + SPACE, SPACE_FIGURE, SPACE_PUNCTUATION, - SPACE_THIN, - SPACE_HAIR, SPACE_NARROW, - SPACE_MEDIUM, - SPACE_IDEOGRAPHIC, }; static inline space_t space_fallback_type (hb_codepoint_t u) @@ -221,22 +224,23 @@ HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS_SIMPLE switch (u) { /* All GC=Zs chars that can use a fallback. */ - default: return NOT_SPACE; /* Shouldn't happen. */ - case 0x00A0u: return SPACE_NBSP; - case 0x2000u: return SPACE_EN; - case 0x2001u: return SPACE_EM; - case 0x2002u: return SPACE_EN; - case 0x2003u: return SPACE_EM; - case 0x2004u: return SPACE_EM_3; - case 0x2005u: return SPACE_EM_4; - case 0x2006u: return SPACE_EM_6; - case 0x2007u: return SPACE_FIGURE; - case 0x2008u: return SPACE_PUNCTUATION; - case 0x2009u: return SPACE_THIN; - case 0x200Au: return SPACE_HAIR; - case 0x202Fu: return SPACE_NARROW; - case 0x205Fu: return SPACE_MEDIUM; - case 0x3000u: return SPACE_IDEOGRAPHIC; + default: return NOT_SPACE; /* Shouldn't happen. */ + case 0x0020u: return SPACE; /* U+0020 SPACE */ + case 0x00A0u: return SPACE; /* U+00A0 NO-BREAK SPACE */ + case 0x2000u: return SPACE_EM_2; /* U+2000 EN QUAD */ + case 0x2001u: return SPACE_EM; /* U+2001 EM QUAD */ + case 0x2002u: return SPACE_EM_2; /* U+2002 EN SPACE */ + case 0x2003u: return SPACE_EM; /* U+2003 EM SPACE */ + case 0x2004u: return SPACE_EM_3; /* U+2004 THREE-PER-EM SPACE */ + case 0x2005u: return SPACE_EM_4; /* U+2005 FOUR-PER-EM SPACE */ + case 0x2006u: return SPACE_EM_6; /* U+2006 SIX-PER-EM SPACE */ + case 0x2007u: return SPACE_FIGURE; /* U+2007 FIGURE SPACE */ + case 0x2008u: return SPACE_PUNCTUATION; /* U+2008 PUNCTUATION SPACE */ + case 0x2009u: return SPACE_EM_5; /* U+2009 THIN SPACE */ + case 0x200Au: return SPACE_EM_16; /* U+200A HAIR SPACE */ + case 0x202Fu: return SPACE_NARROW; /* U+202F NARROW NO-BREAK SPACE */ + case 0x205Fu: return SPACE_4_EM_18; /* U+205F MEDIUM MATHEMATICAL SPACE */ + case 0x3000u: return SPACE_EM; /* U+3000 IDEOGRAPHIC SPACE */ } } diff --git a/test/shaping/tests/spaces.tests b/test/shaping/tests/spaces.tests index d9e5d09..cb386de 100644 --- a/test/shaping/tests/spaces.tests +++ b/test/shaping/tests/spaces.tests @@ -1,17 +1,17 @@ fonts/sha1sum/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf:--font-funcs=ot:U+0020:[gid1=0+560] fonts/sha1sum/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf:--font-funcs=ot:U+00A0:[gid1=0+560] fonts/sha1sum/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf:--font-funcs=ot:U+1680:[gid0=0+692] -fonts/sha1sum/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf:--font-funcs=ot:U+2000:[gid1=0+560] -fonts/sha1sum/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf:--font-funcs=ot:U+2001:[gid1=0+560] -fonts/sha1sum/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf:--font-funcs=ot:U+2002:[gid1=0+560] -fonts/sha1sum/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf:--font-funcs=ot:U+2003:[gid1=0+560] -fonts/sha1sum/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf:--font-funcs=ot:U+2004:[gid1=0+560] -fonts/sha1sum/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf:--font-funcs=ot:U+2005:[gid1=0+560] -fonts/sha1sum/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf:--font-funcs=ot:U+2006:[gid1=0+560] +fonts/sha1sum/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf:--font-funcs=ot:U+2000:[gid1=0+1024] +fonts/sha1sum/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf:--font-funcs=ot:U+2001:[gid1=0+2048] +fonts/sha1sum/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf:--font-funcs=ot:U+2002:[gid1=0+1024] +fonts/sha1sum/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf:--font-funcs=ot:U+2003:[gid1=0+2048] +fonts/sha1sum/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf:--font-funcs=ot:U+2004:[gid1=0+683] +fonts/sha1sum/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf:--font-funcs=ot:U+2005:[gid1=0+512] +fonts/sha1sum/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf:--font-funcs=ot:U+2006:[gid1=0+341] fonts/sha1sum/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf:--font-funcs=ot:U+2007:[gid1=0+560] fonts/sha1sum/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf:--font-funcs=ot:U+2008:[gid1=0+560] -fonts/sha1sum/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf:--font-funcs=ot:U+2009:[gid1=0+560] -fonts/sha1sum/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf:--font-funcs=ot:U+200A:[gid1=0+560] -fonts/sha1sum/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf:--font-funcs=ot:U+202F:[gid1=0+560] -fonts/sha1sum/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf:--font-funcs=ot:U+205F:[gid1=0+560] -fonts/sha1sum/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf:--font-funcs=ot:U+3000:[gid1=0+560] +fonts/sha1sum/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf:--font-funcs=ot:U+2009:[gid1=0+410] +fonts/sha1sum/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf:--font-funcs=ot:U+200A:[gid1=0+128] +fonts/sha1sum/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf:--font-funcs=ot:U+202F:[gid1=0+280] +fonts/sha1sum/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf:--font-funcs=ot:U+205F:[gid1=0+455] +fonts/sha1sum/1c2c3fc37b2d4c3cb2ef726c6cdaaabd4b7f3eb9.ttf:--font-funcs=ot:U+3000:[gid1=0+2048] commit aa7044de0ceacd71cab19212d266c3a66c03b41e Author: Behdad Esfahbod <[email protected]> Date: Wed Nov 4 16:25:57 2015 -0800 Generalize flags types diff --git a/src/hb-buffer-private.hh b/src/hb-buffer-private.hh index 521214d..8e33fc8 100644 --- a/src/hb-buffer-private.hh +++ b/src/hb-buffer-private.hh @@ -38,6 +38,9 @@ ASSERT_STATIC (sizeof (hb_glyph_info_t) == 20); ASSERT_STATIC (sizeof (hb_glyph_info_t) == sizeof (hb_glyph_position_t)); +template <> class hb_mark_as_flags_t<hb_buffer_flags_t> {}; +template <> class hb_mark_as_flags_t<hb_buffer_serialize_flags_t> {}; + /* * hb_buffer_t diff --git a/src/hb-ot-layout-common-private.hh b/src/hb-ot-layout-common-private.hh index 84a1635..04958a8 100644 --- a/src/hb-ot-layout-common-private.hh +++ b/src/hb-ot-layout-common-private.hh @@ -579,6 +579,11 @@ struct LookupFlag : USHORT DEFINE_SIZE_STATIC (2); }; +} /* namespace OT */ +/* This has to be outside the namespace. */ +template <> class hb_mark_as_flags_t<OT::LookupFlag::Flags> {}; +namespace OT { + struct Lookup { inline unsigned int get_subtable_count (void) const { return subTable.len; } diff --git a/src/hb-ot-layout-private.hh b/src/hb-ot-layout-private.hh index 1759520..242d5cc 100644 --- a/src/hb-ot-layout-private.hh +++ b/src/hb-ot-layout-private.hh @@ -49,7 +49,7 @@ hb_ot_layout_table_find_feature (hb_face_t *face, * GDEF */ -typedef enum +enum hb_ot_layout_glyph_props_flags_t { /* The following three match LookupFlags::Ignore* numbers. */ HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH = 0x02u, @@ -64,7 +64,8 @@ typedef enum HB_OT_LAYOUT_GLYPH_PROPS_PRESERVE = HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED | HB_OT_LAYOUT_GLYPH_PROPS_LIGATED | HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED -} hb_ot_layout_glyph_class_mask_t; +}; +template <> class hb_mark_as_flags_t<hb_ot_layout_glyph_props_flags_t> {}; /* @@ -230,12 +231,13 @@ _next_syllable (hb_buffer_t *buffer, unsigned int start) * freeing two more bits. */ -enum { +enum hb_unicode_props_flags_t { UPROPS_MASK_ZWJ = 0x20u, UPROPS_MASK_ZWNJ = 0x40u, UPROPS_MASK_IGNORABLE = 0x80u, UPROPS_MASK_GEN_CAT = 0x1Fu }; +template <> class hb_mark_as_flags_t<hb_unicode_props_flags_t> {}; static inline void _hb_glyph_info_set_unicode_props (hb_glyph_info_t *info, hb_unicode_funcs_t *unicode) diff --git a/src/hb-ot-map-private.hh b/src/hb-ot-map-private.hh index f9538af..1e3ff67 100644 --- a/src/hb-ot-map-private.hh +++ b/src/hb-ot-map-private.hh @@ -159,23 +159,9 @@ enum hb_ot_map_feature_flags_t { F_MANUAL_ZWJ = 0x0004u, /* Don't skip over ZWJ when matching. */ F_GLOBAL_SEARCH = 0x0008u /* If feature not found in LangSys, look for it in global feature list and pick one. */ }; +template <> class hb_mark_as_flags_t<hb_ot_map_feature_flags_t> {}; /* Macro version for where const is desired. */ #define F_COMBINE(l,r) (hb_ot_map_feature_flags_t ((unsigned int) (l) | (unsigned int) (r))) -static inline hb_ot_map_feature_flags_t -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); } -static inline hb_ot_map_feature_flags_t -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); } -static inline hb_ot_map_feature_flags_t -operator ~ (hb_ot_map_feature_flags_t r) -{ return hb_ot_map_feature_flags_t (~(unsigned int) r); } -static inline hb_ot_map_feature_flags_t& -operator |= (hb_ot_map_feature_flags_t &l, hb_ot_map_feature_flags_t r) -{ l = l | r; return l; } -static inline hb_ot_map_feature_flags_t& -operator &= (hb_ot_map_feature_flags_t& l, hb_ot_map_feature_flags_t r) -{ l = l & r; return l; } struct hb_ot_map_builder_t diff --git a/src/hb-ot-shape.cc b/src/hb-ot-shape.cc index 40332d6..205be0a 100644 --- a/src/hb-ot-shape.cc +++ b/src/hb-ot-shape.cc @@ -525,7 +525,7 @@ hb_synthesize_glyph_classes (hb_ot_shape_context_t *c) hb_glyph_info_t *info = c->buffer->info; for (unsigned int i = 0; i < count; i++) { - hb_ot_layout_glyph_class_mask_t klass; + hb_ot_layout_glyph_props_flags_t klass; /* Never mark default-ignorables as marks. * They won't get in the way of lookups anyway, diff --git a/src/hb-private.hh b/src/hb-private.hh index 53e0510..c65a8bf 100644 --- a/src/hb-private.hh +++ b/src/hb-private.hh @@ -891,6 +891,20 @@ hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2, T lo3, T hi3) } +/* Enable bitwise ops on enums marked as flags_t */ +template <class T> class hb_mark_as_flags_t; +template <class T> static inline T operator | (T l, T r) +{ hb_mark_as_flags_t<T> unused HB_UNUSED; return T ((unsigned int) l | (unsigned int) r); } +template <class T> static inline T operator & (T l, T r) +{ hb_mark_as_flags_t<T> unused HB_UNUSED; return T ((unsigned int) l & (unsigned int) r); } +template <class T> static inline T operator ~ (T r) +{ hb_mark_as_flags_t<T> unused HB_UNUSED; return T (~(unsigned int) r); } +template <class T> static inline T& operator |= (T &l, T r) +{ hb_mark_as_flags_t<T> unused HB_UNUSED; l = l | r; return l; } +template <class T> static inline T& operator &= (T& l, T r) +{ hb_mark_as_flags_t<T> unused HB_UNUSED; l = l & r; return l; } + + /* Useful for set-operations on small enums. * For example, for testing "x â {x1, x2, x3}" use: * (FLAG_SAFE(x) & (FLAG(x1) | FLAG(x2) | FLAG(x3)))
_______________________________________________ HarfBuzz mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/harfbuzz
