Makefile.am | 3 configure.ac | 1 src/Makefile.am | 13 - src/hb-uniscribe-shape.cc | 7 src/hb-view.cc | 568 ---------------------------------------------- src/test.cc | 3 test/hb-test.h | 3 test/test-shape-complex.c | 20 + util/Makefile.am | 24 + util/hb-view.cc | 568 ++++++++++++++++++++++++++++++++++++++++++++++ 10 files changed, 618 insertions(+), 592 deletions(-)
New commits: commit 511a136f0c092880b19250a5df53bcf9f4b043ca Author: Behdad Esfahbod <[email protected]> Date: Tue Aug 9 15:03:00 2011 +0200 Move hb-view into util/ diff --git a/Makefile.am b/Makefile.am index bb68ede..8b69c2d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -2,7 +2,7 @@ NULL = -SUBDIRS = src test +SUBDIRS = src util test pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = harfbuzz.pc @@ -76,5 +76,4 @@ $(gpg_file): $(sha256_file) release-files: $(tar_file) $(sha256_file) $(gpg_file) - -include $(top_srcdir)/git.mk diff --git a/configure.ac b/configure.ac index 3f13c43..d960856 100644 --- a/configure.ac +++ b/configure.ac @@ -161,6 +161,7 @@ Makefile harfbuzz.pc src/Makefile src/hb-version.h +util/Makefile test/Makefile ]) diff --git a/src/Makefile.am b/src/Makefile.am index 9b0307a..62a5b39 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -149,19 +149,6 @@ hb-ot-shape-complex-indic-machine.hh: hb-ot-shape-complex-indic-machine.rl noinst_PROGRAMS = main test bin_PROGRAMS = -if HAVE_GLIB -if HAVE_FREETYPE -if HAVE_CAIRO_FT -if HAVE_CAIRO_PNG -hb_view_SOURCES = hb-view.cc -hb_view_CPPFLAGS = $(HBCFLAGS) $(CAIRO_FT_CFLAGS) $(CAIRO_PNG_CFLAGS) -hb_view_LDADD = libharfbuzz.la -lm $(HBLIBS) $(CAIRO_FT_LIBS) $(CAIRO_PNG_LIBS) -bin_PROGRAMS += hb-view -endif -endif -endif -endif - main_SOURCES = main.cc main_CPPFLAGS = $(HBCFLAGS) main_LDADD = libharfbuzz.la $(HBLIBS) diff --git a/src/hb-view.cc b/src/hb-view.cc deleted file mode 100644 index dc3fc47..0000000 --- a/src/hb-view.cc +++ /dev/null @@ -1,568 +0,0 @@ -/* - * Copyright © 2010 Behdad Esfahbod - * Copyright © 2011 Google, Inc. - * - * This is part of HarfBuzz, a text shaping library. - * - * Permission is hereby granted, without written agreement and without - * license or royalty fees, to use, copy, modify, and distribute this - * software and its documentation for any purpose, provided that the - * above copyright notice and the following two paragraphs appear in - * all copies of this software. - * - * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN - * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - * Google Author(s): Behdad Esfahbod - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <unistd.h> -#include <getopt.h> -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <math.h> -#include <locale.h> - -#include <glib.h> - -#include <cairo-ft.h> -#include <hb-ft.h> - - - -/* Controlled by cmd-line options */ -static int margin_t = 10; -static int margin_b = 10; -static int margin_l = 10; -static int margin_r = 10; -static int line_space = 0; -static int face_index = 0; -static double font_size = 18; -static const char *fore = "#000000"; -static const char *back = "#ffffff"; -static const char *text = NULL; -static const char *font_file = NULL; -static const char *out_file = "/dev/stdout"; -static const char *direction = NULL; -static const char *script = NULL; -static const char *language = NULL; -static hb_feature_t *features = NULL; -static unsigned int num_features; -static hb_bool_t annotate = FALSE; -static hb_bool_t debug = FALSE; - -/* Ugh, global vars. Ugly, but does the job */ -static int width = 0; -static int height = 0; -static cairo_surface_t *surface = NULL; -static cairo_pattern_t *fore_pattern = NULL; -static cairo_pattern_t *back_pattern = NULL; -static cairo_font_face_t *cairo_face; - - -G_GNUC_NORETURN static void -usage (FILE *f, int status) -{ - fprintf (f, "usage: hb-view [OPTS...] font-file text\n"); - exit (status); -} - -G_GNUC_NORETURN static void -version (void) -{ - printf ("hb-view (harfbuzz) %s\n", HB_VERSION_STRING); - exit (0); -} - -static void parse_features (char *s); - -static void -parse_opts (int argc, char **argv) -{ - argv[0] = (char *) "hb-view"; - while (1) - { - int option_index = 0, c; - static const struct option long_options[] = { - {"annotate", 0, &annotate, TRUE}, - {"background", 1, 0, 'B'}, - {"debug", 0, &debug, TRUE}, - {"direction", 1, 0, 'd'}, - {"features", 1, 0, 'f'}, - {"font-size", 1, 0, 's'}, - {"face-index", 1, 0, 'i'}, - {"foreground", 1, 0, 'F'}, - {"help", 0, 0, 'h'}, - {"language", 1, 0, 'L'}, - {"line-space", 1, 0, 'l'}, - {"margin", 1, 0, 'm'}, - {"output", 1, 0, 'o'}, - {"script", 1, 0, 'S'}, - {"version", 0, 0, 'v'}, - {0, 0, 0, 0} - }; - - c = getopt_long (argc, argv, "", long_options, &option_index); - if (c == -1) - break; - - switch (c) - { - case 0: - break; - case 'h': - usage (stdout, 0); - break; - case 'v': - version (); - break; - case 'i': - face_index = atoi (optarg); - break; - case 'l': - line_space = atoi (optarg); - break; - case 'm': - switch (sscanf (optarg, "%d %d %d %d", &margin_t, &margin_r, &margin_b, &margin_l)) { - default: break; - case 1: margin_r = margin_t; - case 2: margin_b = margin_t; - case 3: margin_l = margin_r; - } - break; - case 's': - font_size = strtod (optarg, NULL); - break; - case 'f': - parse_features (optarg); - break; - case 'F': - fore = optarg; - break; - case 'B': - back = optarg; - break; - case 't': - text = optarg; - break; - case 'd': - direction = optarg; - break; - case 'S': - script = optarg; - break; - case 'L': - language = optarg; - break; - case 'o': - out_file = optarg; - break; - case '?': - usage (stdout, 1); - break; - default: - break; - } - } - if (optind + 2 != argc) - usage (stderr, 1); - font_file = argv[optind++]; - text = argv[optind++]; -} - - -static void -parse_space (char **pp) -{ - char c; -#define ISSPACE(c) ((c)==' '||(c)=='\f'||(c)=='\n'||(c)=='\r'||(c)=='\t'||(c)=='\v') - while (c = **pp, ISSPACE (c)) - (*pp)++; -#undef ISSPACE -} - -static hb_bool_t -parse_char (char **pp, char c) -{ - parse_space (pp); - - if (**pp != c) - return FALSE; - - (*pp)++; - return TRUE; -} - -static hb_bool_t -parse_uint (char **pp, unsigned int *pv) -{ - char *p = *pp; - unsigned int v; - - v = strtol (p, pp, 0); - - if (p == *pp) - return FALSE; - - *pv = v; - return TRUE; -} - - -static hb_bool_t -parse_feature_value_prefix (char **pp, hb_feature_t *feature) -{ - if (parse_char (pp, '-')) - feature->value = 0; - else { - parse_char (pp, '+'); - feature->value = 1; - } - - return TRUE; -} - -static hb_bool_t -parse_feature_tag (char **pp, hb_feature_t *feature) -{ - char *p = *pp, c; - - parse_space (pp); - -#define ISALNUM(c) (('a' <= (c) && (c) <= 'z') || ('A' <= (c) && (c) <= 'Z') || ('0' <= (c) && (c) <= '9')) - while (c = **pp, ISALNUM(c)) - (*pp)++; -#undef ISALNUM - - if (p == *pp) - return FALSE; - - **pp = '\0'; - feature->tag = hb_tag_from_string (p); - **pp = c; - - return TRUE; -} - -static hb_bool_t -parse_feature_indices (char **pp, hb_feature_t *feature) -{ - hb_bool_t has_start; - - feature->start = 0; - feature->end = (unsigned int) -1; - - if (!parse_char (pp, '[')) - return TRUE; - - has_start = parse_uint (pp, &feature->start); - - if (parse_char (pp, ':')) { - parse_uint (pp, &feature->end); - } else { - if (has_start) - feature->end = feature->start + 1; - } - - return parse_char (pp, ']'); -} - -static hb_bool_t -parse_feature_value_postfix (char **pp, hb_feature_t *feature) -{ - return !parse_char (pp, '=') || parse_uint (pp, &feature->value); -} - - -static hb_bool_t -parse_one_feature (char **pp, hb_feature_t *feature) -{ - return parse_feature_value_prefix (pp, feature) && - parse_feature_tag (pp, feature) && - parse_feature_indices (pp, feature) && - parse_feature_value_postfix (pp, feature) && - (parse_char (pp, ',') || **pp == '\0'); -} - -static void -skip_one_feature (char **pp) -{ - char *e; - e = strchr (*pp, ','); - if (e) - *pp = e + 1; - else - *pp = *pp + strlen (*pp); -} - -static void parse_features (char *s) -{ - char *p; - - num_features = 0; - features = NULL; - - if (!*s) - return; - - /* count the features first, so we can allocate memory */ - p = s; - do { - num_features++; - p = strchr (p, ','); - if (p) - p++; - } while (p); - - features = (hb_feature_t *) calloc (num_features, sizeof (*features)); - - /* now do the actual parsing */ - p = s; - num_features = 0; - while (*p) { - if (parse_one_feature (&p, &features[num_features])) - num_features++; - else - skip_one_feature (&p); - } -} - - -static cairo_glyph_t * -_hb_cr_text_glyphs (cairo_t *cr, - const char *utf8, int len, - unsigned int *pnum_glyphs) -{ - cairo_scaled_font_t *scaled_font = cairo_get_scaled_font (cr); - FT_Face ft_face = cairo_ft_scaled_font_lock_face (scaled_font); - hb_font_t *hb_font = hb_ft_font_create (ft_face, NULL); - hb_buffer_t *hb_buffer; - cairo_glyph_t *cairo_glyphs; - hb_glyph_info_t *hb_glyph; - hb_glyph_position_t *hb_position; - unsigned int num_glyphs, i; - hb_position_t x, y; - - hb_buffer = hb_buffer_create (0); - - if (direction) - hb_buffer_set_direction (hb_buffer, hb_direction_from_string (direction)); - if (script) - hb_buffer_set_script (hb_buffer, hb_script_from_string (script)); - if (language) - hb_buffer_set_language (hb_buffer, hb_language_from_string (language)); - - if (len < 0) - len = strlen (utf8); - hb_buffer_add_utf8 (hb_buffer, utf8, len, 0, len); - - hb_shape (hb_font, hb_buffer, features, num_features); - - num_glyphs = hb_buffer_get_length (hb_buffer); - hb_glyph = hb_buffer_get_glyph_infos (hb_buffer, NULL); - hb_position = hb_buffer_get_glyph_positions (hb_buffer, NULL); - cairo_glyphs = cairo_glyph_allocate (num_glyphs); - x = 0; - y = 0; - for (i = 0; i < num_glyphs; i++) - { - cairo_glyphs[i].index = hb_glyph->codepoint; - cairo_glyphs[i].x = ( hb_position->x_offset + x) * (1./64); - cairo_glyphs[i].y = (-hb_position->y_offset + y) * (1./64); - x += hb_position->x_advance; - y += -hb_position->y_advance; - - hb_glyph++; - hb_position++; - } - hb_buffer_destroy (hb_buffer); - hb_font_destroy (hb_font); - cairo_ft_scaled_font_unlock_face (scaled_font); - - if (pnum_glyphs) - *pnum_glyphs = num_glyphs; - return cairo_glyphs; -} - -static cairo_t * -create_context (void) -{ - cairo_t *cr; - unsigned int fr, fg, fb, fa, br, bg, bb, ba; - - if (surface) - cairo_surface_destroy (surface); - if (back_pattern) - cairo_pattern_destroy (back_pattern); - if (fore_pattern) - cairo_pattern_destroy (fore_pattern); - - br = bg = bb = ba = 255; - sscanf (back + (*back=='#'), "%2x%2x%2x%2x", &br, &bg, &bb, &ba); - fr = fg = fb = 0; fa = 255; - sscanf (fore + (*fore=='#'), "%2x%2x%2x%2x", &fr, &fg, &fb, &fa); - - if (!annotate && ba == 255 && fa == 255 && br == bg && bg == bb && fr == fg && fg == fb) { - /* grayscale. use A8 surface */ - surface = cairo_image_surface_create (CAIRO_FORMAT_A8, width, height); - cr = cairo_create (surface); - cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); - cairo_set_source_rgba (cr, 1., 1., 1., br / 255.); - cairo_paint (cr); - back_pattern = cairo_pattern_reference (cairo_get_source (cr)); - cairo_set_source_rgba (cr, 1., 1., 1., fr / 255.); - fore_pattern = cairo_pattern_reference (cairo_get_source (cr)); - } else { - /* color. use (A)RGB surface */ - if (ba != 255) - surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height); - else - surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, width, height); - cr = cairo_create (surface); - cairo_set_source_rgba (cr, br / 255., bg / 255., bb / 255., ba / 255.); - cairo_paint (cr); - back_pattern = cairo_pattern_reference (cairo_get_source (cr)); - cairo_set_source_rgba (cr, fr / 255., fg / 255., fb / 255., fa / 255.); - fore_pattern = cairo_pattern_reference (cairo_get_source (cr)); - } - - cairo_set_font_face (cr, cairo_face); - - return cr; -} - -static void -draw (void) -{ - cairo_t *cr; - cairo_font_extents_t font_extents; - - cairo_glyph_t *glyphs = NULL; - unsigned int num_glyphs = 0; - - const char *end, *p = text; - double x, y; - - cr= create_context (); - - cairo_set_font_size (cr, font_size); - cairo_font_extents (cr, &font_extents); - - height = 0; - width = 0; - - x = margin_l; - y = margin_t; - - do { - cairo_text_extents_t extents; - - end = strchr (p, '\n'); - if (!end) - end = p + strlen (p); - - if (p != text) - y += line_space; - - if (p != end) { - glyphs = _hb_cr_text_glyphs (cr, p, end - p, &num_glyphs); - - cairo_glyph_extents (cr, glyphs, num_glyphs, &extents); - - y += ceil (font_extents.ascent); - width = MAX (width, extents.x_advance); - cairo_save (cr); - cairo_translate (cr, x, y); - if (annotate) { - unsigned int i; - cairo_save (cr); - - /* Draw actual glyph origins */ - cairo_set_source_rgba (cr, 1., 0., 0., .5); - cairo_set_line_width (cr, 5); - cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND); - for (i = 0; i < num_glyphs; i++) { - cairo_move_to (cr, glyphs[i].x, glyphs[i].y); - cairo_rel_line_to (cr, 0, 0); - } - cairo_stroke (cr); - - cairo_restore (cr); - } - cairo_show_glyphs (cr, glyphs, num_glyphs); - cairo_restore (cr); - y += ceil (font_extents.height - ceil (font_extents.ascent)); - - cairo_glyph_free (glyphs); - } - - p = end + 1; - } while (*end); - - height = y + margin_b; - width += margin_l + margin_r; - - cairo_destroy (cr); -} - - - -int -main (int argc, char **argv) -{ - static FT_Library ft_library; - static FT_Face ft_face; - cairo_status_t status; - - setlocale (LC_ALL, ""); - - parse_opts (argc, argv); - - FT_Init_FreeType (&ft_library); - if (FT_New_Face (ft_library, font_file, face_index, &ft_face)) { - fprintf (stderr, "Failed to open font file `%s'\n", font_file); - exit (1); - } - cairo_face = cairo_ft_font_face_create_for_ft_face (ft_face, 0); - - draw (); - draw (); - - status = cairo_surface_write_to_png (surface, out_file); - if (status != CAIRO_STATUS_SUCCESS) { - fprintf (stderr, "Failed to write output file `%s': %s\n", - out_file, cairo_status_to_string (status)); - exit (1); - } - - if (debug) { - free (features); - - cairo_pattern_destroy (fore_pattern); - cairo_pattern_destroy (back_pattern); - cairo_surface_destroy (surface); - cairo_font_face_destroy (cairo_face); - cairo_debug_reset_static_data (); - - FT_Done_Face (ft_face); - FT_Done_FreeType (ft_library); - } - - return 0; -} - - diff --git a/util/Makefile.am b/util/Makefile.am new file mode 100644 index 0000000..a3ae980 --- /dev/null +++ b/util/Makefile.am @@ -0,0 +1,24 @@ +# Process this file with automake to produce Makefile.in + +NULL = +EXTRA_DIST = +CLEANFILES = +DISTCLEANFILES = +MAINTAINERCLEANFILES = + +bin_PROGRAMS = + +if HAVE_GLIB +if HAVE_FREETYPE +if HAVE_CAIRO_FT +if HAVE_CAIRO_PNG +hb_view_SOURCES = hb-view.cc +hb_view_CPPFLAGS = -I$(top_srcdir)/src/ -I$(top_builddir)/src/ $(GLIB_CFLAGS) $(FREETYPE_CFLAGS) $(CAIRO_FT_CFLAGS) $(CAIRO_PNG_CFLAGS) +hb_view_LDADD = $(top_builddir)/src/libharfbuzz.la -lm $(GLIB_LIBS) $(FREETYPE_LIBS) $(CAIRO_FT_LIBS) $(CAIRO_PNG_LIBS) +bin_PROGRAMS += hb-view +endif +endif +endif +endif + +-include $(top_srcdir)/git.mk diff --git a/util/hb-view.cc b/util/hb-view.cc new file mode 100644 index 0000000..dc3fc47 --- /dev/null +++ b/util/hb-view.cc @@ -0,0 +1,568 @@ +/* + * Copyright © 2010 Behdad Esfahbod + * Copyright © 2011 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Behdad Esfahbod + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <unistd.h> +#include <getopt.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <math.h> +#include <locale.h> + +#include <glib.h> + +#include <cairo-ft.h> +#include <hb-ft.h> + + + +/* Controlled by cmd-line options */ +static int margin_t = 10; +static int margin_b = 10; +static int margin_l = 10; +static int margin_r = 10; +static int line_space = 0; +static int face_index = 0; +static double font_size = 18; +static const char *fore = "#000000"; +static const char *back = "#ffffff"; +static const char *text = NULL; +static const char *font_file = NULL; +static const char *out_file = "/dev/stdout"; +static const char *direction = NULL; +static const char *script = NULL; +static const char *language = NULL; +static hb_feature_t *features = NULL; +static unsigned int num_features; +static hb_bool_t annotate = FALSE; +static hb_bool_t debug = FALSE; + +/* Ugh, global vars. Ugly, but does the job */ +static int width = 0; +static int height = 0; +static cairo_surface_t *surface = NULL; +static cairo_pattern_t *fore_pattern = NULL; +static cairo_pattern_t *back_pattern = NULL; +static cairo_font_face_t *cairo_face; + + +G_GNUC_NORETURN static void +usage (FILE *f, int status) +{ + fprintf (f, "usage: hb-view [OPTS...] font-file text\n"); + exit (status); +} + +G_GNUC_NORETURN static void +version (void) +{ + printf ("hb-view (harfbuzz) %s\n", HB_VERSION_STRING); + exit (0); +} + +static void parse_features (char *s); + +static void +parse_opts (int argc, char **argv) +{ + argv[0] = (char *) "hb-view"; + while (1) + { + int option_index = 0, c; + static const struct option long_options[] = { + {"annotate", 0, &annotate, TRUE}, + {"background", 1, 0, 'B'}, + {"debug", 0, &debug, TRUE}, + {"direction", 1, 0, 'd'}, + {"features", 1, 0, 'f'}, + {"font-size", 1, 0, 's'}, + {"face-index", 1, 0, 'i'}, + {"foreground", 1, 0, 'F'}, + {"help", 0, 0, 'h'}, + {"language", 1, 0, 'L'}, + {"line-space", 1, 0, 'l'}, + {"margin", 1, 0, 'm'}, + {"output", 1, 0, 'o'}, + {"script", 1, 0, 'S'}, + {"version", 0, 0, 'v'}, + {0, 0, 0, 0} + }; + + c = getopt_long (argc, argv, "", long_options, &option_index); + if (c == -1) + break; + + switch (c) + { + case 0: + break; + case 'h': + usage (stdout, 0); + break; + case 'v': + version (); + break; + case 'i': + face_index = atoi (optarg); + break; + case 'l': + line_space = atoi (optarg); + break; + case 'm': + switch (sscanf (optarg, "%d %d %d %d", &margin_t, &margin_r, &margin_b, &margin_l)) { + default: break; + case 1: margin_r = margin_t; + case 2: margin_b = margin_t; + case 3: margin_l = margin_r; + } + break; + case 's': + font_size = strtod (optarg, NULL); + break; + case 'f': + parse_features (optarg); + break; + case 'F': + fore = optarg; + break; + case 'B': + back = optarg; + break; + case 't': + text = optarg; + break; + case 'd': + direction = optarg; + break; + case 'S': + script = optarg; + break; + case 'L': + language = optarg; + break; + case 'o': + out_file = optarg; + break; + case '?': + usage (stdout, 1); + break; + default: + break; + } + } + if (optind + 2 != argc) + usage (stderr, 1); + font_file = argv[optind++]; + text = argv[optind++]; +} + + +static void +parse_space (char **pp) +{ + char c; +#define ISSPACE(c) ((c)==' '||(c)=='\f'||(c)=='\n'||(c)=='\r'||(c)=='\t'||(c)=='\v') + while (c = **pp, ISSPACE (c)) + (*pp)++; +#undef ISSPACE +} + +static hb_bool_t +parse_char (char **pp, char c) +{ + parse_space (pp); + + if (**pp != c) + return FALSE; + + (*pp)++; + return TRUE; +} + +static hb_bool_t +parse_uint (char **pp, unsigned int *pv) +{ + char *p = *pp; + unsigned int v; + + v = strtol (p, pp, 0); + + if (p == *pp) + return FALSE; + + *pv = v; + return TRUE; +} + + +static hb_bool_t +parse_feature_value_prefix (char **pp, hb_feature_t *feature) +{ + if (parse_char (pp, '-')) + feature->value = 0; + else { + parse_char (pp, '+'); + feature->value = 1; + } + + return TRUE; +} + +static hb_bool_t +parse_feature_tag (char **pp, hb_feature_t *feature) +{ + char *p = *pp, c; + + parse_space (pp); + +#define ISALNUM(c) (('a' <= (c) && (c) <= 'z') || ('A' <= (c) && (c) <= 'Z') || ('0' <= (c) && (c) <= '9')) + while (c = **pp, ISALNUM(c)) + (*pp)++; +#undef ISALNUM + + if (p == *pp) + return FALSE; + + **pp = '\0'; + feature->tag = hb_tag_from_string (p); + **pp = c; + + return TRUE; +} + +static hb_bool_t +parse_feature_indices (char **pp, hb_feature_t *feature) +{ + hb_bool_t has_start; + + feature->start = 0; + feature->end = (unsigned int) -1; + + if (!parse_char (pp, '[')) + return TRUE; + + has_start = parse_uint (pp, &feature->start); + + if (parse_char (pp, ':')) { + parse_uint (pp, &feature->end); + } else { + if (has_start) + feature->end = feature->start + 1; + } + + return parse_char (pp, ']'); +} + +static hb_bool_t +parse_feature_value_postfix (char **pp, hb_feature_t *feature) +{ + return !parse_char (pp, '=') || parse_uint (pp, &feature->value); +} + + +static hb_bool_t +parse_one_feature (char **pp, hb_feature_t *feature) +{ + return parse_feature_value_prefix (pp, feature) && + parse_feature_tag (pp, feature) && + parse_feature_indices (pp, feature) && + parse_feature_value_postfix (pp, feature) && + (parse_char (pp, ',') || **pp == '\0'); +} + +static void +skip_one_feature (char **pp) +{ + char *e; + e = strchr (*pp, ','); + if (e) + *pp = e + 1; + else + *pp = *pp + strlen (*pp); +} + +static void parse_features (char *s) +{ + char *p; + + num_features = 0; + features = NULL; + + if (!*s) + return; + + /* count the features first, so we can allocate memory */ + p = s; + do { + num_features++; + p = strchr (p, ','); + if (p) + p++; + } while (p); + + features = (hb_feature_t *) calloc (num_features, sizeof (*features)); + + /* now do the actual parsing */ + p = s; + num_features = 0; + while (*p) { + if (parse_one_feature (&p, &features[num_features])) + num_features++; + else + skip_one_feature (&p); + } +} + + +static cairo_glyph_t * +_hb_cr_text_glyphs (cairo_t *cr, + const char *utf8, int len, + unsigned int *pnum_glyphs) +{ + cairo_scaled_font_t *scaled_font = cairo_get_scaled_font (cr); + FT_Face ft_face = cairo_ft_scaled_font_lock_face (scaled_font); + hb_font_t *hb_font = hb_ft_font_create (ft_face, NULL); + hb_buffer_t *hb_buffer; + cairo_glyph_t *cairo_glyphs; + hb_glyph_info_t *hb_glyph; + hb_glyph_position_t *hb_position; + unsigned int num_glyphs, i; + hb_position_t x, y; + + hb_buffer = hb_buffer_create (0); + + if (direction) + hb_buffer_set_direction (hb_buffer, hb_direction_from_string (direction)); + if (script) + hb_buffer_set_script (hb_buffer, hb_script_from_string (script)); + if (language) + hb_buffer_set_language (hb_buffer, hb_language_from_string (language)); + + if (len < 0) + len = strlen (utf8); + hb_buffer_add_utf8 (hb_buffer, utf8, len, 0, len); + + hb_shape (hb_font, hb_buffer, features, num_features); + + num_glyphs = hb_buffer_get_length (hb_buffer); + hb_glyph = hb_buffer_get_glyph_infos (hb_buffer, NULL); + hb_position = hb_buffer_get_glyph_positions (hb_buffer, NULL); + cairo_glyphs = cairo_glyph_allocate (num_glyphs); + x = 0; + y = 0; + for (i = 0; i < num_glyphs; i++) + { + cairo_glyphs[i].index = hb_glyph->codepoint; + cairo_glyphs[i].x = ( hb_position->x_offset + x) * (1./64); + cairo_glyphs[i].y = (-hb_position->y_offset + y) * (1./64); + x += hb_position->x_advance; + y += -hb_position->y_advance; + + hb_glyph++; + hb_position++; + } + hb_buffer_destroy (hb_buffer); + hb_font_destroy (hb_font); + cairo_ft_scaled_font_unlock_face (scaled_font); + + if (pnum_glyphs) + *pnum_glyphs = num_glyphs; + return cairo_glyphs; +} + +static cairo_t * +create_context (void) +{ + cairo_t *cr; + unsigned int fr, fg, fb, fa, br, bg, bb, ba; + + if (surface) + cairo_surface_destroy (surface); + if (back_pattern) + cairo_pattern_destroy (back_pattern); + if (fore_pattern) + cairo_pattern_destroy (fore_pattern); + + br = bg = bb = ba = 255; + sscanf (back + (*back=='#'), "%2x%2x%2x%2x", &br, &bg, &bb, &ba); + fr = fg = fb = 0; fa = 255; + sscanf (fore + (*fore=='#'), "%2x%2x%2x%2x", &fr, &fg, &fb, &fa); + + if (!annotate && ba == 255 && fa == 255 && br == bg && bg == bb && fr == fg && fg == fb) { + /* grayscale. use A8 surface */ + surface = cairo_image_surface_create (CAIRO_FORMAT_A8, width, height); + cr = cairo_create (surface); + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + cairo_set_source_rgba (cr, 1., 1., 1., br / 255.); + cairo_paint (cr); + back_pattern = cairo_pattern_reference (cairo_get_source (cr)); + cairo_set_source_rgba (cr, 1., 1., 1., fr / 255.); + fore_pattern = cairo_pattern_reference (cairo_get_source (cr)); + } else { + /* color. use (A)RGB surface */ + if (ba != 255) + surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height); + else + surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, width, height); + cr = cairo_create (surface); + cairo_set_source_rgba (cr, br / 255., bg / 255., bb / 255., ba / 255.); + cairo_paint (cr); + back_pattern = cairo_pattern_reference (cairo_get_source (cr)); + cairo_set_source_rgba (cr, fr / 255., fg / 255., fb / 255., fa / 255.); + fore_pattern = cairo_pattern_reference (cairo_get_source (cr)); + } + + cairo_set_font_face (cr, cairo_face); + + return cr; +} + +static void +draw (void) +{ + cairo_t *cr; + cairo_font_extents_t font_extents; + + cairo_glyph_t *glyphs = NULL; + unsigned int num_glyphs = 0; + + const char *end, *p = text; + double x, y; + + cr= create_context (); + + cairo_set_font_size (cr, font_size); + cairo_font_extents (cr, &font_extents); + + height = 0; + width = 0; + + x = margin_l; + y = margin_t; + + do { + cairo_text_extents_t extents; + + end = strchr (p, '\n'); + if (!end) + end = p + strlen (p); + + if (p != text) + y += line_space; + + if (p != end) { + glyphs = _hb_cr_text_glyphs (cr, p, end - p, &num_glyphs); + + cairo_glyph_extents (cr, glyphs, num_glyphs, &extents); + + y += ceil (font_extents.ascent); + width = MAX (width, extents.x_advance); + cairo_save (cr); + cairo_translate (cr, x, y); + if (annotate) { + unsigned int i; + cairo_save (cr); + + /* Draw actual glyph origins */ + cairo_set_source_rgba (cr, 1., 0., 0., .5); + cairo_set_line_width (cr, 5); + cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND); + for (i = 0; i < num_glyphs; i++) { + cairo_move_to (cr, glyphs[i].x, glyphs[i].y); + cairo_rel_line_to (cr, 0, 0); + } + cairo_stroke (cr); + + cairo_restore (cr); + } + cairo_show_glyphs (cr, glyphs, num_glyphs); + cairo_restore (cr); + y += ceil (font_extents.height - ceil (font_extents.ascent)); + + cairo_glyph_free (glyphs); + } + + p = end + 1; + } while (*end); + + height = y + margin_b; + width += margin_l + margin_r; + + cairo_destroy (cr); +} + + + +int +main (int argc, char **argv) +{ + static FT_Library ft_library; + static FT_Face ft_face; + cairo_status_t status; + + setlocale (LC_ALL, ""); + + parse_opts (argc, argv); + + FT_Init_FreeType (&ft_library); + if (FT_New_Face (ft_library, font_file, face_index, &ft_face)) { + fprintf (stderr, "Failed to open font file `%s'\n", font_file); + exit (1); + } + cairo_face = cairo_ft_font_face_create_for_ft_face (ft_face, 0); + + draw (); + draw (); + + status = cairo_surface_write_to_png (surface, out_file); + if (status != CAIRO_STATUS_SUCCESS) { + fprintf (stderr, "Failed to write output file `%s': %s\n", + out_file, cairo_status_to_string (status)); + exit (1); + } + + if (debug) { + free (features); + + cairo_pattern_destroy (fore_pattern); + cairo_pattern_destroy (back_pattern); + cairo_surface_destroy (surface); + cairo_font_face_destroy (cairo_face); + cairo_debug_reset_static_data (); + + FT_Done_Face (ft_face); + FT_Done_FreeType (ft_library); + } + + return 0; +} + + commit d753ac78da5619a0a545cdaf7a8e65787e996570 Author: Behdad Esfahbod <[email protected]> Date: Tue Aug 9 14:03:12 2011 +0200 [uniscribe] Remove zerowidth glyphs from output diff --git a/src/hb-uniscribe-shape.cc b/src/hb-uniscribe-shape.cc index a0020ca..e583ae1 100644 --- a/src/hb-uniscribe-shape.cc +++ b/src/hb-uniscribe-shape.cc @@ -399,9 +399,13 @@ retry: #undef FAIL /* Set glyph infos */ + buffer->len = 0; for (unsigned int i = 0; i < glyphs_len; i++) { - hb_glyph_info_t *info = &buffer->info[i]; + if (glyph_props[i].sva.fZeroWidth) + continue; + + hb_glyph_info_t *info = &buffer->info[buffer->len++]; info->codepoint = glyphs[i]; info->cluster = vis_clusters[i]; @@ -411,7 +415,6 @@ retry: info->var1.u32 = offsets[i].du; info->var2.u32 = offsets[i].dv; } - buffer->len = glyphs_len; /* Set glyph positions */ buffer->clear_positions (); commit 217cc81cd9c3de30b2ef226983ec43c0f78b5c7d Author: Behdad Esfahbod <[email protected]> Date: Tue Aug 9 14:00:44 2011 +0200 [test/shape-complex] Print cluster and position info in --verbose diff --git a/test/test-shape-complex.c b/test/test-shape-complex.c index 1963b5e..6416b36 100644 --- a/test/test-shape-complex.c +++ b/test/test-shape-complex.c @@ -1029,6 +1029,7 @@ test_shape_complex (ft_fixture_t *f, gconstpointer user_data) hb_buffer_t *buffer; unsigned int i, len, expected_len; hb_glyph_info_t *glyphs; + hb_glyph_position_t *pos; hb_bool_t fail; GString *str; @@ -1047,6 +1048,7 @@ test_shape_complex (ft_fixture_t *f, gconstpointer user_data) expected_len = len; glyphs = hb_buffer_get_glyph_infos (buffer, &len); + pos = hb_buffer_get_glyph_positions (buffer, NULL); fail = len != expected_len; if (!fail) for (i = 0; i < len; i++) @@ -1056,13 +1058,25 @@ test_shape_complex (ft_fixture_t *f, gconstpointer user_data) } str = g_string_new (""); + for (i = 0; i < expected_len; i++) + g_string_append_printf (str, " %4d", data->glyphs[i]); + g_test_message ("Expected glyphs: %s", str->str); + g_string_truncate (str, 0); for (i = 0; i < len; i++) g_string_append_printf (str, " %4d", glyphs[i].codepoint); g_test_message ("Received glyphs: %s", str->str); g_string_truncate (str, 0); - for (i = 0; i < expected_len; i++) - g_string_append_printf (str, " %4d", data->glyphs[i]); - g_test_message ("Expected glyphs: %s", str->str); + for (i = 0; i < len; i++) + g_string_append_printf (str, " %d", glyphs[i].cluster); + g_test_message ("Received clusters: %s", str->str); + g_string_truncate (str, 0); + for (i = 0; i < len; i++) + g_string_append_printf (str, " (%d,%d)+(%d,%d)", + pos[i].x_offset, + pos[i].y_offset, + pos[i].x_advance, + pos[i].y_advance); + g_test_message ("Received positions: %s", str->str); g_string_free (str, TRUE); if (fail) { commit 708403e7f3e4a5cf9b0d2bd764fb74b148af7adb Author: Behdad Esfahbod <[email protected]> Date: Tue Aug 9 13:52:36 2011 +0200 Fix warnings with old glib diff --git a/test/hb-test.h b/test/hb-test.h index de9a79a..f36d53b 100644 --- a/test/hb-test.h +++ b/test/hb-test.h @@ -152,8 +152,7 @@ typedef GTestFixtureFunc hb_test_fixture_func_t; #else typedef void (*hb_test_func_t) (void); typedef void (*hb_test_data_func_t) (gconstpointer user_data); -typedef void (*hb_test_fixture_func_t) (gpointer fixture, - gconstpointer user_data); +typedef void (*hb_test_fixture_func_t) (void); #endif #if !GLIB_CHECK_VERSION(2,30,0) commit ddd247b0c528cdb8bdf5f8063180abe884afa305 Author: Behdad Esfahbod <[email protected]> Date: Tue Aug 9 11:44:42 2011 +0200 Minor diff --git a/src/test.cc b/src/test.cc index c446429..d1c0faf 100644 --- a/src/test.cc +++ b/src/test.cc @@ -1,5 +1,5 @@ /* - * Copyright © 2010 Google, Inc. + * Copyright © 2010,2011 Google, Inc. * * This is part of HarfBuzz, a text shaping library. * @@ -21,7 +21,6 @@ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. * - * Red Hat Author(s): Behdad Esfahbod * Google Author(s): Behdad Esfahbod */
_______________________________________________ HarfBuzz mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/harfbuzz
