diff options
Diffstat (limited to 'modules')
-rw-r--r-- | modules/basic/Makefile.am | 2 | ||||
-rw-r--r-- | modules/basic/basic-fc.c | 333 |
2 files changed, 199 insertions, 136 deletions
diff --git a/modules/basic/Makefile.am b/modules/basic/Makefile.am index acd0c4d4..8035e3b3 100644 --- a/modules/basic/Makefile.am +++ b/modules/basic/Makefile.am @@ -19,7 +19,7 @@ libpango_basic_x_la_CFLAGS = -DPANGO_MODULE_PREFIX=_pango_basic_x if HAVE_FREETYPE -INCLUDES += $(FREETYPE_CFLAGS) +INCLUDES += $(FREETYPE_CFLAGS) $(HARFBUZZ_CFLAGS) if INCLUDE_BASIC_FC noinst_LTLIBRARIES += libpango-basic-fc.la else diff --git a/modules/basic/basic-fc.c b/modules/basic/basic-fc.c index 6e0d2ef2..787a2bc4 100644 --- a/modules/basic/basic-fc.c +++ b/modules/basic/basic-fc.c @@ -1,7 +1,7 @@ /* Pango * basic-fc.c: Basic shaper for FreeType-based backends * - * Copyright (C) 2000, 2007 Red Hat Software + * Copyright (C) 2000, 2007, 2009 Red Hat Software * Authors: * Owen Taylor <otaylor@redhat.com> * Behdad Esfahbod <behdad@behdad.org> @@ -25,11 +25,13 @@ #include "config.h" #include <string.h> +#define PANGO_ENABLE_BACKEND 1 /* XXX */ #include <glib/gprintf.h> #include "pango-engine.h" #include "pango-utils.h" #include "pangofc-font.h" -#include "pango-ot.h" +#include <hb-ft.h> +#include <hb-glib.h> /* No extra fields needed */ typedef PangoEngineShape BasicEngineFc; @@ -39,47 +41,6 @@ typedef PangoEngineShapeClass BasicEngineFcClass; #define RENDER_TYPE PANGO_RENDER_TYPE_FC static PangoEngineScriptInfo basic_scripts[] = { - /* Listed in OpenType "Standard scripts" standard */ - { PANGO_SCRIPT_LATIN, "*" }, - { PANGO_SCRIPT_CYRILLIC, "*" }, - { PANGO_SCRIPT_GREEK, "*" }, - { PANGO_SCRIPT_ARMENIAN, "*" }, - { PANGO_SCRIPT_GEORGIAN, "*" }, - { PANGO_SCRIPT_RUNIC, "*" }, - { PANGO_SCRIPT_OGHAM, "*" }, - - /* The following are simple and can be shaped easily too */ - - { PANGO_SCRIPT_BOPOMOFO, "*" }, - { PANGO_SCRIPT_CHEROKEE, "*" }, - { PANGO_SCRIPT_COPTIC, "*" }, - { PANGO_SCRIPT_DESERET, "*" }, - { PANGO_SCRIPT_ETHIOPIC, "*" }, - { PANGO_SCRIPT_GOTHIC, "*" }, - { PANGO_SCRIPT_HAN, "*" }, - { PANGO_SCRIPT_HIRAGANA, "*" }, - { PANGO_SCRIPT_KATAKANA, "*" }, - { PANGO_SCRIPT_OLD_ITALIC, "*" }, - { PANGO_SCRIPT_CANADIAN_ABORIGINAL, "*" }, - { PANGO_SCRIPT_YI, "*" }, - - /* Unicode-4.0 additions */ - { PANGO_SCRIPT_BRAILLE, "*" }, - { PANGO_SCRIPT_CYPRIOT, "*" }, - { PANGO_SCRIPT_LIMBU, "*" }, - { PANGO_SCRIPT_OSMANYA, "*" }, - { PANGO_SCRIPT_SHAVIAN, "*" }, - { PANGO_SCRIPT_LINEAR_B, "*" }, - { PANGO_SCRIPT_UGARITIC, "*" }, - - /* Unicode-4.1 additions */ - { PANGO_SCRIPT_GLAGOLITIC, "*" }, - - /* Unicode-5.0 additions */ - { PANGO_SCRIPT_CUNEIFORM, "*" }, - { PANGO_SCRIPT_PHOENICIAN, "*" }, - - /* In fact any script we don't know how to shape can go here */ { PANGO_SCRIPT_COMMON, "" } }; @@ -92,32 +53,152 @@ static PangoEngineInfo script_engines[] = { } }; -static const PangoOTFeatureMap gsub_features[] = + +/* cache a single hb_buffer_t */ +static hb_buffer_t *cached_buffer = NULL; +G_LOCK_DEFINE_STATIC (cached_buffer); + +static hb_buffer_t * +create_buffer (void) { - {"ccmp", PANGO_OT_ALL_GLYPHS}, - {"locl", PANGO_OT_ALL_GLYPHS}, - {"liga", PANGO_OT_ALL_GLYPHS}, - {"clig", PANGO_OT_ALL_GLYPHS} -}; + hb_buffer_t *buffer; + + buffer = hb_buffer_create (32); + hb_buffer_set_unicode_funcs (buffer, hb_glib_get_unicode_funcs ()); + + return buffer; +} -static const PangoOTFeatureMap gpos_features[] = +static hb_buffer_t * +acquire_buffer (gboolean *free_buffer) { - {"kern", PANGO_OT_ALL_GLYPHS}, - {"mark", PANGO_OT_ALL_GLYPHS}, - {"mkmk", PANGO_OT_ALL_GLYPHS} -}; + hb_buffer_t *buffer; -static const PangoOTFeatureMap vertical_gsub_features[] = + if (G_LIKELY (G_TRYLOCK (cached_buffer))) + { + if (G_UNLIKELY (!cached_buffer)) + cached_buffer = create_buffer (); + + buffer = cached_buffer; + *free_buffer = FALSE; + } + else + { + buffer = create_buffer (); + *free_buffer = TRUE; + } + + return buffer; +} + +static void +release_buffer (hb_buffer_t *buffer, gboolean free_buffer) { - {"ccmp", PANGO_OT_ALL_GLYPHS}, - {"locl", PANGO_OT_ALL_GLYPHS}, - {"vert", PANGO_OT_ALL_GLYPHS} -}; + if (G_LIKELY (!free_buffer) && hb_buffer_get_reference_count (buffer) == 1) + { + hb_buffer_clear (buffer); + G_UNLOCK (cached_buffer); + } + else + hb_buffer_destroy (buffer); +} -static const PangoOTFeatureMap vertical_gpos_features[] = + +static hb_codepoint_t +pango_fc_hb_font_get_glyph (hb_font_t *font, hb_face_t *face, const void *user_data, + hb_codepoint_t unicode, hb_codepoint_t variation_selector) { - {"vkrn", PANGO_OT_ALL_GLYPHS} -}; + PangoFcFont *fc_font = (PangoFcFont *) user_data; + PangoGlyph glyph; + + glyph = pango_fc_font_get_glyph (fc_font, unicode); + if (G_UNLIKELY (!glyph)) + glyph = PANGO_GET_UNKNOWN_GLYPH (unicode); + + return glyph; +} + +static hb_bool_t +pango_fc_hb_font_get_contour_point (hb_font_t *font, hb_face_t *face, const void *user_data, + unsigned int point_index, + hb_codepoint_t glyph, hb_position_t *x, hb_position_t *y) +{ + return FALSE; +#if 0 + FT_Face ft_face = (FT_Face) user_data; + int load_flags = FT_LOAD_DEFAULT; + + /* TODO: load_flags, embolden, etc */ + + if (HB_UNLIKELY (FT_Load_Glyph (ft_face, glyph, load_flags))) + return FALSE; + + if (HB_UNLIKELY (ft_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE)) + return FALSE; + + if (HB_UNLIKELY (point_index >= (unsigned int) ft_face->glyph->outline.n_points)) + return FALSE; + + *x = ft_face->glyph->outline.points[point_index].x; + *y = ft_face->glyph->outline.points[point_index].y; + + return TRUE; +#endif +} + +static void +pango_fc_hb_font_get_glyph_metrics (hb_font_t *font, hb_face_t *face, const void *user_data, + hb_codepoint_t glyph, hb_glyph_metrics_t *metrics) +{ + PangoFcFont *fc_font = (PangoFcFont *) user_data; + PangoRectangle ink, logical; + + pango_font_get_glyph_extents ((PangoFont *) fc_font, glyph, &ink, &logical); + + metrics->x_advance = logical.width; + metrics->y_advance = 0; + metrics->x_offset = ink.x; + metrics->y_offset = ink.y; + metrics->width = ink.width; + metrics->height = ink.height; +} + +static hb_position_t +pango_fc_hb_font_get_kerning (hb_font_t *font, hb_face_t *face, const void *user_data, + hb_codepoint_t first_glyph, hb_codepoint_t second_glyph) +{ + PangoFcFont *fc_font = (PangoFcFont *) user_data; +#if 0 + FT_Face ft_face = (FT_Face) user_data; + FT_Vector kerning; + + /* TODO: Kern type? */ + if (FT_Get_Kerning (ft_face, first_glyph, second_glyph, FT_KERNING_DEFAULT, &kerning)) + return 0; + + return kerning.x; +#endif + return 0; +} + +static hb_font_funcs_t * +pango_fc_get_hb_font_funcs (void) +{ + static hb_font_funcs_t *funcs; + + if (G_UNLIKELY (!funcs)) { + funcs = hb_font_funcs_create (); + hb_font_funcs_set_glyph_func (funcs, pango_fc_hb_font_get_glyph); + hb_font_funcs_set_contour_point_func (funcs, pango_fc_hb_font_get_contour_point); + hb_font_funcs_set_glyph_metrics_func (funcs, pango_fc_hb_font_get_glyph_metrics); + hb_font_funcs_set_kerning_func (funcs, pango_fc_hb_font_get_kerning); + } + + return funcs; +} + + + static void basic_engine_shape (PangoEngineShape *engine G_GNUC_UNUSED, @@ -128,14 +209,16 @@ basic_engine_shape (PangoEngineShape *engine G_GNUC_UNUSED, PangoGlyphString *glyphs) { PangoFcFont *fc_font; - FT_Face face; - PangoOTRulesetDescription desc; - const PangoOTRuleset *ruleset; - PangoOTBuffer *buffer; - glong n_chars; - const char *p; - int cluster = 0; - int i; + FT_Face ft_face; + hb_face_t *hb_face; + hb_font_t *hb_font; + hb_buffer_t *hb_buffer; + gboolean free_buffer; + gboolean is_hinted; + hb_glyph_info_t *hb_glyph; + hb_glyph_position_t *hb_position; + int last_cluster; + guint i, num_glyphs; g_return_if_fail (font != NULL); g_return_if_fail (text != NULL); @@ -143,77 +226,57 @@ basic_engine_shape (PangoEngineShape *engine G_GNUC_UNUSED, g_return_if_fail (analysis != NULL); fc_font = PANGO_FC_FONT (font); - face = pango_fc_font_lock_face (fc_font); - if (!face) + ft_face = pango_fc_font_lock_face (fc_font); + if (!ft_face) return; - - buffer = pango_ot_buffer_new (fc_font); - pango_ot_buffer_set_rtl (buffer, analysis->level % 2 != 0); - - n_chars = g_utf8_strlen (text, length); - pango_glyph_string_set_size (glyphs, n_chars); - - p = text; - for (i=0; i < n_chars; i++) + hb_face = hb_ft_face_create_cached (ft_face); + + /* TODO: Cache hb_font */ + hb_font = hb_font_create (); + hb_font_set_funcs (hb_font, + pango_fc_get_hb_font_funcs (), + NULL, + fc_font); + hb_font_set_scale (hb_font, + ft_face->size->metrics.x_scale, + ft_face->size->metrics.y_scale); + is_hinted = fc_font->is_hinted; + hb_font_set_ppem (hb_font, + is_hinted ? ft_face->size->metrics.x_ppem : 0, + is_hinted ? ft_face->size->metrics.y_ppem : 0); + + hb_buffer = acquire_buffer (&free_buffer); + /* setup buffer */ + hb_buffer_set_direction (hb_buffer, analysis->level % 2 != 0 ? HB_DIRECTION_RTL : HB_DIRECTION_LTR); + hb_buffer_set_script (hb_buffer, analysis->script); + hb_buffer_set_language (hb_buffer, hb_language_from_string (pango_language_to_string (analysis->language))); + hb_buffer_add_utf8 (hb_buffer, text, length, 0, length); + + hb_shape (hb_font, hb_face, hb_buffer, NULL, 0); + + /* buffer output */ + num_glyphs = hb_buffer_get_len (hb_buffer); + hb_glyph = hb_buffer_get_glyph_infos (hb_buffer); + hb_position = hb_buffer_get_glyph_positions (hb_buffer); + pango_glyph_string_set_size (glyphs, num_glyphs); + last_cluster = -1; + for (i = 0; i < num_glyphs; i++) { - gunichar wc; - PangoGlyph glyph; - - wc = g_utf8_get_char (p); - - if (g_unichar_type (wc) != G_UNICODE_NON_SPACING_MARK) - cluster = p - text; - - if (pango_is_zero_width (wc)) - glyph = PANGO_GLYPH_EMPTY; - else - { - gunichar c = wc; - - if (analysis->level % 2) - g_unichar_get_mirror_char (c, &c); - - glyph = pango_fc_font_get_glyph (fc_font, c); - } - - if (!glyph) - glyph = PANGO_GET_UNKNOWN_GLYPH (wc); - - pango_ot_buffer_add_glyph (buffer, glyph, 0, cluster); - - p = g_utf8_next_char (p); - } + glyphs->glyphs[i].glyph = hb_glyph->codepoint; + glyphs->log_clusters[i] = hb_glyph->cluster; + glyphs->glyphs[i].attr.is_cluster_start = glyphs->log_clusters[i] != last_cluster; + last_cluster = glyphs->log_clusters[i]; - desc.script = analysis->script; - desc.language = analysis->language; + glyphs->glyphs[i].geometry.width = hb_position->x_advance; + glyphs->glyphs[i].geometry.x_offset = hb_position->x_offset; + glyphs->glyphs[i].geometry.y_offset = hb_position->y_offset; - if (PANGO_GRAVITY_IS_VERTICAL (analysis->gravity)) - { - desc.n_static_gsub_features = G_N_ELEMENTS (vertical_gsub_features); - desc.static_gsub_features = vertical_gsub_features; - desc.n_static_gpos_features = G_N_ELEMENTS (vertical_gpos_features); - desc.static_gpos_features = vertical_gpos_features; - } - else - { - desc.n_static_gsub_features = G_N_ELEMENTS (gsub_features); - desc.static_gsub_features = gsub_features; - desc.n_static_gpos_features = G_N_ELEMENTS (gpos_features); - desc.static_gpos_features = gpos_features; + hb_glyph++; + hb_position++; } - /* TODO populate other_features from analysis->extra_attrs */ - desc.n_other_features = 0; - desc.other_features = NULL; - - ruleset = pango_ot_ruleset_get_for_description (pango_ot_info_get (face), &desc); - - pango_ot_ruleset_substitute (ruleset, buffer); - pango_ot_ruleset_position (ruleset, buffer); - pango_ot_buffer_output (buffer, glyphs); - - pango_ot_buffer_destroy (buffer); - + release_buffer (hb_buffer, free_buffer); + hb_face_destroy (hb_face); pango_fc_font_unlock_face (fc_font); } |