Implement fallback vertical shaping from Firefox

Fixes https://github.com/harfbuzz/harfbuzz/issues/355
This commit is contained in:
Behdad Esfahbod 2019-12-05 15:28:42 +00:00
parent b6d0f1529d
commit 2dc20e632e
3 changed files with 80 additions and 14 deletions

View File

@ -102,6 +102,8 @@ hb_ot_shape_planner_t::compile (hb_ot_shape_plan_t &plan,
#endif
plan.rtlm_mask = plan.map.get_1_mask (HB_TAG ('r','t','l','m'));
plan.has_vert = !!plan.map.get_1_mask (HB_TAG ('v','e','r','t'));
hb_tag_t kern_tag = HB_DIRECTION_IS_HORIZONTAL (props.direction) ?
HB_TAG ('k','e','r','n') : HB_TAG ('v','k','r','n');
#ifndef HB_NO_OT_KERN
@ -573,24 +575,86 @@ hb_ensure_native_direction (hb_buffer_t *buffer)
* Substitute
*/
static inline void
hb_ot_mirror_chars (const hb_ot_shape_context_t *c)
static hb_codepoint_t
hb_vert_char_for (hb_codepoint_t u)
{
if (HB_DIRECTION_IS_FORWARD (c->target_direction))
return;
switch (u >> 8)
{
case 0x20: switch (u) {
case 0x2013u: return 0xfe32u; // EN DASH
case 0x2014u: return 0xfe31u; // EM DASH
case 0x2025u: return 0xfe30u; // TWO DOT LEADER
case 0x2026u: return 0xfe19u; // HORIZONTAL ELLIPSIS
} break;
case 0x30: switch (u) {
case 0x3001u: return 0xfe11u; // IDEOGRAPHIC COMMA
case 0x3002u: return 0xfe12u; // IDEOGRAPHIC FULL STOP
case 0x3008u: return 0xfe3fu; // LEFT ANGLE BRACKET
case 0x3009u: return 0xfe40u; // RIGHT ANGLE BRACKET
case 0x300au: return 0xfe3du; // LEFT DOUBLE ANGLE BRACKET
case 0x300bu: return 0xfe3eu; // RIGHT DOUBLE ANGLE BRACKET
case 0x300cu: return 0xfe41u; // LEFT CORNER BRACKET
case 0x300du: return 0xfe42u; // RIGHT CORNER BRACKET
case 0x300eu: return 0xfe43u; // LEFT WHITE CORNER BRACKET
case 0x300fu: return 0xfe44u; // RIGHT WHITE CORNER BRACKET
case 0x3010u: return 0xfe3bu; // LEFT BLACK LENTICULAR BRACKET
case 0x3011u: return 0xfe3cu; // RIGHT BLACK LENTICULAR BRACKET
case 0x3014u: return 0xfe39u; // LEFT TORTOISE SHELL BRACKET
case 0x3015u: return 0xfe3au; // RIGHT TORTOISE SHELL BRACKET
case 0x3016u: return 0xfe17u; // LEFT WHITE LENTICULAR BRACKET
case 0x3017u: return 0xfe18u; // RIGHT WHITE LENTICULAR BRACKET
} break;
case 0xfe: switch (u) {
case 0xfe4fu: return 0xfe34u; // WAVY LOW LINE
} break;
case 0xff: switch (u) {
case 0xff01u: return 0xfe15u; // FULLWIDTH EXCLAMATION MARK
case 0xff08u: return 0xfe35u; // FULLWIDTH LEFT PARENTHESIS
case 0xff09u: return 0xfe36u; // FULLWIDTH RIGHT PARENTHESIS
case 0xff0cu: return 0xfe10u; // FULLWIDTH COMMA
case 0xff1au: return 0xfe13u; // FULLWIDTH COLON
case 0xff1bu: return 0xfe14u; // FULLWIDTH SEMICOLON
case 0xff1fu: return 0xfe16u; // FULLWIDTH QUESTION MARK
case 0xff3bu: return 0xfe47u; // FULLWIDTH LEFT SQUARE BRACKET
case 0xff3du: return 0xfe48u; // FULLWIDTH RIGHT SQUARE BRACKET
case 0xff3fu: return 0xfe33u; // FULLWIDTH LOW LINE
case 0xff5bu: return 0xfe37u; // FULLWIDTH LEFT CURLY BRACKET
case 0xff5du: return 0xfe38u; // FULLWIDTH RIGHT CURLY BRACKET
} break;
}
return u;
}
static inline void
hb_ot_rotate_chars (const hb_ot_shape_context_t *c)
{
hb_buffer_t *buffer = c->buffer;
hb_unicode_funcs_t *unicode = buffer->unicode;
hb_mask_t rtlm_mask = c->plan->rtlm_mask;
unsigned int count = buffer->len;
hb_glyph_info_t *info = buffer->info;
for (unsigned int i = 0; i < count; i++) {
hb_codepoint_t codepoint = unicode->mirroring (info[i].codepoint);
if (likely (codepoint == info[i].codepoint || !c->font->has_glyph (codepoint)))
info[i].mask |= rtlm_mask;
else
info[i].codepoint = codepoint;
if (HB_DIRECTION_IS_BACKWARD (c->target_direction))
{
hb_unicode_funcs_t *unicode = buffer->unicode;
hb_mask_t rtlm_mask = c->plan->rtlm_mask;
for (unsigned int i = 0; i < count; i++) {
hb_codepoint_t codepoint = unicode->mirroring (info[i].codepoint);
if (unlikely (codepoint != info[i].codepoint && c->font->has_glyph (codepoint)))
info[i].codepoint = codepoint;
else
info[i].mask |= rtlm_mask;
}
}
if (HB_DIRECTION_IS_VERTICAL (c->target_direction) && !c->plan->has_vert)
{
for (unsigned int i = 0; i < count; i++) {
hb_codepoint_t codepoint = hb_vert_char_for (info[i].codepoint);
if (c->font->has_glyph (codepoint))
if (unlikely (codepoint != info[i].codepoint && c->font->has_glyph (codepoint)))
info[i].codepoint = codepoint;
}
}
}
@ -767,7 +831,7 @@ hb_ot_substitute_default (const hb_ot_shape_context_t *c)
{
hb_buffer_t *buffer = c->buffer;
hb_ot_mirror_chars (c);
hb_ot_rotate_chars (c);
HB_BUFFER_ALLOCATE_VAR (buffer, glyph_index);

View File

@ -99,6 +99,7 @@ struct hb_ot_shape_plan_t
#else
static constexpr bool has_frac = false;
#endif
bool has_vert : 1;
bool has_gpos_mark : 1;
bool zero_marks : 1;
bool fallback_glyph_classes : 1;

View File

@ -43,6 +43,7 @@ TESTS = \
tests/none-directional.tests \
tests/positioning-features.tests \
tests/rand.tests \
tests/rotation.tests \
tests/spaces.tests \
tests/simple.tests \
tests/sinhala.tests \