diff options
author | Tor Andersson <tor.andersson@artifex.com> | 2016-04-04 18:16:02 +0200 |
---|---|---|
committer | Tor Andersson <tor.andersson@artifex.com> | 2016-04-04 18:46:08 +0200 |
commit | 1beb60e78c5bb1f0abe6d4f30ac1777f611c0c3d (patch) | |
tree | ee5374f9fa18e1f499ae9b81877416d63f482290 | |
parent | b3dce80c9a50d26790d592313afe96e85bdb842e (diff) | |
download | mupdf-1beb60e78c5bb1f0abe6d4f30ac1777f611c0c3d.tar.xz |
epub: Add harfbuzz bypass for fonts without opentype tables.
In certain simple circumstances, we can bypass harfbuzz shaping and gain
a lot of performance.
-rw-r--r-- | include/mupdf/fitz/font.h | 6 | ||||
-rw-r--r-- | source/fitz/font.c | 26 | ||||
-rw-r--r-- | source/html/html-layout.c | 102 |
3 files changed, 104 insertions, 30 deletions
diff --git a/include/mupdf/fitz/font.h b/include/mupdf/fitz/font.h index e4feaab7..2d3a8100 100644 --- a/include/mupdf/fitz/font.h +++ b/include/mupdf/fitz/font.h @@ -36,12 +36,15 @@ struct fz_font_s char is_italic; void *ft_face; /* has an FT_Face if used */ + void *hb_font; /* hb_font for shaping */ int ft_substitute; /* ... substitute metrics */ int ft_stretch; /* ... and stretch to match PDF metrics */ + int fake_bold; /* ... synthesize bold */ int fake_italic; /* ... synthesize italic */ int force_hinting; /* ... force hinting for DynaLab fonts */ + int has_opentype; /* ... has opentype shaping tables */ fz_matrix t3matrix; void *t3resources; @@ -71,9 +74,6 @@ struct fz_font_s /* cached encoding lookup */ uint16_t *encoding_cache[256]; - - /* Shaping information */ - void *shaper; }; /* common CJK font collections */ diff --git a/source/fitz/font.c b/source/fitz/font.c index b0adae71..c274995b 100644 --- a/source/fitz/font.c +++ b/source/fitz/font.c @@ -8,6 +8,7 @@ #include FT_ADVANCES_H #include FT_STROKER_H #include FT_TRUETYPE_TABLES_H +#include FT_TRUETYPE_TAGS_H #define MAX_BBOX_TABLE_SIZE 4096 #define MAX_ADVANCE_CACHE 4096 @@ -40,6 +41,7 @@ fz_new_font(fz_context *ctx, const char *name, int use_glyph_bbox, int glyph_cou font->fake_bold = 0; font->fake_italic = 0; font->force_hinting = 0; + font->has_opentype = 0; font->t3matrix = fz_identity; font->t3resources = NULL; @@ -155,7 +157,7 @@ fz_drop_font(fz_context *ctx, fz_font *font) fz_free(ctx, font->width_table); fz_free(ctx, font->advance_cache); hb_lock(ctx); - hb_font_destroy(font->shaper); + hb_font_destroy(font->hb_font); hb_unlock(ctx); fz_free(ctx, font); } @@ -427,6 +429,7 @@ fz_new_font_from_buffer(fz_context *ctx, const char *name, fz_buffer *buffer, in TT_OS2 *os2; fz_font *font; int fterr; + FT_ULong tag, size, i, n; fz_keep_freetype(ctx); @@ -455,9 +458,20 @@ fz_new_font_from_buffer(fz_context *ctx, const char *name, fz_buffer *buffer, in font->is_bold = !!(face->style_flags & FT_STYLE_FLAG_BOLD); font->is_italic = !!(face->style_flags & FT_STYLE_FLAG_ITALIC); - os2 = FT_Get_Sfnt_Table(face, FT_SFNT_OS2); - if (os2) - font->is_serif = !(os2->sFamilyClass & 2048); /* Class 8 is sans-serif */ + if (FT_IS_SFNT(face)) + { + os2 = FT_Get_Sfnt_Table(face, FT_SFNT_OS2); + if (os2) + font->is_serif = !(os2->sFamilyClass & 2048); /* Class 8 is sans-serif */ + + FT_Sfnt_Table_Info(face, 0, NULL, &n); + for (i = 0; i < n; ++i) + { + FT_Sfnt_Table_Info(face, i, &tag, &size); + if (tag == TTAG_GDEF || tag == TTAG_GPOS || tag == TTAG_GSUB) + font->has_opentype = 1; + } + } font->buffer = fz_keep_buffer(ctx, buffer); @@ -1506,9 +1520,5 @@ fz_encode_character_with_fallback(fz_context *ctx, fz_font *user_font, int unico return *out_font = font, gid; } - /* bullet */ - if (unicode != 0x25CF) - return fz_encode_character_with_fallback(ctx, user_font, 0x25CF, UCDN_SCRIPT_LATIN, out_font); - return *out_font = user_font, 0; } diff --git a/source/html/html-layout.c b/source/html/html-layout.c index 0d615928..51a6c5ce 100644 --- a/source/html/html-layout.c +++ b/source/html/html-layout.c @@ -655,6 +655,51 @@ typedef struct string_walker int scale; } string_walker; +static int quick_ligature_mov(fz_context *ctx, string_walker *walker, int i, int n, int unicode) +{ + int k; + for (k = i + n + 1; k < walker->glyph_count; ++k) + { + walker->glyph_info[k-n] = walker->glyph_info[k]; + walker->glyph_pos[k-n] = walker->glyph_pos[k]; + } + walker->glyph_count -= n; + return unicode; +} + +static int quick_ligature(fz_context *ctx, string_walker *walker, int i) +{ + if (walker->glyph_info[i].codepoint == 'f' && i + 1 < walker->glyph_count && !walker->font->is_mono) + { + if (walker->glyph_info[i+1].codepoint == 'f') + { + if (i + 2 < walker->glyph_count && walker->glyph_info[i+2].codepoint == 'i') + { + if (fz_encode_character(ctx, walker->font, 0xFB03)) + return quick_ligature_mov(ctx, walker, i, 2, 0xFB03); + } + if (i + 2 < walker->glyph_count && walker->glyph_info[i+2].codepoint == 'l') + { + if (fz_encode_character(ctx, walker->font, 0xFB04)) + return quick_ligature_mov(ctx, walker, i, 2, 0xFB04); + } + if (fz_encode_character(ctx, walker->font, 0xFB00)) + return quick_ligature_mov(ctx, walker, i, 1, 0xFB00); + } + if (walker->glyph_info[i+1].codepoint == 'i') + { + if (fz_encode_character(ctx, walker->font, 0xFB01)) + return quick_ligature_mov(ctx, walker, i, 1, 0xFB01); + } + if (walker->glyph_info[i+1].codepoint == 'l') + { + if (fz_encode_character(ctx, walker->font, 0xFB02)) + return quick_ligature_mov(ctx, walker, i, 1, 0xFB02); + } + } + return walker->glyph_info[i].codepoint; +} + static void init_string_walker(fz_context *ctx, string_walker *walker, hb_buffer_t *hb_buf, int r2l, fz_font *font, int script, const char *text) { walker->ctx = ctx; @@ -674,6 +719,7 @@ static int walk_string(string_walker *walker) fz_context *ctx = walker->ctx; FT_Face face; int fterr; + int quickshape; walker->start = walker->end; walker->end = walker->s; @@ -699,40 +745,43 @@ static int walk_string(string_walker *walker) walker->end = walker->s; } + /* Disable harfbuzz shaping if script is common or LGC and there are no opentype tables. */ + quickshape = 0; + if (walker->script <= 3 && !walker->r2l && !walker->font->has_opentype) + quickshape = 1; + + hb_lock(ctx); fz_try(ctx) { - hb_lock(ctx); - - /* So, shape from start to end in font */ face = walker->font->ft_face; walker->scale = face->units_per_EM; fterr = FT_Set_Char_Size(face, walker->scale, walker->scale, 72, 72); if (fterr) fz_throw(ctx, FZ_ERROR_GENERIC, "freetype setting character size: %s", ft_error_string(fterr)); - if (walker->font->shaper == NULL) - { - Memento_startLeaking(); /* HarfBuzz leaks harmlessly */ - walker->font->shaper = (void *)hb_ft_font_create(face, NULL); - Memento_stopLeaking(); - } - hb_buffer_clear_contents(walker->hb_buf); hb_buffer_set_direction(walker->hb_buf, walker->r2l ? HB_DIRECTION_RTL : HB_DIRECTION_LTR); - - /* We don't know script or language, so leave them blank */ - /* hb_buffer_set_script(hb_buf, HB_SCRIPT_LATIN); */ + /* hb_buffer_set_script(hb_buf, hb_ucdn_script_translate(script)); */ /* hb_buffer_set_language(hb_buf, hb_language_from_string("en", strlen("en"))); */ /* hb_buffer_set_cluster_level(hb_buf, HB_BUFFER_CLUSTER_LEVEL_CHARACTERS); */ - /* First put the text content into a harfbuzz buffer labelled with the position within the word. */ hb_buffer_add_utf8(walker->hb_buf, walker->start, walker->end - walker->start, 0, -1); - Memento_startLeaking(); /* HarfBuzz leaks harmlessly */ - hb_buffer_guess_segment_properties(walker->hb_buf); - Memento_stopLeaking(); - /* Now shape that buffer */ - hb_shape(walker->font->shaper, walker->hb_buf, NULL, 0); + if (!quickshape) + { + if (walker->font->hb_font == NULL) + { + Memento_startLeaking(); /* HarfBuzz leaks harmlessly */ + walker->font->hb_font = hb_ft_font_create(face, NULL); + Memento_stopLeaking(); + } + + Memento_startLeaking(); /* HarfBuzz leaks harmlessly */ + hb_buffer_guess_segment_properties(walker->hb_buf); + Memento_stopLeaking(); + + hb_shape(walker->font->hb_font, walker->hb_buf, NULL, 0); + } walker->glyph_pos = hb_buffer_get_glyph_positions(walker->hb_buf, &walker->glyph_count); walker->glyph_info = hb_buffer_get_glyph_infos(walker->hb_buf, NULL); @@ -746,6 +795,21 @@ static int walk_string(string_walker *walker) fz_rethrow(ctx); } + if (quickshape) + { + int i; + for (i = 0; i < walker->glyph_count; ++i) + { + int unicode = quick_ligature(ctx, walker, i); + int glyph = fz_encode_character(ctx, walker->font, unicode); + walker->glyph_info[i].codepoint = glyph; + walker->glyph_pos[i].x_offset = 0; + walker->glyph_pos[i].y_offset = 0; + walker->glyph_pos[i].x_advance = fz_advance_glyph(ctx, walker->font, glyph, 0) * face->units_per_EM; + walker->glyph_pos[i].y_advance = 0; + } + } + return 1; } |