5 #include FT_TRUETYPE_TABLES_H
6 #include <fontconfig/fontconfig.h>
7 #include <fontconfig/fcfreetype.h>
12 #define PROGNAME "flt-gui"
14 #elif defined (FLT_OTF)
18 #define PROGNAME "flt-otf"
20 #elif defined (FLT_HB)
24 #define PROGNAME "flt-hb"
26 #else /* (defined (FLT_PANGO)) */
29 #define PANGO_ENABLE_ENGINE
30 #define PANGO_ENABLE_BACKEND
31 #include <pango/pangcairo.h>
32 #include <pango/pango-ot.h>
36 #include <m17n-misc.h>
38 static FT_Library ft_library;
41 parse_font_name (char *fontname, char **family, int *size, char **err)
47 pat = FcNameParse ((FcChar8 *) fontname);
50 *err = "invalid name format";
53 if (FcPatternGetString (pat, FC_FAMILY, 0, &fam) != FcResultMatch)
55 FcPatternDestroy (pat);
56 *err = "no family name";
59 if (FcPatternGetDouble (pat, FC_PIXEL_SIZE, 0, &pixelsize) != FcResultMatch)
61 *family = strdup ((char *) fam);
63 FcPatternDestroy (pat);
68 new_face (char *fontname, char **err)
78 if (parse_font_name (fontname, (char **) &fam, &size, err) < 0)
81 pat = FcPatternBuild (0,
82 FC_FAMILY, FcTypeString, fam,
83 FC_SCALABLE, FcTypeBool, FcTrue,
86 os = FcObjectSetBuild (FC_FILE, NULL);
87 fs = FcFontList (NULL, pat, os);
90 *err = "no matching font";
93 FcPatternGetString (fs->fonts[0], FC_FILE, 0, &file);
95 if (FT_New_Face (ft_library, (char *) file, 0, &face))
97 FcFontSetDestroy (fs);
98 FcObjectSetDestroy (os);
99 FcPatternDestroy (pat);
100 *err = "font open fail";
103 FcFontSetDestroy (fs);
104 FcObjectSetDestroy (os);
105 FcPatternDestroy (pat);
106 if (FT_Set_Pixel_Sizes (face, pixelsize, pixelsize))
108 *err = "set pixelsize fail";
117 typedef struct _MFLTFont MFLTFont;
122 void (*get_glyph_id) (void);
123 void (*get_metrics) (void);
124 void (*suitable_p) (void);
125 void (*drive_otf) (void);
130 void get_glyph_id (void) {}
131 void get_metrics (void) {}
132 void suitable_p (void) {}
133 void drive_otf (void) {}
138 open_font (char *fontname, char **err)
140 FT_Face ft_face = new_face (fontname, err);
150 fontset = mfontset ("generic");
151 mface_put_prop (face, Mfontset, fontset);
152 mplist_add (plist, Mface, face);
153 mplist_add (plist, Mdevice, Mnil);
154 frame = mframe (plist);
155 m17n_object_unref (plist);
156 m17n_object_unref (face);
157 m17n_object_unref (fontset);
159 font = calloc (1, sizeof (MFLTFont));
160 font->font = mfont_encapsulate (frame, Mfreetype, ft_face);
161 font->face = ft_face;
166 close_font (MFLTFont *font)
168 FT_Done_Face (font->face);
170 m17n_object_unref (frame);
173 #elif defined (FLT_OTF) || defined (FLT_HB)
181 get_glyph_id (MFLTFont *font, MFLTGlyphString *gstring, int from, int to)
183 FT_Face face = ((FontInfo *) font)->face;
185 for (; from < to; from++)
187 MFLTGlyph *g = gstring->glyphs + from;
190 && ! (g->code = FT_Get_Char_Index (face, g->code)))
198 get_metrics (MFLTFont *font, MFLTGlyphString *gstring, int from, int to)
200 FT_Face face = ((FontInfo *) font)->face;
202 for (; from < to; from++)
204 MFLTGlyph *g = gstring->glyphs + from;
208 FT_Glyph_Metrics *metrics;
210 if (FT_Load_Glyph (face, g->code, FT_LOAD_DEFAULT))
212 metrics = &face->glyph->metrics;
213 g->lbearing = metrics->horiBearingX;
214 g->rbearing = metrics->horiBearingX + metrics->width;
215 g->xadv = metrics->horiAdvance;
216 g->yadv = metrics->vertAdvance;
217 g->ascent = metrics->horiBearingY;
218 g->descent = metrics->height - metrics->horiBearingY;
233 #define DEVICE_DELTA(table, size) \
234 (((size) >= (table).StartSize && (size) <= (table).EndSize) \
235 ? ((table).DeltaValue[(size) - (table).StartSize] << 6) \
239 adjust_anchor (OTF_Anchor *anchor, FT_Face face,
240 unsigned code, unsigned x_ppem, unsigned y_ppem, int *x, int *y)
242 if (anchor->AnchorFormat == 2)
245 int ap = anchor->f.f1.AnchorPoint;
247 FT_Load_Glyph (face, (FT_UInt) code, FT_LOAD_MONOCHROME);
248 outline = &face->glyph->outline;
249 if (ap < outline->n_points)
251 *x = outline->points[ap].x;
252 *y = outline->points[ap].y;
255 else if (anchor->AnchorFormat == 3)
257 if (anchor->f.f2.XDeviceTable.offset)
258 *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, x_ppem);
259 if (anchor->f.f2.YDeviceTable.offset)
260 *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, y_ppem);
265 tag_name (char *str, unsigned tag)
268 *str++ = (tag >> 16) & 0xFF;
269 *str++ = (tag >> 8) & 0xFF;
275 encode_features (char *str, int count, unsigned *features)
280 for (i = 0; i < count; i++)
282 unsigned tag = features[i];
292 str = tag_name (str, tag);
304 static OTF_GlyphString otf_gstring;
307 setup_otf_gstring (int size)
309 if (otf_gstring.size == 0)
311 otf_gstring.glyphs = (OTF_Glyph *) xmalloc (sizeof (OTF_Glyph) * size);
312 otf_gstring.size = size;
314 else if (otf_gstring.size < size)
316 otf_gstring.glyphs = xrealloc (otf_gstring.glyphs,
317 sizeof (OTF_Glyph) * size);
318 otf_gstring.size = size;
320 otf_gstring.used = size;
321 memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * size);
325 drive_otf (MFLTFont *font, MFLTOtfSpec *spec,
326 MFLTGlyphString *in, int from, int to,
327 MFLTGlyphString *out, MFLTGlyphAdjustment *adjustment)
329 OTF *otf = ((FontInfoOTF *) font)->otf;
333 char script[5], *langsys = NULL;
334 char *gsub_features = NULL, *gpos_features = NULL;
339 OTF_tag_name (spec->script, script);
342 langsys = alloca (5);
343 OTF_tag_name (spec->langsys, langsys);
345 for (i = 0; i < 2; i++)
349 if (spec->features[i] && spec->features[i][1] != 0xFFFFFFFF)
351 for (j = 0; spec->features[i][j]; j++);
353 p = gsub_features = alloca (6 * j);
355 p = gpos_features = alloca (6 * j);
356 for (j = 0; spec->features[i][j]; j++)
358 if (spec->features[i][j] == 0xFFFFFFFF)
359 *p++ = '*', *p++ = ',';
362 OTF_tag_name (spec->features[i][j], p);
371 setup_otf_gstring (len);
372 for (i = 0; i < len; i++)
374 otf_gstring.glyphs[i].c = in->glyphs[from + i].c;
375 otf_gstring.glyphs[i].glyph_id = in->glyphs[from + i].code;
378 OTF_drive_gdef (otf, &otf_gstring);
383 if (OTF_drive_gsub (otf, &otf_gstring, script, langsys, gsub_features)
386 if (out->allocated < out->used + otf_gstring.used)
388 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++, otfg++)
390 MFLTGlyph *g = out->glyphs + out->used;
393 *g = in->glyphs[from + otfg->f.index.from];
395 for (j = from + otfg->f.index.from; j <= from + otfg->f.index.to; j++)
396 if (in->glyphs[j].code == otfg->glyph_id)
398 g->c = in->glyphs[j].c;
401 if (g->code != otfg->glyph_id)
403 g->code = otfg->glyph_id;
411 if (out->allocated < out->used + len)
413 for (i = 0; i < len; i++)
414 out->glyphs[out->used++] = in->glyphs[from + i];
420 MFLTGlyph *base = NULL, *mark = NULL, *g;
421 int x_ppem, y_ppem, x_scale, y_scale;
423 if (OTF_drive_gpos (otf, &otf_gstring, script, langsys, gpos_features)
427 face = ((FontInfo *) font)->face;
428 x_ppem = face->size->metrics.x_ppem;
429 y_ppem = face->size->metrics.y_ppem;
430 x_scale = face->size->metrics.x_scale;
431 y_scale = face->size->metrics.y_scale;
433 for (i = 0, otfg = otf_gstring.glyphs, g = out->glyphs + gidx;
434 i < otf_gstring.used; i++, otfg++, g++)
438 if (! otfg->glyph_id)
440 switch (otfg->positioning_type)
446 int format = otfg->f.f1.format;
448 if (format & OTF_XPlacement)
450 = otfg->f.f1.value->XPlacement * x_scale / 0x10000;
451 if (format & OTF_XPlaDevice)
453 += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, x_ppem);
454 if (format & OTF_YPlacement)
456 = - (otfg->f.f1.value->YPlacement * y_scale / 0x10000);
457 if (format & OTF_YPlaDevice)
459 -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, y_ppem);
460 if (format & OTF_XAdvance)
462 += otfg->f.f1.value->XAdvance * x_scale / 0x10000;
463 if (format & OTF_XAdvDevice)
465 += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, x_ppem);
466 if (format & OTF_YAdvance)
468 += otfg->f.f1.value->YAdvance * y_scale / 0x10000;
469 if (format & OTF_YAdvDevice)
471 += DEVICE_DELTA (otfg->f.f1.value->YAdvDevice, y_ppem);
472 adjustment[i].set = 1;
476 /* Not yet supported. */
482 goto label_adjust_anchor;
483 default: /* i.e. case 6 */
490 int base_x, base_y, mark_x, mark_y;
492 base_x = otfg->f.f4.base_anchor->XCoordinate * x_scale / 0x10000;
493 base_y = otfg->f.f4.base_anchor->YCoordinate * y_scale / 0x10000;
494 mark_x = otfg->f.f4.mark_anchor->XCoordinate * x_scale / 0x10000;
495 mark_y = otfg->f.f4.mark_anchor->YCoordinate * y_scale / 0x10000;;
497 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
498 adjust_anchor (otfg->f.f4.base_anchor, face, prev->code,
499 x_ppem, y_ppem, &base_x, &base_y);
500 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
501 adjust_anchor (otfg->f.f4.mark_anchor, face, g->code,
502 x_ppem, y_ppem, &mark_x, &mark_y);
503 adjustment[i].xoff = (base_x - mark_x);
504 adjustment[i].yoff = - (base_y - mark_y);
505 adjustment[i].back = (g - prev);
506 adjustment[i].set = 1;
509 if (otfg->GlyphClass == OTF_GlyphClass0)
511 else if (otfg->GlyphClass == OTF_GlyphClassMark)
517 free (otf_gstring.glyphs);
521 font->get_metrics (font, in, from, to);
522 for (i = 0; i < len; i++)
524 MFLTGlyph *g = in->glyphs + (from + i);
526 out->glyphs[out->used++] = *g;
528 if (otf_gstring.glyphs)
529 free (otf_gstring.glyphs);
534 open_font (char *fontname, char **err)
536 FT_Face face = new_face (fontname, err);
537 FontInfoOTF *font_info;
541 font_info = malloc (sizeof (FontInfoOTF));
542 font_info->face = face;
543 font_info->otf = OTF_open_ft_face (face);
544 if (OTF_get_table (font_info->otf, "head") < 0)
546 OTF_close (font_info->otf);
547 FT_Done_Face (font_info->face);
551 return ((MFLTFont *) font_info);
555 close_font (MFLTFont *font)
557 FontInfoOTF *font_info = (FontInfoOTF *) font;
559 OTF_close (font_info->otf);
560 FT_Done_Face (font_info->face);
580 HB_StreamRec gdef_stream;
584 MPlist *otf_spec_cache;
588 convertStringToGlyphIndices (HB_Font font, const HB_UChar16 *string,
589 hb_uint32 length, HB_Glyph *glyphs,
590 hb_uint32 *numGlyphs, HB_Bool rightToLeft)
596 getGlyphAdvances (HB_Font font, const HB_Glyph *glyphs, hb_uint32 numGlyphs,
597 HB_Fixed *advances, int flags /*HB_ShaperFlag*/)
601 for (i = 0; i < numGlyphs; i++)
606 canRender (HB_Font font, const HB_UChar16 *string, hb_uint32 length)
612 getPointInOutline (HB_Font font, HB_Glyph glyph, int flags /*HB_ShaperFlag*/,
613 hb_uint32 point, HB_Fixed *xpos, HB_Fixed *ypos,
616 FT_Face face = font->faceData;
619 if ((error = (HB_Error) FT_Load_Glyph (face, glyph, flags)))
621 if (face->glyph->format != ft_glyph_format_outline)
622 return (HB_Error) HB_Err_Invalid_GPOS_SubTable;
623 *nPoints = face->glyph->outline.n_points;
626 if (point > *nPoints)
627 return (HB_Error) HB_Err_Invalid_GPOS_SubTable;
629 *xpos = face->glyph->outline.points[point].x;
630 *ypos = face->glyph->outline.points[point].y;
636 getGlyphMetrics (HB_Font font, HB_Glyph glyph, HB_GlyphMetrics *metrics)
641 getFontMetric (HB_Font font, HB_FontMetric metric)
646 #define MAKE_TAG(name) ((((FT_ULong) (name)[0]) << 24) \
647 | (((FT_ULong) (name)[1]) << 16) \
648 | (((FT_ULong) (name)[2]) << 8) \
652 new_stream (FT_Face face, char *tagname, HB_Stream stream)
654 FT_ULong tag = MAKE_TAG (tagname);
658 if (! FT_IS_SFNT (face))
659 return HB_Err_Invalid_Argument;
661 if (FT_Load_Sfnt_Table (face, tag, 0, NULL, &len))
662 return HB_Err_Table_Missing;
665 return HB_Err_Out_Of_Memory;
666 if (FT_Load_Sfnt_Table (face, tag, 0, buf, &len))
669 return HB_Err_Table_Missing;
671 stream->base = (HB_Byte *) buf;
674 stream->cursor = NULL;
680 load_gdef (FontInfoHB *font_info)
684 if (! font_info->gdef_stream.base)
686 err = new_stream ((FT_Face) font_info->hb_font.faceData, "GDEF",
687 &font_info->gdef_stream);
688 if (err != HB_Err_Ok)
691 return HB_Load_GDEF_Table (&font_info->gdef_stream, &font_info->gdef);
695 load_gsub (FontInfoHB *font_info)
699 HB_LookupList *lookup_list;
702 if (! font_info->gdef)
704 if ((err = load_gdef (font_info)) != HB_Err_Ok)
707 err = new_stream ((FT_Face) font_info->hb_font.faceData, "GSUB", &stream);
708 if (err != HB_Err_Ok)
710 err = HB_Load_GSUB_Table (&stream, &font_info->gsub,
711 font_info->gdef, &font_info->gdef_stream);
713 lookup_list = &font_info->gsub->LookupList;
714 for (i = 0; i < lookup_list->LookupCount; i++)
715 lookup_list->Properties[i] = HB_GLYPH_PROPERTIES_UNKNOWN;
720 load_gpos (FontInfoHB *font_info)
724 HB_LookupList *lookup_list;
727 if (! font_info->gdef)
729 if ((err = load_gdef (font_info)) != HB_Err_Ok)
732 err = new_stream ((FT_Face) font_info->hb_font.faceData, "GPOS", &stream);
733 if (err != HB_Err_Ok)
735 err = HB_Load_GPOS_Table (&stream, &font_info->gpos,
736 font_info->gdef, &font_info->gdef_stream);
738 lookup_list = &font_info->gpos->LookupList;
739 for (i = 0; i < lookup_list->LookupCount; i++)
740 lookup_list->Properties[i] = HB_GLYPH_PROPERTIES_UNKNOWN;
744 const HB_FontClass hb_fontClass = {
745 convertStringToGlyphIndices, getGlyphAdvances, canRender,
746 getPointInOutline, getGlyphMetrics, getFontMetric
750 setup_features (int gsubp, FontInfoHB *font_info, MFLTOtfSpec *spec,
753 int count, preordered;
754 unsigned int *features;
755 FT_UShort script, langsys;
756 FT_UShort req_feature, index;
757 FT_UInt *feature_list;
762 if (! font_info->gsub)
764 if (load_gsub (font_info) != HB_Err_Ok)
767 if (HB_GSUB_Select_Script (font_info->gsub, spec->script, &script)
772 if (HB_GSUB_Select_Language (font_info->gsub, spec->langsys,
773 script, &langsys, &req_feature)
778 langsys = req_feature = 0xFFFF;
779 count = spec->gsub_count;
780 features = spec->gsub;
784 if (! font_info->gpos)
786 if (load_gpos (font_info) != HB_Err_Ok)
789 if (HB_GPOS_Select_Script (font_info->gpos, spec->script, &script)
794 if (HB_GPOS_Select_Language (font_info->gpos, spec->langsys,
795 script, &langsys, &req_feature)
800 langsys = req_feature = 0xFFFF;
801 count = spec->gpos_count;
802 features = spec->gpos;
805 for (preordered = 0; preordered < count; preordered++)
806 if (features[preordered] == 0)
808 if ((gsubp ? HB_GSUB_Query_Features (font_info->gsub, script, langsys,
810 : HB_GPOS_Query_Features (font_info->gpos, script, langsys,
817 for (i = 0; feature_list[i]; i++);
820 info->indices = malloc (sizeof (FT_UShort) * ((req_feature != 0xFFFF) + i));
822 if (req_feature != 0xFFFF)
823 info->indices[i++] = req_feature;
824 for (j = 0; j < preordered; j++)
825 if ((gsubp ? HB_GSUB_Select_Feature (font_info->gsub, features[j],
826 script, langsys, &index)
827 : HB_GPOS_Select_Feature (font_info->gpos, features[j],
828 script, langsys, &index))
830 info->indices[i++] = index;
832 for (j = 0; feature_list[j]; j++)
834 for (k = preordered + 1; k < count; k++)
835 if (feature_list[j] == features[k])
839 ? HB_GSUB_Select_Feature (font_info->gsub, feature_list[j],
840 script, langsys, &index)
841 : HB_GPOS_Select_Feature (font_info->gpos, feature_list[j],
842 script, langsys, &index))
844 info->indices[i++] = index;
850 setup_otf_spec (MFLTFont *font, MFLTOtfSpec *spec)
852 FontInfoHB *font_info = (FontInfoHB *) font;
855 if (spec->gsub_count + spec->gpos_count == 0)
857 ginfo = mplist_get (font_info->otf_spec_cache, spec->sym);
859 return (ginfo->gsub.count + ginfo->gpos.count > 0 ? ginfo : NULL);
860 ginfo = calloc (1, sizeof (GsubGposInfo));
861 mplist_push (font_info->otf_spec_cache, spec->sym, ginfo);
862 setup_features (1, font_info, spec, &(ginfo->gsub));
863 setup_features (0, font_info, spec, &(ginfo->gpos));
868 drive_otf (MFLTFont *font, MFLTOtfSpec *spec,
869 MFLTGlyphString *in, int from, int to,
870 MFLTGlyphString *out, MFLTGlyphAdjustment *adjustment)
872 FontInfoHB *font_info = (FontInfoHB *) font;
877 HB_UShort *apply_order_save;
878 HB_UShort apply_count_save;
879 int gpos_applied = 0;
886 if (hb_buffer_new (&buf) != FT_Err_Ok)
888 for (i = from; i < to; i++)
890 if (hb_buffer_add_glyph (buf, in->glyphs[i].code, 0, i) != FT_Err_Ok)
893 ginfo = setup_otf_spec (font, spec);
896 if (ginfo->gsub.count > 0)
898 if (! font_info->gdef
899 && load_gdef (font_info) != HB_Err_Ok)
901 apply_order_save = font_info->gsub->FeatureList.ApplyOrder;
902 apply_count_save = font_info->gsub->FeatureList.ApplyCount;
903 font_info->gsub->FeatureList.ApplyOrder = ginfo->gsub.indices;
904 font_info->gsub->FeatureList.ApplyCount = ginfo->gsub.count;
905 err = HB_GSUB_Apply_String (font_info->gsub, buf);
906 font_info->gsub->FeatureList.ApplyOrder = apply_order_save;
907 font_info->gsub->FeatureList.ApplyCount = apply_count_save;
908 if (err != HB_Err_Ok && err != HB_Err_Not_Covered)
910 if (out->used + buf->in_length > out->allocated)
914 if (ginfo->gpos.count > 0
915 && (font_info->gpos || load_gpos (font_info) == HB_Err_Ok))
917 apply_order_save = font_info->gpos->FeatureList.ApplyOrder;
918 apply_count_save = font_info->gpos->FeatureList.ApplyCount;
919 font_info->gpos->FeatureList.ApplyOrder = ginfo->gpos.indices;
920 font_info->gpos->FeatureList.ApplyCount = ginfo->gpos.count;
921 err = HB_GPOS_Apply_String (&font_info->hb_font, font_info->gpos,
922 FT_LOAD_DEFAULT, buf, FALSE, FALSE);
923 font_info->gpos->FeatureList.ApplyOrder = apply_order_save;
924 font_info->gpos->FeatureList.ApplyCount = apply_count_save;
925 if (err == HB_Err_Ok)
929 for (i = 0; i < buf->in_length; i++)
931 HB_GlyphItem hg = buf->in_string + i;
932 HB_Position pos = buf->positions + i;
935 out->glyphs[out->used] = in->glyphs[hg->cluster];
936 g = out->glyphs + out->used++;
937 if (g->code != hg->gindex)
940 g->code = hg->gindex;
943 adjustment[i].set = gpos_applied;
946 adjustment[i].xadv = pos->x_advance;
947 adjustment[i].yadv = pos->y_advance;
948 adjustment[i].xoff = pos->x_pos;
949 adjustment[i].yoff = - pos->y_pos;
950 adjustment[i].back = pos->back;
951 adjustment[i].advance_is_absolute = pos->new_advance;
958 hb_buffer_free (buf);
959 for (i = 0; i < len; i++)
960 out->glyphs[out->used++] = in->glyphs[from + i];
965 open_font (char *fontname, char **err)
967 FT_Face face = new_face (fontname, err);
968 FontInfoHB *font_info;
972 font_info = calloc (1, sizeof (FontInfoHB));
973 font_info->face = face;
974 font_info->hb_font.klass = &hb_fontClass;
975 font_info->hb_font.faceData = face;
976 font_info->hb_font.userData = NULL;
977 font_info->hb_font.x_ppem = face->size->metrics.x_ppem;
978 font_info->hb_font.x_scale = face->size->metrics.x_scale;
979 font_info->hb_font.y_scale = face->size->metrics.y_scale;
980 font_info->hb_font.y_ppem = face->size->metrics.y_ppem;
981 font_info->otf_spec_cache = mplist ();
982 return ((MFLTFont *) font_info);
986 close_font (MFLTFont *font)
988 FontInfoHB *font_info = (FontInfoHB *) font;
993 HB_Done_GDEF_Table (font_info->gdef);
994 free (font_info->gdef_stream.base);
997 HB_Done_GSUB_Table (font_info->gsub);
999 HB_Done_GPOS_Table (font_info->gpos);
1000 FT_Done_Face ((FT_Face) (font_info->hb_font.faceData));
1001 for (p = font_info->otf_spec_cache; mplist_key (p) != Mnil;
1002 p = mplist_next (p))
1004 GsubGposInfo *ginfo = mplist_value (p);
1006 if (ginfo->gsub.count > 0)
1007 free (ginfo->gsub.indices);
1008 if (ginfo->gpos.count > 0)
1009 free (ginfo->gpos.indices);
1011 m17n_object_unref (font_info->otf_spec_cache);
1017 #else /* (defined (FLT_PANGO) */
1022 PangoOTRuleset *ruleset;
1032 PangoFontMap *fontmap;
1033 PangoContext *context;
1034 PangoFcFont *pango_font;
1035 MPlist *otf_spec_cache;
1039 get_glyph_id (MFLTFont *font, MFLTGlyphString *gstring, int from, int to)
1041 FontInfoPango *font_info = (FontInfoPango *) font;
1043 for (; from < to; from++)
1045 MFLTGlyph *g = gstring->glyphs + from;
1048 && ! (g->code = pango_fc_font_get_glyph (font_info->pango_font,
1056 #define PANGO_SCALE_TO_26_6 (PANGO_SCALE / (1<<6))
1059 get_metrics (MFLTFont *font, MFLTGlyphString *gstring, int from, int to)
1061 FontInfoPango *font_info = (FontInfoPango *) font;
1064 for (i = from; i < to; i++)
1066 MFLTGlyph *g = gstring->glyphs + from;
1070 PangoRectangle inc, logical;
1072 pango_font_get_glyph_extents (PANGO_FONT (font_info->pango_font),
1073 gstring->glyphs[i].code, &inc, &logical);
1074 g->lbearing = inc.x / PANGO_SCALE_TO_26_6;
1075 g->rbearing = (inc.x + inc.width) / PANGO_SCALE_TO_26_6;
1076 g->xadv = logical.width / PANGO_SCALE_TO_26_6;
1078 g->ascent = - inc.y / PANGO_SCALE_TO_26_6;
1079 g->descent = (inc.height + inc.y) / PANGO_SCALE_TO_26_6;
1087 #ifndef PANGO_OT_DEFAULT_LANGUAGE
1088 #define PANGO_OT_DEFAULT_LANGUAGE ((guint) 0xFFFF)
1090 #ifndef PANGO_OT_ALL_GLYPHS
1091 #define PANGO_OT_ALL_GLYPHS ((guint) 0xFFFF)
1095 setup_features (PangoOTTableType type, FontInfoPango *font_info,
1096 MFLTOtfSpec *spec, FeatureInfo *info)
1098 int count, preordered;
1099 unsigned int *features;
1100 guint script, langsys;
1101 guint req_feature, index;
1102 guint *feature_list;
1105 PangoOTInfo *ot_info;
1107 face = pango_fc_font_lock_face (font_info->pango_font);
1108 ot_info = pango_ot_info_get (face);
1109 pango_fc_font_unlock_face (font_info->pango_font);
1111 if (! pango_ot_info_find_script (ot_info, type, spec->script, &script))
1115 if (! pango_ot_info_find_language (ot_info, type, script,
1117 &langsys, &req_feature))
1122 langsys = PANGO_OT_DEFAULT_LANGUAGE;
1123 req_feature = 0xFFFF;
1125 if (type == PANGO_OT_TABLE_GSUB)
1127 count = spec->gsub_count;
1128 features = spec->gsub;
1132 count = spec->gpos_count;
1133 features = spec->gpos;
1135 feature_list = NULL;
1136 for (preordered = 0; preordered < count; preordered++)
1137 if (features[preordered] == 0)
1139 feature_list = pango_ot_info_list_features (ot_info, type, 0,
1146 for (i = 0; feature_list[i]; i++);
1149 info->indices = malloc (sizeof (guint) * ((req_feature != 0xFFFF) + i));
1151 if (req_feature != 0xFFFF)
1152 info->indices[i++] = req_feature;
1153 for (j = 0; j < preordered; j++)
1154 if (pango_ot_info_find_feature (ot_info, type, features[j],
1155 script, langsys, &index))
1156 info->indices[i++] = index;
1158 for (j = 0; feature_list[j]; j++)
1160 for (k = preordered + 1; k < count; k++)
1161 if (feature_list[j] == features[k])
1164 && pango_ot_info_find_feature (ot_info, type, feature_list[j],
1165 script, langsys, &index))
1166 info->indices[i++] = index;
1169 info->ruleset = pango_ot_ruleset_new (ot_info);
1171 for (i = 0; i < info->count; i++)
1172 pango_ot_ruleset_add_feature (info->ruleset, type, info->indices[i],
1173 PANGO_OT_ALL_GLYPHS);
1175 for (i = info->count - 1; i >= 0; i--)
1176 pango_ot_ruleset_add_feature (info->ruleset, type, info->indices[i],
1177 PANGO_OT_ALL_GLYPHS);
1182 setup_otf_spec (FontInfoPango *font_info, MFLTOtfSpec *spec)
1184 GsubGposInfo *ginfo;
1186 if (spec->gsub_count + spec->gpos_count == 0)
1188 ginfo = mplist_get (font_info->otf_spec_cache, spec->sym);
1190 return (ginfo->gsub.count + ginfo->gpos.count > 0 ? ginfo : NULL);
1191 ginfo = calloc (1, sizeof (GsubGposInfo));
1192 mplist_push (font_info->otf_spec_cache, spec->sym, ginfo);
1193 setup_features (PANGO_OT_TABLE_GSUB, font_info, spec, &(ginfo->gsub));
1194 setup_features (PANGO_OT_TABLE_GPOS, font_info, spec, &(ginfo->gpos));
1199 drive_otf (MFLTFont *font, MFLTOtfSpec *spec,
1200 MFLTGlyphString *in, int from, int to,
1201 MFLTGlyphString *out, MFLTGlyphAdjustment *adjustment)
1203 FontInfoPango *font_info = (FontInfoPango *) font;
1204 PangoOTBuffer *buffer;
1205 GsubGposInfo *ginfo;
1206 PangoGlyphString *glyphs;
1209 buffer = pango_ot_buffer_new (font_info->pango_font);
1210 for (i = from; i < to; i++)
1211 pango_ot_buffer_add_glyph (buffer, in->glyphs[i].code, 0, i);
1212 ginfo = setup_otf_spec (font_info, spec);
1215 if (ginfo->gsub.count > 0)
1216 pango_ot_ruleset_substitute (ginfo->gsub.ruleset, buffer);
1217 if (ginfo->gpos.count > 0)
1218 pango_ot_ruleset_position (ginfo->gpos.ruleset, buffer);
1219 glyphs = pango_glyph_string_new ();
1220 pango_ot_buffer_output (buffer, glyphs);
1221 for (i = 0; i < glyphs->num_glyphs; i++)
1223 PangoGlyphInfo *glyph_info = glyphs->glyphs + i;
1226 out->glyphs[out->used] = in->glyphs[glyphs->log_clusters[i]];
1227 g = out->glyphs + out->used++;
1228 if (g->code != glyph_info->glyph)
1231 g->code = glyph_info->glyph;
1234 g->xoff = glyph_info->geometry.x_offset / PANGO_SCALE_TO_26_6;
1235 g->yoff = glyph_info->geometry.y_offset / PANGO_SCALE_TO_26_6;
1236 g->xadv = glyph_info->geometry.width / PANGO_SCALE_TO_26_6;
1238 adjustment[i].set = 0;
1240 pango_ot_buffer_destroy (buffer);
1241 pango_glyph_string_free (glyphs);
1245 pango_ot_buffer_destroy (buffer);
1246 for (i = from; i < to; i++)
1247 out->glyphs[out->used++] = in->glyphs[i];
1253 open_font (char *fontname, char **err)
1255 FontInfoPango *font_info = NULL;
1256 PangoFontMap *fontmap;
1257 PangoContext *context;
1258 PangoFontDescription *desc;
1259 PangoFont *pango_font;
1264 if (parse_font_name (fontname, &family, &size, err) < 0)
1266 desc = pango_font_description_new ();
1267 pango_font_description_set_family (desc, family);
1269 pango_size = size * PANGO_SCALE;
1270 pango_font_description_set_absolute_size (desc, pango_size);
1272 fontmap = pango_ft2_font_map_new ();
1273 context = pango_context_new ();
1274 pango_context_set_font_map (context, fontmap);
1275 pango_font = pango_context_load_font (context, desc);
1276 pango_font_description_free (desc);
1279 font_info = calloc (1, sizeof (FontInfoPango));
1280 font_info->fontmap = fontmap;
1281 font_info->context = context;
1282 font_info->pango_font = PANGO_FC_FONT (pango_font);
1283 font_info->otf_spec_cache = mplist ();
1287 g_object_unref (context);
1288 g_object_unref (fontmap);
1290 return (MFLTFont *) font_info;
1294 close_font (MFLTFont *font)
1296 FontInfoPango *font_info = (FontInfoPango *) font;
1298 g_object_unref (font_info->context);
1299 g_object_unref (font_info->fontmap);
1307 run_flt (MText *mt, int from, int to, MFLTFont *font, char *flt_name)
1309 MDrawControl control;
1311 memset (&control, 0, sizeof (MDrawControl));
1312 control.two_dimensional = 1;
1313 control.enable_bidi = 1;
1314 control.anti_alias = 1;
1315 /*control.disable_caching = 1;*/
1316 mtext_put_prop (mt, from, to, Mfont, font->font);
1317 mdraw_text_extents (frame, mt, from, to, &control, NULL, NULL, NULL);
1324 run_flt (MText *mt, int from, int to, MFLTFont *font, char *flt_name)
1326 static MFLT *flt = NULL;
1327 MCharTable *coverage;
1328 static MFLTGlyphString gstring;
1331 && ! (flt = mflt_get (flt_name)))
1333 fprintf (stderr, "Invalid FLT name: %s\n", flt_name);
1336 coverage = mflt_coverage (flt);
1341 for (; from < to; from++)
1342 if (mchartable_lookup (coverage, mtext_ref_char (mt, from)))
1344 for (i = from + 1; i < to; i++)
1345 if (! mchartable_lookup (coverage, mtext_ref_char (mt, i)))
1352 if (gstring.allocated < len)
1354 gstring.allocated = len * 2;
1355 gstring.glyphs = realloc (gstring.glyphs,
1356 sizeof (MFLTGlyph) * len * 2);
1358 gstring.glyph_size = sizeof (MFLTGlyph);
1359 for (i = 0; i < len; i++)
1360 gstring.glyphs[i].c = mtext_ref_char (mt, from + i);
1362 i = mflt_run (&gstring, 0, len, font, flt);
1374 main (int argc, char **argv)
1376 char *font_name, *flt_name;
1385 fprintf (stderr, "Usage: flt FONT-NAME FLT-NAME < TEXT-FILE\n");
1389 font_name = argv[1];
1392 FT_Init_FreeType (&ft_library);
1394 font = open_font (font_name, &err);
1397 fprintf (stderr, "Font error: %s: %s\n", argv[1], err);
1400 font->get_glyph_id = get_glyph_id;
1401 font->get_metrics = get_metrics;
1402 font->drive_otf = drive_otf;
1405 buf = malloc (4096);
1406 while ((j = fread (buf + i, 1, 4096, stdin)) == 4096)
1409 buf = realloc (buf, i + 4096);
1411 mt = mtext_from_data (buf, i, MTEXT_FORMAT_UTF_8);
1412 len = mtext_len (mt);
1413 for (i = 0, j = mtext_character (mt, i, len, '\n'); i < len;
1414 i = j + 1, j = mtext_character (mt, i, len, '\n'))
1420 to = run_flt (mt, i, j, font, flt_name);
1423 fprintf (stderr, "Error in FLT processing.\n");
1428 m17n_object_unref (mt);