X-Git-Url: http://git.chise.org/gitweb/?p=m17n%2Fm17n-test.git;a=blobdiff_plain;f=flt.c;h=5cf2479de07582dcd00a684c5724fffac7924ff9;hp=100f1ac1b1447389211beb8031e30de3fbe85b58;hb=1cf616637034fe2f47296758983c415b25966d17;hpb=ea2a7ab497ae116346546a12b8601c6d6c96ed75 diff --git a/flt.c b/flt.c index 100f1ac..5cf2479 100644 --- a/flt.c +++ b/flt.c @@ -9,49 +9,82 @@ #if defined (FLT_GUI) #include +#include #define PROGNAME "flt-gui" #elif defined (FLT_OTF) #include +#include #include #define PROGNAME "flt-otf" -#else /* defined (FLT_HB) */ +#elif defined (FLT_HB) #include #include #define PROGNAME "flt-hb" +#else /* (defined (FLT_PANGO)) */ + +#include +#include +#define PANGO_ENABLE_ENGINE +#define PANGO_ENABLE_BACKEND +#include +#include +#include +#include #endif static FT_Library ft_library; -FT_Face -new_face (char *fontname, char **err) +int +parse_font_name (char *fontname, char **family, int *size, char **err) { FcPattern *pat; - FcChar8 *fam, *file; + FcChar8 *fam; double pixelsize; - FcFontSet *fs; - FcObjectSet *os; - FT_Face face; pat = FcNameParse ((FcChar8 *) fontname); if (! pat) { *err = "invalid name format"; - return NULL; + return -1; } if (FcPatternGetString (pat, FC_FAMILY, 0, &fam) != FcResultMatch) { + FcPatternDestroy (pat); *err = "no family name"; - return NULL; + return -1; } if (FcPatternGetDouble (pat, FC_PIXEL_SIZE, 0, &pixelsize) != FcResultMatch) pixelsize = 20; - FcPatternAddBool (pat, FC_SCALABLE, FcTrue); - FcPatternDel (pat, FC_PIXEL_SIZE); + *family = strdup ((char *) fam); + *size = pixelsize; + FcPatternDestroy (pat); + return 0; +} + +FT_Face +new_face (char *fontname, char **err) +{ + FcPattern *pat; + FcChar8 *fam, *file; + int size; + double pixelsize; + FcFontSet *fs; + FcObjectSet *os; + FT_Face face; + + if (parse_font_name (fontname, (char **) &fam, &size, err) < 0) + return NULL; + pixelsize = size; + pat = FcPatternBuild (0, + FC_FAMILY, FcTypeString, fam, + FC_SCALABLE, FcTypeBool, FcTrue, + NULL); + free (fam); os = FcObjectSetBuild (FC_FILE, NULL); fs = FcFontList (NULL, pat, os); if (fs->nfont == 0) @@ -83,11 +116,23 @@ new_face (char *fontname, char **err) #ifdef FLT_GUI -typedef struct +typedef struct _MFLTFont MFLTFont; + +struct _MFLTFont { + int x_ppem, y_ppem; + void (*get_glyph_id) (void); + void (*get_metrics) (void); + void (*suitable_p) (void); + void (*drive_otf) (void); MFont *font; FT_Face face; -} MFLTFont; +}; + +void get_glyph_id (void) {} +void get_metrics (void) {} +void suitable_p (void) {} +void drive_otf (void) {} MFrame *frame; @@ -127,22 +172,7 @@ close_font (MFLTFont *font) m17n_object_unref (frame); } -int -flt (MText *mt, int from, int to, MFLTFont *font, char *flt_name) -{ - MDrawControl control; - - memset (&control, 0, sizeof (MDrawControl)); - control.two_dimensional = 1; - control.enable_bidi = 1; - control.anti_alias = 1; - /*control.disable_caching = 1;*/ - mtext_put_prop (mt, from, to, Mfont, font->font); - mdraw_text_extents (frame, mt, from, to, &control, NULL, NULL, NULL); - return 0; -} - -#else /* FLT_OTF or FLT_HB */ +#elif defined (FLT_OTF) || defined (FLT_HB) typedef struct { MFLTFont font; @@ -150,55 +180,50 @@ typedef struct { } FontInfo; int -get_glyph_id (MFLTFont *font, MFLTGlyph *g) +get_glyph_id (MFLTFont *font, MFLTGlyphString *gstring, int from, int to) { FT_Face face = ((FontInfo *) font)->face; - g->code = FT_Get_Char_Index (face, g->code); + for (; from < to; from++) + { + MFLTGlyph *g = gstring->glyphs + from; - return (g->code ? 0 : -1); + if (! g->encoded + && ! (g->code = FT_Get_Char_Index (face, g->code))) + return -1; + g->encoded = 1; + } + return 0; } int -get_metric (MFLTFont *font, MFLTGlyphString *gstring, int from, int to) +get_metrics (MFLTFont *font, MFLTGlyphString *gstring, int from, int to) { FT_Face face = ((FontInfo *) font)->face; for (; from < to; from++) { MFLTGlyph *g = gstring->glyphs + from; - FT_Glyph_Metrics *metrics; - if (FT_Load_Glyph (face, g->code, FT_LOAD_DEFAULT)) - return -1; - metrics = &face->glyph->metrics; - g->lbearing = metrics->horiBearingX; - g->rbearing = metrics->horiBearingX + metrics->width; - g->xadv = metrics->horiAdvance; - g->yadv = metrics->vertAdvance; - g->ascent = metrics->horiBearingY; - g->descent = metrics->height - metrics->horiBearingY; + if (! g->measured) + { + FT_Glyph_Metrics *metrics; + + if (FT_Load_Glyph (face, g->code, FT_LOAD_DEFAULT)) + return -1; + metrics = &face->glyph->metrics; + g->lbearing = metrics->horiBearingX; + g->rbearing = metrics->horiBearingX + metrics->width; + g->xadv = metrics->horiAdvance; + g->yadv = metrics->vertAdvance; + g->ascent = metrics->horiBearingY; + g->descent = metrics->height - metrics->horiBearingY; + g->measured = 1; + } } return 0; } -int -flt (MText *mt, int from, int to, MFLTFont *font, char *flt_name) -{ - MFLTGlyphString gstring; - int len = to - from; - int i; - - memset (&gstring, 0, sizeof (MFLTGlyphString)); - gstring.glyph_size = sizeof (MFLTGlyph); - gstring.allocated = len * 2; - gstring.glyphs = alloca (sizeof (MFLTGlyph) * gstring.allocated); - for (i = 0; i < len; i++) - gstring.glyphs[i].c = mtext_ref_char (mt, from + i); - gstring.used = len; - return mflt_run (&gstring, 0, len, font, msymbol (flt_name)); -} - #ifdef FLT_OTF typedef struct { @@ -362,7 +387,11 @@ drive_otf (MFLTFont *font, MFLTOtfSpec *spec, g->c = in->glyphs[j].c; break; } - g->code = otfg->glyph_id; + if (g->code != otfg->glyph_id) + { + g->code = otfg->glyph_id; + g->measured = 0; + } out->used++; } } @@ -374,8 +403,6 @@ drive_otf (MFLTFont *font, MFLTOtfSpec *spec, out->glyphs[out->used++] = in->glyphs[from + i]; } - font->get_metric (font, out, gidx, out->used); - if (gpos_features) { FT_Face face; @@ -480,7 +507,7 @@ drive_otf (MFLTFont *font, MFLTOtfSpec *spec, return to; simple_copy: - font->get_metric (font, in, from, to); + font->get_metrics (font, in, from, to); for (i = 0; i < len; i++) { MFLTGlyph *g = in->glyphs + (from + i); @@ -501,9 +528,6 @@ open_font (char *fontname, char **err) if (! face) return NULL; font_info = malloc (sizeof (FontInfoOTF)); - font_info->font.get_glyph_id = get_glyph_id; - font_info->font.get_metric = get_metric; - font_info->font.drive_otf = drive_otf; font_info->face = face; font_info->otf = OTF_open_ft_face (face); return ((MFLTFont *) font_info); @@ -714,7 +738,6 @@ setup_features (int gsubp, FontInfoHB *font_info, MFLTOtfSpec *spec, FT_UShort req_feature, index; FT_UInt *feature_list; int i, j, k; - HB_Error err; if (gsubp) { @@ -830,7 +853,7 @@ drive_otf (MFLTFont *font, MFLTOtfSpec *spec, { FontInfoHB *font_info = (FontInfoHB *) font; int len = to - from; - int i, gidx; + int i; HB_Buffer buf; GsubGposInfo *ginfo; HB_UShort *apply_order_save; @@ -885,8 +908,6 @@ drive_otf (MFLTFont *font, MFLTOtfSpec *spec, gpos_applied = 1; } - gidx = out->used; - for (i = 0; i < buf->in_length; i++) { HB_GlyphItem hg = buf->in_string + i; @@ -896,7 +917,11 @@ drive_otf (MFLTFont *font, MFLTOtfSpec *spec, out->glyphs[out->used] = in->glyphs[hg->cluster]; g = out->glyphs + out->used++; if (g->code != hg->gindex) - g->c = 0, g->code = hg->gindex; + { + g->c = 0; + g->code = hg->gindex; + g->measured = 0; + } adjustment[i].set = gpos_applied; if (gpos_applied) { @@ -927,9 +952,6 @@ open_font (char *fontname, char **err) if (! face) return NULL; font_info = calloc (1, sizeof (FontInfoHB)); - font_info->font.get_glyph_id = get_glyph_id; - font_info->font.get_metric = get_metric; - font_info->font.drive_otf = drive_otf; font_info->face = face; font_info->hb_font.klass = &hb_fontClass; font_info->hb_font.faceData = face; @@ -973,8 +995,363 @@ close_font (MFLTFont *font) } #endif + +#else /* (defined (FLT_PANGO) */ + +typedef struct { + int count; + guint *indices; + PangoOTRuleset *ruleset; +} FeatureInfo; + +typedef struct { + FeatureInfo gsub; + FeatureInfo gpos; +} GsubGposInfo; + +typedef struct { + MFLTFont font; + PangoFontMap *fontmap; + PangoContext *context; + PangoFcFont *pango_font; + MPlist *otf_spec_cache; +} FontInfoPango; + +int +get_glyph_id (MFLTFont *font, MFLTGlyphString *gstring, int from, int to) +{ + FontInfoPango *font_info = (FontInfoPango *) font; + + for (; from < to; from++) + { + MFLTGlyph *g = gstring->glyphs + from; + + if (! g->encoded + && ! (g->code = pango_fc_font_get_glyph (font_info->pango_font, + g->code))) + return -1; + g->encoded = 1; + } + return 0; +} + +#define PANGO_SCALE_TO_26_6 (PANGO_SCALE / (1<<6)) + +int +get_metrics (MFLTFont *font, MFLTGlyphString *gstring, int from, int to) +{ + FontInfoPango *font_info = (FontInfoPango *) font; + int i; + + for (i = from; i < to; i++) + { + MFLTGlyph *g = gstring->glyphs + from; + + if (! g->measured) + { + PangoRectangle inc, logical; + + pango_font_get_glyph_extents (PANGO_FONT (font_info->pango_font), + gstring->glyphs[i].code, &inc, &logical); + g->lbearing = inc.x / PANGO_SCALE_TO_26_6; + g->rbearing = (inc.x + inc.width) / PANGO_SCALE_TO_26_6; + g->xadv = logical.width / PANGO_SCALE_TO_26_6; + g->yadv = 0; + g->ascent = - inc.y / PANGO_SCALE_TO_26_6; + g->descent = (inc.height + inc.y) / PANGO_SCALE_TO_26_6; + g->measured = 1; + } + } + return 0; +} + + +#ifndef PANGO_OT_DEFAULT_LANGUAGE +#define PANGO_OT_DEFAULT_LANGUAGE ((guint) 0xFFFF) +#endif +#ifndef PANGO_OT_ALL_GLYPHS +#define PANGO_OT_ALL_GLYPHS ((guint) 0xFFFF) +#endif + +void +setup_features (PangoOTTableType type, FontInfoPango *font_info, + MFLTOtfSpec *spec, FeatureInfo *info) +{ + int count, preordered; + unsigned int *features; + guint script, langsys; + guint req_feature, index; + guint *feature_list; + int i, j, k; + FT_Face face; + PangoOTInfo *ot_info; + + face = pango_fc_font_lock_face (font_info->pango_font); + ot_info = pango_ot_info_get (face); + pango_fc_font_unlock_face (font_info->pango_font); + + if (! pango_ot_info_find_script (ot_info, type, spec->script, &script)) + return; + if (spec->langsys) + { + if (! pango_ot_info_find_language (ot_info, type, script, + spec->langsys, + &langsys, &req_feature)) + return; + } + else + { + langsys = PANGO_OT_DEFAULT_LANGUAGE; + req_feature = 0xFFFF; + } + if (type == PANGO_OT_TABLE_GSUB) + { + count = spec->gsub_count; + features = spec->gsub; + } + else + { + count = spec->gpos_count; + features = spec->gpos; + } + feature_list = NULL; + for (preordered = 0; preordered < count; preordered++) + if (features[preordered] == 0) + { + feature_list = pango_ot_info_list_features (ot_info, type, 0, + script, langsys); + if (! feature_list) + return; + break; + } + if (feature_list) + for (i = 0; feature_list[i]; i++); + else + i = preordered; + info->indices = malloc (sizeof (guint) * ((req_feature != 0xFFFF) + i)); + i = 0; + if (req_feature != 0xFFFF) + info->indices[i++] = req_feature; + for (j = 0; j < preordered; j++) + if (pango_ot_info_find_feature (ot_info, type, features[j], + script, langsys, &index)) + info->indices[i++] = index; + if (feature_list) + for (j = 0; feature_list[j]; j++) + { + for (k = preordered + 1; k < count; k++) + if (feature_list[j] == features[k]) + break; + if (k == count + && pango_ot_info_find_feature (ot_info, type, feature_list[j], + script, langsys, &index)) + info->indices[i++] = index; + } + info->count = i; + info->ruleset = pango_ot_ruleset_new (ot_info); +#if 1 + for (i = 0; i < info->count; i++) + pango_ot_ruleset_add_feature (info->ruleset, type, info->indices[i], + PANGO_OT_ALL_GLYPHS); +#else + for (i = info->count - 1; i >= 0; i--) + pango_ot_ruleset_add_feature (info->ruleset, type, info->indices[i], + PANGO_OT_ALL_GLYPHS); +#endif +} + +GsubGposInfo * +setup_otf_spec (FontInfoPango *font_info, MFLTOtfSpec *spec) +{ + GsubGposInfo *ginfo; + + if (spec->gsub_count + spec->gpos_count == 0) + return NULL; + ginfo = mplist_get (font_info->otf_spec_cache, spec->sym); + if (ginfo) + return (ginfo->gsub.count + ginfo->gpos.count > 0 ? ginfo : NULL); + ginfo = calloc (1, sizeof (GsubGposInfo)); + mplist_push (font_info->otf_spec_cache, spec->sym, ginfo); + setup_features (PANGO_OT_TABLE_GSUB, font_info, spec, &(ginfo->gsub)); + setup_features (PANGO_OT_TABLE_GPOS, font_info, spec, &(ginfo->gpos)); + return ginfo; +} + +int +drive_otf (MFLTFont *font, MFLTOtfSpec *spec, + MFLTGlyphString *in, int from, int to, + MFLTGlyphString *out, MFLTGlyphAdjustment *adjustment) +{ + FontInfoPango *font_info = (FontInfoPango *) font; + PangoOTBuffer *buffer; + GsubGposInfo *ginfo; + PangoGlyphString *glyphs; + int i; + + buffer = pango_ot_buffer_new (font_info->pango_font); + for (i = from; i < to; i++) + pango_ot_buffer_add_glyph (buffer, in->glyphs[i].code, 0, i); + ginfo = setup_otf_spec (font_info, spec); + if (! ginfo) + goto simple_copy; + if (ginfo->gsub.count > 0) + pango_ot_ruleset_substitute (ginfo->gsub.ruleset, buffer); + if (ginfo->gpos.count > 0) + pango_ot_ruleset_position (ginfo->gpos.ruleset, buffer); + glyphs = pango_glyph_string_new (); + pango_ot_buffer_output (buffer, glyphs); + for (i = 0; i < glyphs->num_glyphs; i++) + { + PangoGlyphInfo *glyph_info = glyphs->glyphs + i; + MFLTGlyph *g; + + out->glyphs[out->used] = in->glyphs[glyphs->log_clusters[i]]; + g = out->glyphs + out->used++; + if (g->code != glyph_info->glyph) + { + g->c = 0; + g->code = glyph_info->glyph; + g->measured = 0; + } + g->xoff = glyph_info->geometry.x_offset / PANGO_SCALE_TO_26_6; + g->yoff = glyph_info->geometry.y_offset / PANGO_SCALE_TO_26_6; + g->xadv = glyph_info->geometry.width / PANGO_SCALE_TO_26_6; + g->yadv = 0; + adjustment[i].set = 0; + } + pango_ot_buffer_destroy (buffer); + pango_glyph_string_free (glyphs); + return to; + + simple_copy: + pango_ot_buffer_destroy (buffer); + for (i = from; i < to; i++) + out->glyphs[out->used++] = in->glyphs[i]; + return to; +} + + +MFLTFont * +open_font (char *fontname, char **err) +{ + FontInfoPango *font_info = NULL; + PangoFontMap *fontmap; + PangoContext *context; + PangoFontDescription *desc; + PangoFont *pango_font; + char *family; + int size; + double pango_size; + + if (parse_font_name (fontname, &family, &size, err) < 0) + return NULL; + desc = pango_font_description_new (); + pango_font_description_set_family (desc, family); + free (family); + pango_size = size * PANGO_SCALE; + pango_font_description_set_absolute_size (desc, pango_size); + + fontmap = pango_ft2_font_map_new (); + context = pango_context_new (); + pango_context_set_font_map (context, fontmap); + pango_font = pango_context_load_font (context, desc); + pango_font_description_free (desc); + if (pango_font) + { + font_info = calloc (1, sizeof (FontInfoPango)); + font_info->fontmap = fontmap; + font_info->context = context; + font_info->pango_font = PANGO_FC_FONT (pango_font); + font_info->otf_spec_cache = mplist (); + } + else + { + g_object_unref (context); + g_object_unref (fontmap); + } + return (MFLTFont *) font_info; +} + +void +close_font (MFLTFont *font) +{ + FontInfoPango *font_info = (FontInfoPango *) font; + + g_object_unref (font_info->context); + g_object_unref (font_info->fontmap); +} + +#endif + +#ifdef FLT_GUI + +int +run_flt (MText *mt, int from, int to, MFLTFont *font, char *flt_name) +{ + MDrawControl control; + + memset (&control, 0, sizeof (MDrawControl)); + control.two_dimensional = 1; + control.enable_bidi = 1; + control.anti_alias = 1; + /*control.disable_caching = 1;*/ + mtext_put_prop (mt, from, to, Mfont, font->font); + mdraw_text_extents (frame, mt, from, to, &control, NULL, NULL, NULL); + return 0; +} + +#else + +int +run_flt (MText *mt, int from, int to, MFLTFont *font, char *flt_name) +{ + static MFLT *flt = NULL; + MCharTable *coverage; + static MFLTGlyphString gstring; + + if (! flt + && ! (flt = mflt_get (flt_name))) + { + fprintf (stderr, "Invalid FLT name: %s\n", flt_name); + exit (1); + } + coverage = mflt_coverage (flt); + while (from < to) + { + int len = 0, i; + + for (; from < to; from++) + if (mchartable_lookup (coverage, mtext_ref_char (mt, from))) + { + for (i = from + 1; i < to; i++) + if (! mchartable_lookup (coverage, mtext_ref_char (mt, i))) + break; + len = i - from; + break; + } + if (len > 0) + { + if (gstring.allocated < len) + { + gstring.allocated = len * 2; + gstring.glyphs = realloc (gstring.glyphs, + sizeof (MFLTGlyph) * len * 2); + } + gstring.glyph_size = sizeof (MFLTGlyph); + for (i = 0; i < len; i++) + gstring.glyphs[i].c = mtext_ref_char (mt, from + i); + gstring.used = len; + i = mflt_run (&gstring, 0, len, font, flt); + if (i < 0) + return i; + from += len; + } + } + return to; +} #endif + int main (int argc, char **argv) { @@ -983,6 +1360,7 @@ main (int argc, char **argv) MText *mt; MFLTFont *font; int len, i, j; + unsigned char *buf; if (argc < 3) { @@ -1001,21 +1379,36 @@ main (int argc, char **argv) fprintf (stderr, "Font error: %s: %s\n", argv[1], err); exit (1); } + font->get_glyph_id = get_glyph_id; + font->get_metrics = get_metrics; + font->drive_otf = drive_otf; - mt = mconv_decode_stream (msymbol ("utf-8"), stdin); + i = 0; + buf = malloc (4096); + while ((j = fread (buf + i, 1, 4096, stdin)) == 4096) + { + i += 4096; + buf = realloc (buf, i + 4096); + } + mt = mtext_from_data (buf, i, MTEXT_FORMAT_UTF_8); len = mtext_len (mt); for (i = 0, j = mtext_character (mt, i, len, '\n'); i < len; i = j + 1, j = mtext_character (mt, i, len, '\n')) { + int to; + if (j < 0) j = len; - if (flt (mt, i, j, font, flt_name) < 0) + to = run_flt (mt, i, j, font, flt_name); + if (to < 0) { fprintf (stderr, "Error in FLT processing.\n"); exit (1); } + i = j; } m17n_object_unref (mt); + free (buf); close_font (font); M17N_FINI (); return 0;