# HG changeset patch # User Kenichi Handa # Date 1196476767 0 # Node ID 00323e98bffbe544a6ce445b70afe2b1a1f28880 # Parent d54684fee1543063ca1f532ddbf89d18862e29b4 Don't include Freetype headers. Include "ftfont.h". (struct ftfont_info) [HAVE_LIBOTF]: New members maybe_otf and otf. (ftfont_open) [HAVE_LIBOTF]: Initialize the above members. (ftfont_driver) [HAVE_LIBOTF, HAVE_M17N_FLT]: Don't set font_otf_capability and font_drive_otf, set ftfont_shape. (ftfont_list): Adjusted for the change of :otf property value. (struct MFLTFontFT) [HAVE_LIBOTF, HAVE_M17N_FLT]: New struct. (ftfont_get_glyph_id, ftfont_get_metrics, ftfont_check_otf) (adjust_anchor, ftfont_drive_otf, ftfont_shape_by_flt) (ftfont_shape) [HAVE_LIBOTF, HAVE_M17N_FLT]: New function.s (DEVICE_DELTA) [HAVE_LIBOTF, HAVE_M17N_FLT]: New macro. (otf_gstring, gstring, m17n_flt_initialized): New variables. diff -r d54684fee154 -r 00323e98bffb src/ftfont.c --- a/src/ftfont.c Sat Dec 01 02:39:01 2007 +0000 +++ b/src/ftfont.c Sat Dec 01 02:39:27 2007 +0000 @@ -24,9 +24,6 @@ #include #include -#include -#include FT_FREETYPE_H -#include FT_SIZES_H #include #include @@ -39,6 +36,7 @@ #include "coding.h" #include "fontset.h" #include "font.h" +#include "ftfont.h" /* Symbolic type of this font-driver. */ Lisp_Object Qfreetype; @@ -66,6 +64,10 @@ { struct font font; FT_Size ft_size; +#ifdef HAVE_LIBOTF + int maybe_otf; /* Flag to tell if this may be OTF or not. */ + OTF *otf; +#endif /* HAVE_LIBOTF */ }; static int ftfont_build_basic_charsets P_ ((void)); @@ -275,6 +277,7 @@ struct font_bitmap *, int)); static int ftfont_anchor_point P_ ((struct font *, unsigned, int, int *, int *)); +static Lisp_Object ftfont_shape P_ ((Lisp_Object)); struct font_driver ftfont_driver = { @@ -299,14 +302,15 @@ NULL, NULL, ftfont_anchor_point, -#ifdef HAVE_LIBOTF - font_otf_capability, - font_drive_otf, -#else + NULL, + NULL, NULL, NULL, +#ifdef HAVE_M17N_FLT + ftfont_shape +#else /* not HAVE_M17N_FLT */ NULL -#endif /* HAVE_LIBOTF */ +#endif /* not HAVE_M17N_FLT */ }; extern Lisp_Object QCname; @@ -380,11 +384,19 @@ key = XCAR (tmp), val = XCDR (tmp); if (EQ (key, QCotf)) { - script = assq_no_quit (val, Votf_script_alist); - if (CONSP (script) && SYMBOLP (XCDR (script))) - script = XCDR (script); - tmp = SYMBOL_NAME (val); - sprintf (otf_script, "otlayout:%s", (char *) SDATA (tmp)); + tmp = XCAR (val); + if (NILP (tmp)) + strcpy (otf_script, "otlayout:DFLT"); + else + { + val = assq_no_quit (tmp, Votf_script_alist); + if (CONSP (val) && SYMBOLP (XCDR (val))) + { + sprintf (otf_script, "otlayout:%s", + (char *) SDATA (SYMBOL_NAME (tmp))); + script = XCDR (val); + } + } } else if (EQ (key, QClanguage)) { @@ -723,6 +735,8 @@ if (! ftfont_info) return NULL; ftfont_info->ft_size = ft_size; + ftfont_info->maybe_otf = ft_face->face_flags & FT_FACE_FLAG_SFNT; + ftfont_info->otf = NULL; font = (struct font *) ftfont_info; font->format = ftfont_font_format (pattern); @@ -802,7 +816,13 @@ (XSAVE_VALUE (val)->integer)--; if (XSAVE_VALUE (val)->integer == 0) - FT_Done_Face (ftfont_info->ft_size->face); + { + FT_Done_Face (ftfont_info->ft_size->face); +#ifdef HAVE_LIBOTF + if (ftfont_info->otf) + OTF_close (ftfont_info->otf); +#endif + } else FT_Done_Size (ftfont_info->ft_size); @@ -957,6 +977,524 @@ return 0; } +#ifdef HAVE_LIBOTF +#ifdef HAVE_M17N_FLT + +struct MFLTFontFT +{ + MFLTFont flt_font; + struct font *font; + FT_Face ft_face; + OTF *otf; +}; + +static int +ftfont_get_glyph_id (font, gstring, from, to) + MFLTFont *font; + MFLTGlyphString *gstring; + int from, to; +{ + struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font; + FT_Face ft_face = flt_font_ft->ft_face; + MFLTGlyph *g; + + for (g = gstring->glyphs + from; from < to; g++, from++) + if (! g->encoded) + { + FT_UInt code = FT_Get_Char_Index (ft_face, g->code); + + g->code = code > 0 ? code : FONT_INVALID_CODE; + g->encoded = 1; + } + return 0; +} + +static int +ftfont_get_metrics (font, gstring, from, to) + MFLTFont *font; + MFLTGlyphString *gstring; + int from, to; +{ + struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font; + FT_Face ft_face = flt_font_ft->ft_face; + MFLTGlyph *g; + + for (g = gstring->glyphs + from; from < to; g++, from++) + if (! g->measured) + { + if (g->code != FONT_INVALID_CODE) + { + FT_Glyph_Metrics *m; + + if (FT_Load_Glyph (ft_face, g->code, FT_LOAD_DEFAULT) != 0) + abort (); + m = &ft_face->glyph->metrics; + + g->lbearing = m->horiBearingX; + g->rbearing = m->horiBearingX + m->width; + g->ascent = m->horiBearingY; + g->descent = m->height - m->horiBearingY; + g->xadv = m->horiAdvance; + } + else + { + g->lbearing = 0; + g->rbearing = g->xadv = flt_font_ft->font->font.space_width << 6; + g->ascent = flt_font_ft->font->ascent << 6; + g->descent = flt_font_ft->font->descent << 6; + } + g->yadv = 0; + g->measured = 1; + } + return 0; +} + +static int +ftfont_check_otf (MFLTFont *font, MFLTOtfSpec *spec) +{ + struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font; + OTF *otf = flt_font_ft->otf; + OTF_Tag *tags; + int i, n, negative; + + for (i = 0; i < 2; i++) + { + if (! spec->features[i]) + continue; + for (n = 0; spec->features[i][n]; n++); + tags = alloca (sizeof (OTF_Tag) * n); + for (n = 0, negative = 0; spec->features[i][n]; n++) + { + if (spec->features[i][n] == 0xFFFFFFFF) + negative = 1; + else if (negative) + tags[n - 1] = spec->features[i][n] | 0x80000000; + else + tags[n] = spec->features[i][n]; + } + if (n - negative > 0 + && OTF_check_features (otf, i == 0, spec->script, spec->langsys, + tags, n - negative) != 1) + return 0; + } + return 1; +} + +#define DEVICE_DELTA(table, size) \ + (((size) >= (table).StartSize && (size) <= (table).EndSize) \ + ? (table).DeltaValue[(size) - (table).StartSize] << 6 \ + : 0) + +static void +adjust_anchor (FT_Face ft_face, OTF_Anchor *anchor, + unsigned code, int x_ppem, int y_ppem, int *x, int *y) +{ + if (anchor->AnchorFormat == 2) + { + FT_Outline *outline; + int ap = anchor->f.f1.AnchorPoint; + + FT_Load_Glyph (ft_face, (FT_UInt) code, FT_LOAD_MONOCHROME); + outline = &ft_face->glyph->outline; + if (ap < outline->n_points) + { + *x = outline->points[ap].x << 6; + *y = outline->points[ap].y << 6; + } + } + else if (anchor->AnchorFormat == 3) + { + if (anchor->f.f2.XDeviceTable.offset) + *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, x_ppem); + if (anchor->f.f2.YDeviceTable.offset) + *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, y_ppem); + } +} + +static OTF_GlyphString otf_gstring; + +static int +ftfont_drive_otf (font, spec, in, from, to, out, adjustment) + MFLTFont *font; + MFLTOtfSpec *spec; + MFLTGlyphString *in; + int from, to; + MFLTGlyphString *out; + MFLTGlyphAdjustment *adjustment; +{ + struct MFLTFontFT *flt_font_ft = (struct MFLTFontFT *) font; + FT_Face ft_face = flt_font_ft->ft_face; + OTF *otf = flt_font_ft->otf; + int len = to - from; + int i, j, gidx; + OTF_Glyph *otfg; + char script[5], *langsys = NULL; + char *gsub_features = NULL, *gpos_features = NULL; + + if (len == 0) + return from; + OTF_tag_name (spec->script, script); + if (spec->langsys) + { + langsys = alloca (5); + OTF_tag_name (spec->langsys, langsys); + } + for (i = 0; i < 2; i++) + { + char *p; + + if (spec->features[i] && spec->features[i][1] != 0xFFFFFFFF) + { + for (j = 0; spec->features[i][j]; j++); + if (i == 0) + p = gsub_features = alloca (6 * j); + else + p = gpos_features = alloca (6 * j); + for (j = 0; spec->features[i][j]; j++) + { + if (spec->features[i][j] == 0xFFFFFFFF) + *p++ = '*', *p++ = ','; + else + { + OTF_tag_name (spec->features[i][j], p); + p[4] = ','; + p += 5; + } + } + *--p = '\0'; + } + } + + if (otf_gstring.size == 0) + { + otf_gstring.glyphs = (OTF_Glyph *) malloc (sizeof (OTF_Glyph) * len); + otf_gstring.size = len; + } + else if (otf_gstring.size < len) + { + otf_gstring.glyphs = (OTF_Glyph *) realloc (otf_gstring.glyphs, + sizeof (OTF_Glyph) * len); + otf_gstring.size = len; + } + otf_gstring.used = len; + memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * len); + for (i = 0; i < len; i++) + { + otf_gstring.glyphs[i].c = in->glyphs[from + i].c; + otf_gstring.glyphs[i].glyph_id = in->glyphs[from + i].code; + } + + OTF_drive_gdef (otf, &otf_gstring); + gidx = out->used; + + if (gsub_features) + { + if (OTF_drive_gsub (otf, &otf_gstring, script, langsys, gsub_features) + < 0) + goto simple_copy; + if (out->allocated < out->used + otf_gstring.used) + return -2; + for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++, otfg++) + { + MFLTGlyph *g = out->glyphs + out->used; + int j; + + *g = in->glyphs[from + otfg->f.index.from]; + g->c = 0; + for (j = from + otfg->f.index.from; j <= from + otfg->f.index.to; j++) + if (in->glyphs[j].code == otfg->glyph_id) + { + g->c = in->glyphs[j].c; + break; + } + if (g->code != otfg->glyph_id) + { + g->code = otfg->glyph_id; + g->measured = 0; + } + out->used++; + } + } + else + { + if (out->allocated < out->used + len) + return -2; + for (i = 0; i < len; i++) + out->glyphs[out->used++] = in->glyphs[from + i]; + } + + if (gpos_features) + { + MFLTGlyph *base = NULL, *mark = NULL, *g; + int x_ppem, y_ppem, x_scale, y_scale; + + if (OTF_drive_gpos (otf, &otf_gstring, script, langsys, gpos_features) + < 0) + return to; + + x_ppem = ft_face->size->metrics.x_ppem; + y_ppem = ft_face->size->metrics.y_ppem; + x_scale = ft_face->size->metrics.x_scale; + y_scale = ft_face->size->metrics.y_scale; + + for (i = 0, otfg = otf_gstring.glyphs, g = out->glyphs + gidx; + i < otf_gstring.used; i++, otfg++, g++) + { + MFLTGlyph *prev; + + if (! otfg->glyph_id) + continue; + switch (otfg->positioning_type) + { + case 0: + break; + case 1: /* Single */ + case 2: /* Pair */ + { + int format = otfg->f.f1.format; + + if (format & OTF_XPlacement) + adjustment[i].xoff + = otfg->f.f1.value->XPlacement * x_scale / 0x10000; + if (format & OTF_XPlaDevice) + adjustment[i].xoff + += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, x_ppem); + if (format & OTF_YPlacement) + adjustment[i].yoff + = - (otfg->f.f1.value->YPlacement * y_scale / 0x10000); + if (format & OTF_YPlaDevice) + adjustment[i].yoff + -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, y_ppem); + if (format & OTF_XAdvance) + adjustment[i].xadv + += otfg->f.f1.value->XAdvance * x_scale / 0x10000; + if (format & OTF_XAdvDevice) + adjustment[i].xadv + += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, x_ppem); + if (format & OTF_YAdvance) + adjustment[i].yadv + += otfg->f.f1.value->YAdvance * y_scale / 0x10000; + if (format & OTF_YAdvDevice) + adjustment[i].yadv + += DEVICE_DELTA (otfg->f.f1.value->YAdvDevice, y_ppem); + adjustment[i].set = 1; + } + break; + case 3: /* Cursive */ + /* Not yet supported. */ + break; + case 4: /* Mark-to-Base */ + case 5: /* Mark-to-Ligature */ + if (! base) + break; + prev = base; + goto label_adjust_anchor; + default: /* i.e. case 6 Mark-to-Mark */ + if (! mark) + break; + prev = mark; + + label_adjust_anchor: + { + int base_x, base_y, mark_x, mark_y; + int this_from, this_to; + + base_x = otfg->f.f4.base_anchor->XCoordinate * x_scale / 0x10000; + base_y = otfg->f.f4.base_anchor->YCoordinate * y_scale / 0x10000; + mark_x = otfg->f.f4.mark_anchor->XCoordinate * x_scale / 0x10000; + mark_y = otfg->f.f4.mark_anchor->YCoordinate * y_scale / 0x10000;; + + if (otfg->f.f4.base_anchor->AnchorFormat != 1) + adjust_anchor (ft_face, otfg->f.f4.base_anchor, + prev->code, x_ppem, y_ppem, &base_x, &base_y); + if (otfg->f.f4.mark_anchor->AnchorFormat != 1) + adjust_anchor (ft_face, otfg->f.f4.mark_anchor, g->code, + x_ppem, y_ppem, &mark_x, &mark_y); + adjustment[i].xoff = (base_x - mark_x); + adjustment[i].yoff = - (base_y - mark_y); + adjustment[i].back = (g - prev); + adjustment[i].xadv = 0; + adjustment[i].advance_is_absolute = 1; + adjustment[i].set = 1; + this_from = g->from; + this_to = g->to; + for (j = 0; prev + j < g; j++) + { + if (this_from > prev[j].from) + this_from = prev[j].from; + if (this_to < prev[j].to) + this_to = prev[j].to; + } + for (; prev <= g; prev++) + { + prev->from = this_from; + prev->to = this_to; + } + } + } + if (otfg->GlyphClass == OTF_GlyphClass0) + base = mark = g; + else if (otfg->GlyphClass == OTF_GlyphClassMark) + mark = g; + else + base = g; + } + } + return to; + + simple_copy: + if (out->allocated < out->used + len) + return -2; + font->get_metrics (font, in, from, to); + memcpy (out->glyphs + out->used, in->glyphs + from, + sizeof (MFLTGlyph) * len); + out->used += len; + return to; +} + +static MFLTGlyphString gstring; + +static int m17n_flt_initialized; + +extern Lisp_Object QCfamily; + +Lisp_Object +ftfont_shape_by_flt (lgstring, font, ft_face, otf) + Lisp_Object lgstring; + struct font *font; + FT_Face ft_face; + OTF *otf; +{ + EMACS_UINT len = LGSTRING_LENGTH (lgstring); + EMACS_UINT i; + struct MFLTFontFT flt_font_ft; + + if (! m17n_flt_initialized) + { + M17N_INIT (); + m17n_flt_initialized = 1; + } + + for (i = 0; i < len; i++) + if (NILP (LGSTRING_GLYPH (lgstring, i))) + break; + len = i; + + if (gstring.allocated == 0) + { + gstring.allocated = len * 2; + gstring.glyph_size = sizeof (MFLTGlyph); + gstring.glyphs = malloc (sizeof (MFLTGlyph) * gstring.allocated); + } + else if (gstring.allocated < len * 2) + { + gstring.allocated = len * 2; + gstring.glyphs = realloc (gstring.glyphs, + sizeof (MFLTGlyph) * gstring.allocated); + } + for (i = 0; i < len; i++) + gstring.glyphs[i].c = LGLYPH_CHAR (LGSTRING_GLYPH (lgstring, i)); + gstring.used = len; + gstring.r2l = 0; + + { + Lisp_Object family = Ffont_get (LGSTRING_FONT (lgstring), QCfamily); + + if (NILP (family)) + flt_font_ft.flt_font.family = Mnil; + else + flt_font_ft.flt_font.family = msymbol (SDATA (SYMBOL_NAME (family))); + } + flt_font_ft.flt_font.x_ppem = ft_face->size->metrics.x_ppem; + flt_font_ft.flt_font.y_ppem = ft_face->size->metrics.y_ppem; + flt_font_ft.flt_font.get_glyph_id = ftfont_get_glyph_id; + flt_font_ft.flt_font.get_metrics = ftfont_get_metrics; + flt_font_ft.flt_font.check_otf = ftfont_check_otf; + flt_font_ft.flt_font.drive_otf = ftfont_drive_otf; + flt_font_ft.flt_font.internal = NULL; + flt_font_ft.font = font; + flt_font_ft.ft_face = ft_face; + flt_font_ft.otf = otf; + for (i = 0; i < 3; i++) + { + int result = mflt_run (&gstring, 0, len, &flt_font_ft.flt_font, NULL); + if (result != -2) + break; + gstring.allocated += gstring.allocated; + gstring.glyphs = realloc (gstring.glyphs, + sizeof (MFLTGlyph) * gstring.allocated); + } + if (gstring.used > LGSTRING_LENGTH (lgstring)) + return Qnil; + for (i = 0; i < gstring.used; i++) + { + MFLTGlyph *g = gstring.glyphs + i; + + g->from = LGLYPH_FROM (LGSTRING_GLYPH (lgstring, g->from)); + g->to = LGLYPH_TO (LGSTRING_GLYPH (lgstring, g->to)); + } + + for (i = 0; i < gstring.used; i++) + { + Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i); + MFLTGlyph *g = gstring.glyphs + i; + + LGLYPH_SET_FROM (lglyph, g->from); + LGLYPH_SET_TO (lglyph, g->to); + LGLYPH_SET_CHAR (lglyph, g->c); + LGLYPH_SET_CODE (lglyph, g->code); + LGLYPH_SET_WIDTH (lglyph, g->xadv >> 6); + LGLYPH_SET_LBEARING (lglyph, g->lbearing >> 6); + LGLYPH_SET_RBEARING (lglyph, g->rbearing >> 6); + LGLYPH_SET_ASCENT (lglyph, g->ascent >> 6); + LGLYPH_SET_DESCENT (lglyph, g->descent >> 6); + if (g->adjusted) + { + Lisp_Object vec; + + vec = Fmake_vector (make_number (3), Qnil); + ASET (vec, 0, make_number (g->xoff >> 6)); + ASET (vec, 1, make_number (g->yoff >> 6)); + ASET (vec, 2, make_number (g->xadv >> 6)); + LGLYPH_SET_ADJUSTMENT (lglyph, vec); + } + } + return make_number (i); +} + +Lisp_Object +ftfont_shape (lgstring) + Lisp_Object lgstring; +{ + struct font *font; + struct ftfont_info *ftfont_info; + + CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring), font); + ftfont_info = (struct ftfont_info *) font; + if (! ftfont_info->maybe_otf) + return 0; + if (! ftfont_info->otf) + { + OTF *otf = OTF_open_ft_face (ftfont_info->ft_size->face); + + if (! otf || OTF_get_table (otf, "head") < 0) + { + if (otf) + OTF_close (otf); + ftfont_info->maybe_otf = 0; + return 0; + } + + ftfont_info->otf = otf; + } + + return ftfont_shape_by_flt (lgstring, font, ftfont_info->ft_size->face, + ftfont_info->otf); +} + +#endif /* HAVE_M17N_FLT */ +#endif /* HAVE_LIBOTF */ + Lisp_Object ftfont_font_format (FcPattern *pattern) {