Adjust the width of various spaces if font does not cover them

See discussion here:
81ef4f407d

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
This commit is contained in:
Behdad Esfahbod 2015-11-04 17:27:07 -08:00
parent aa7044de0c
commit 49ef630936
8 changed files with 126 additions and 38 deletions

View File

@ -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;

View File

@ -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,

View File

@ -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 */

View File

@ -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;
}
}
}

View File

@ -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. */

View File

@ -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;

View File

@ -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)
@ -222,21 +225,22 @@ HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS_SIMPLE
{
/* 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;
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 */
}
}

View File

@ -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]