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/pango.h>
32 #include <pango/pango-ot.h>
33 #include <pango/pangoft2.h>
34 #include <pango/pangofc-font.h>
37 static FT_Library ft_library;
40 parse_font_name (char *fontname, char **family, int *size, char **err)
46 pat = FcNameParse ((FcChar8 *) fontname);
49 *err = "invalid name format";
52 if (FcPatternGetString (pat, FC_FAMILY, 0, &fam) != FcResultMatch)
54 FcPatternDestroy (pat);
55 *err = "no family name";
58 if (FcPatternGetDouble (pat, FC_PIXEL_SIZE, 0, &pixelsize) != FcResultMatch)
60 *family = strdup ((char *) fam);
62 FcPatternDestroy (pat);
67 new_face (char *fontname, char **err)
77 if (parse_font_name (fontname, (char **) &fam, &size, err) < 0)
80 pat = FcPatternBuild (0,
81 FC_FAMILY, FcTypeString, fam,
82 FC_SCALABLE, FcTypeBool, FcTrue,
85 os = FcObjectSetBuild (FC_FILE, NULL);
86 fs = FcFontList (NULL, pat, os);
89 *err = "no matching font";
92 FcPatternGetString (fs->fonts[0], FC_FILE, 0, &file);
94 if (FT_New_Face (ft_library, (char *) file, 0, &face))
96 FcFontSetDestroy (fs);
97 FcObjectSetDestroy (os);
98 FcPatternDestroy (pat);
99 *err = "font open fail";
102 FcFontSetDestroy (fs);
103 FcObjectSetDestroy (os);
104 FcPatternDestroy (pat);
105 if (FT_Set_Pixel_Sizes (face, pixelsize, pixelsize))
107 *err = "set pixelsize fail";
116 typedef struct _MFLTFont MFLTFont;
121 void (*get_glyph_id) (void);
122 void (*get_metric) (void);
123 void (*suitable_p) (void);
124 void (*drive_otf) (void);
129 void get_glyph_id (void) {}
130 void get_metric (void) {}
131 void suitable_p (void) {}
132 void drive_otf (void) {}
137 open_font (char *fontname, char **err)
139 FT_Face ft_face = new_face (fontname, err);
149 fontset = mfontset ("generic");
150 mface_put_prop (face, Mfontset, fontset);
151 mplist_add (plist, Mface, face);
152 mplist_add (plist, Mdevice, Mnil);
153 frame = mframe (plist);
154 m17n_object_unref (plist);
155 m17n_object_unref (face);
156 m17n_object_unref (fontset);
158 font = calloc (1, sizeof (MFLTFont));
159 font->font = mfont_encapsulate (frame, Mfreetype, ft_face);
160 font->face = ft_face;
165 close_font (MFLTFont *font)
167 FT_Done_Face (font->face);
169 m17n_object_unref (frame);
172 #elif defined (FLT_OTF) || defined (FLT_HB)
180 get_glyph_id (MFLTFont *font, MFLTGlyphString *gstring, int from, int to)
182 FT_Face face = ((FontInfo *) font)->face;
184 for (; from < to; from++)
186 MFLTGlyph *g = gstring->glyphs + from;
189 && ! (g->code = FT_Get_Char_Index (face, g->code)))
197 get_metric (MFLTFont *font, MFLTGlyphString *gstring, int from, int to)
199 FT_Face face = ((FontInfo *) font)->face;
201 for (; from < to; from++)
203 MFLTGlyph *g = gstring->glyphs + from;
207 FT_Glyph_Metrics *metrics;
209 if (FT_Load_Glyph (face, g->code, FT_LOAD_DEFAULT))
211 metrics = &face->glyph->metrics;
212 g->lbearing = metrics->horiBearingX;
213 g->rbearing = metrics->horiBearingX + metrics->width;
214 g->xadv = metrics->horiAdvance;
215 g->yadv = metrics->vertAdvance;
216 g->ascent = metrics->horiBearingY;
217 g->descent = metrics->height - metrics->horiBearingY;
232 #define DEVICE_DELTA(table, size) \
233 (((size) >= (table).StartSize && (size) <= (table).EndSize) \
234 ? ((table).DeltaValue[(size) - (table).StartSize] << 6) \
238 adjust_anchor (OTF_Anchor *anchor, FT_Face face,
239 unsigned code, unsigned x_ppem, unsigned y_ppem, int *x, int *y)
241 if (anchor->AnchorFormat == 2)
244 int ap = anchor->f.f1.AnchorPoint;
246 FT_Load_Glyph (face, (FT_UInt) code, FT_LOAD_MONOCHROME);
247 outline = &face->glyph->outline;
248 if (ap < outline->n_points)
250 *x = outline->points[ap].x;
251 *y = outline->points[ap].y;
254 else if (anchor->AnchorFormat == 3)
256 if (anchor->f.f2.XDeviceTable.offset)
257 *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, x_ppem);
258 if (anchor->f.f2.YDeviceTable.offset)
259 *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, y_ppem);
264 tag_name (char *str, unsigned tag)
267 *str++ = (tag >> 16) & 0xFF;
268 *str++ = (tag >> 8) & 0xFF;
274 encode_features (char *str, int count, unsigned *features)
279 for (i = 0; i < count; i++)
281 unsigned tag = features[i];
291 str = tag_name (str, tag);
304 drive_otf (MFLTFont *font, MFLTOtfSpec *spec,
305 MFLTGlyphString *in, int from, int to,
306 MFLTGlyphString *out, MFLTGlyphAdjustment *adjustment)
310 OTF *otf = ((FontInfoOTF *) font)->otf;
311 OTF_GlyphString otf_gstring;
313 char script[4], langsys[4];
314 char *gsub_features = NULL, *gpos_features = NULL;
321 otf_gstring.glyphs = NULL;
322 if (OTF_get_table (otf, "head") < 0)
325 ((FontInfoOTF *) font)->otf = NULL;
329 tag_name (script, spec->script);
330 tag_name (langsys, spec->langsys);
332 if (spec->gsub_count > 0)
334 gsub_features = alloca (6 * spec->gsub_count);
337 if (OTF_check_table (otf, "GSUB") < 0)
338 gsub_features = NULL;
340 encode_features (gsub_features, spec->gsub_count, spec->gsub);
343 if (spec->gpos_count)
345 gpos_features = alloca (6 * spec->gpos_count);
348 if (OTF_check_table (otf, "GPOS") < 0)
349 gpos_features = NULL;
351 encode_features (gpos_features, spec->gpos_count, spec->gpos);
355 otf_gstring.size = otf_gstring.used = len;
356 otf_gstring.glyphs = (OTF_Glyph *) malloc (sizeof (OTF_Glyph) * len);
357 memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * len);
358 for (i = 0; i < len; i++)
360 otf_gstring.glyphs[i].c = in->glyphs[from + i].c;
361 otf_gstring.glyphs[i].glyph_id = in->glyphs[from + i].code;
364 OTF_drive_gdef (otf, &otf_gstring);
369 if (OTF_drive_gsub (otf, &otf_gstring, script, langsys, gsub_features)
372 if (out->allocated < out->used + otf_gstring.used)
374 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++, otfg++)
376 MFLTGlyph *g = out->glyphs + out->used;
379 *g = in->glyphs[from + otfg->f.index.from];
381 for (j = from + otfg->f.index.from; j <= from + otfg->f.index.to; j++)
382 if (in->glyphs[j].code == otfg->glyph_id)
384 g->c = in->glyphs[j].c;
387 g->code = otfg->glyph_id;
393 if (out->allocated < out->used + len)
395 for (i = 0; i < len; i++)
396 out->glyphs[out->used++] = in->glyphs[from + i];
399 font->get_metric (font, out, gidx, out->used);
404 MFLTGlyph *base = NULL, *mark = NULL, *g;
405 int x_ppem, y_ppem, x_scale, y_scale;
407 if (OTF_drive_gpos (otf, &otf_gstring, script, langsys, gpos_features)
411 face = ((FontInfo *) font)->face;
412 x_ppem = face->size->metrics.x_ppem;
413 y_ppem = face->size->metrics.y_ppem;
414 x_scale = face->size->metrics.x_scale;
415 y_scale = face->size->metrics.y_scale;
417 for (i = 0, otfg = otf_gstring.glyphs, g = out->glyphs + gidx;
418 i < otf_gstring.used; i++, otfg++, g++)
422 if (! otfg->glyph_id)
424 switch (otfg->positioning_type)
430 int format = otfg->f.f1.format;
432 if (format & OTF_XPlacement)
434 = otfg->f.f1.value->XPlacement * x_scale / 0x10000;
435 if (format & OTF_XPlaDevice)
437 += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, x_ppem);
438 if (format & OTF_YPlacement)
440 = - (otfg->f.f1.value->YPlacement * y_scale / 0x10000);
441 if (format & OTF_YPlaDevice)
443 -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, y_ppem);
444 if (format & OTF_XAdvance)
446 += otfg->f.f1.value->XAdvance * x_scale / 0x10000;
447 if (format & OTF_XAdvDevice)
449 += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, x_ppem);
450 if (format & OTF_YAdvance)
452 += otfg->f.f1.value->YAdvance * y_scale / 0x10000;
453 if (format & OTF_YAdvDevice)
455 += DEVICE_DELTA (otfg->f.f1.value->YAdvDevice, y_ppem);
456 adjustment[i].set = 1;
460 /* Not yet supported. */
466 goto label_adjust_anchor;
467 default: /* i.e. case 6 */
474 int base_x, base_y, mark_x, mark_y;
476 base_x = otfg->f.f4.base_anchor->XCoordinate * x_scale / 0x10000;
477 base_y = otfg->f.f4.base_anchor->YCoordinate * y_scale / 0x10000;
478 mark_x = otfg->f.f4.mark_anchor->XCoordinate * x_scale / 0x10000;
479 mark_y = otfg->f.f4.mark_anchor->YCoordinate * y_scale / 0x10000;;
481 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
482 adjust_anchor (otfg->f.f4.base_anchor, face, prev->code,
483 x_ppem, y_ppem, &base_x, &base_y);
484 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
485 adjust_anchor (otfg->f.f4.mark_anchor, face, g->code,
486 x_ppem, y_ppem, &mark_x, &mark_y);
487 adjustment[i].xoff = (base_x - mark_x);
488 adjustment[i].yoff = - (base_y - mark_y);
489 adjustment[i].back = (g - prev);
490 adjustment[i].set = 1;
493 if (otfg->GlyphClass == OTF_GlyphClass0)
495 else if (otfg->GlyphClass == OTF_GlyphClassMark)
501 free (otf_gstring.glyphs);
505 font->get_metric (font, in, from, to);
506 for (i = 0; i < len; i++)
508 MFLTGlyph *g = in->glyphs + (from + i);
510 out->glyphs[out->used++] = *g;
512 if (otf_gstring.glyphs)
513 free (otf_gstring.glyphs);
518 open_font (char *fontname, char **err)
520 FT_Face face = new_face (fontname, err);
521 FontInfoOTF *font_info;
525 font_info = malloc (sizeof (FontInfoOTF));
526 font_info->face = face;
527 font_info->otf = OTF_open_ft_face (face);
528 return ((MFLTFont *) font_info);
532 close_font (MFLTFont *font)
534 FontInfoOTF *font_info = (FontInfoOTF *) font;
536 OTF_close (font_info->otf);
537 FT_Done_Face (font_info->face);
557 HB_StreamRec gdef_stream;
561 MPlist *otf_spec_cache;
565 convertStringToGlyphIndices (HB_Font font, const HB_UChar16 *string,
566 hb_uint32 length, HB_Glyph *glyphs,
567 hb_uint32 *numGlyphs, HB_Bool rightToLeft)
573 getGlyphAdvances (HB_Font font, const HB_Glyph *glyphs, hb_uint32 numGlyphs,
574 HB_Fixed *advances, int flags /*HB_ShaperFlag*/)
578 for (i = 0; i < numGlyphs; i++)
583 canRender (HB_Font font, const HB_UChar16 *string, hb_uint32 length)
589 getPointInOutline (HB_Font font, HB_Glyph glyph, int flags /*HB_ShaperFlag*/,
590 hb_uint32 point, HB_Fixed *xpos, HB_Fixed *ypos,
593 FT_Face face = font->faceData;
596 if ((error = (HB_Error) FT_Load_Glyph (face, glyph, flags)))
598 if (face->glyph->format != ft_glyph_format_outline)
599 return (HB_Error) HB_Err_Invalid_GPOS_SubTable;
600 *nPoints = face->glyph->outline.n_points;
603 if (point > *nPoints)
604 return (HB_Error) HB_Err_Invalid_GPOS_SubTable;
606 *xpos = face->glyph->outline.points[point].x;
607 *ypos = face->glyph->outline.points[point].y;
613 getGlyphMetrics (HB_Font font, HB_Glyph glyph, HB_GlyphMetrics *metrics)
618 getFontMetric (HB_Font font, HB_FontMetric metric)
623 #define MAKE_TAG(name) ((((FT_ULong) (name)[0]) << 24) \
624 | (((FT_ULong) (name)[1]) << 16) \
625 | (((FT_ULong) (name)[2]) << 8) \
629 new_stream (FT_Face face, char *tagname, HB_Stream stream)
631 FT_ULong tag = MAKE_TAG (tagname);
635 if (! FT_IS_SFNT (face))
636 return HB_Err_Invalid_Argument;
638 if (FT_Load_Sfnt_Table (face, tag, 0, NULL, &len))
639 return HB_Err_Table_Missing;
642 return HB_Err_Out_Of_Memory;
643 if (FT_Load_Sfnt_Table (face, tag, 0, buf, &len))
646 return HB_Err_Table_Missing;
648 stream->base = (HB_Byte *) buf;
651 stream->cursor = NULL;
657 load_gdef (FontInfoHB *font_info)
661 if (! font_info->gdef_stream.base)
663 err = new_stream ((FT_Face) font_info->hb_font.faceData, "GDEF",
664 &font_info->gdef_stream);
665 if (err != HB_Err_Ok)
668 return HB_Load_GDEF_Table (&font_info->gdef_stream, &font_info->gdef);
672 load_gsub (FontInfoHB *font_info)
676 HB_LookupList *lookup_list;
679 if (! font_info->gdef)
681 if ((err = load_gdef (font_info)) != HB_Err_Ok)
684 err = new_stream ((FT_Face) font_info->hb_font.faceData, "GSUB", &stream);
685 if (err != HB_Err_Ok)
687 err = HB_Load_GSUB_Table (&stream, &font_info->gsub,
688 font_info->gdef, &font_info->gdef_stream);
690 lookup_list = &font_info->gsub->LookupList;
691 for (i = 0; i < lookup_list->LookupCount; i++)
692 lookup_list->Properties[i] = HB_GLYPH_PROPERTIES_UNKNOWN;
697 load_gpos (FontInfoHB *font_info)
701 HB_LookupList *lookup_list;
704 if (! font_info->gdef)
706 if ((err = load_gdef (font_info)) != HB_Err_Ok)
709 err = new_stream ((FT_Face) font_info->hb_font.faceData, "GPOS", &stream);
710 if (err != HB_Err_Ok)
712 err = HB_Load_GPOS_Table (&stream, &font_info->gpos,
713 font_info->gdef, &font_info->gdef_stream);
715 lookup_list = &font_info->gpos->LookupList;
716 for (i = 0; i < lookup_list->LookupCount; i++)
717 lookup_list->Properties[i] = HB_GLYPH_PROPERTIES_UNKNOWN;
721 const HB_FontClass hb_fontClass = {
722 convertStringToGlyphIndices, getGlyphAdvances, canRender,
723 getPointInOutline, getGlyphMetrics, getFontMetric
727 setup_features (int gsubp, FontInfoHB *font_info, MFLTOtfSpec *spec,
730 int count, preordered;
731 unsigned int *features;
732 FT_UShort script, langsys;
733 FT_UShort req_feature, index;
734 FT_UInt *feature_list;
739 if (! font_info->gsub)
741 if (load_gsub (font_info) != HB_Err_Ok)
744 if (HB_GSUB_Select_Script (font_info->gsub, spec->script, &script)
749 if (HB_GSUB_Select_Language (font_info->gsub, spec->langsys,
750 script, &langsys, &req_feature)
755 langsys = req_feature = 0xFFFF;
756 count = spec->gsub_count;
757 features = spec->gsub;
761 if (! font_info->gpos)
763 if (load_gpos (font_info) != HB_Err_Ok)
766 if (HB_GPOS_Select_Script (font_info->gpos, spec->script, &script)
771 if (HB_GPOS_Select_Language (font_info->gpos, spec->langsys,
772 script, &langsys, &req_feature)
777 langsys = req_feature = 0xFFFF;
778 count = spec->gpos_count;
779 features = spec->gpos;
782 for (preordered = 0; preordered < count; preordered++)
783 if (features[preordered] == 0)
785 if ((gsubp ? HB_GSUB_Query_Features (font_info->gsub, script, langsys,
787 : HB_GPOS_Query_Features (font_info->gpos, script, langsys,
794 for (i = 0; feature_list[i]; i++);
797 info->indices = malloc (sizeof (FT_UShort) * ((req_feature != 0xFFFF) + i));
799 if (req_feature != 0xFFFF)
800 info->indices[i++] = req_feature;
801 for (j = 0; j < preordered; j++)
802 if ((gsubp ? HB_GSUB_Select_Feature (font_info->gsub, features[j],
803 script, langsys, &index)
804 : HB_GPOS_Select_Feature (font_info->gpos, features[j],
805 script, langsys, &index))
807 info->indices[i++] = index;
809 for (j = 0; feature_list[j]; j++)
811 for (k = preordered + 1; k < count; k++)
812 if (feature_list[j] == features[k])
816 ? HB_GSUB_Select_Feature (font_info->gsub, feature_list[j],
817 script, langsys, &index)
818 : HB_GPOS_Select_Feature (font_info->gpos, feature_list[j],
819 script, langsys, &index))
821 info->indices[i++] = index;
827 setup_otf_spec (MFLTFont *font, MFLTOtfSpec *spec)
829 FontInfoHB *font_info = (FontInfoHB *) font;
832 if (spec->gsub_count + spec->gpos_count == 0)
834 ginfo = mplist_get (font_info->otf_spec_cache, spec->sym);
836 return (ginfo->gsub.count + ginfo->gpos.count > 0 ? ginfo : NULL);
837 ginfo = calloc (1, sizeof (GsubGposInfo));
838 mplist_push (font_info->otf_spec_cache, spec->sym, ginfo);
839 setup_features (1, font_info, spec, &(ginfo->gsub));
840 setup_features (0, font_info, spec, &(ginfo->gpos));
845 drive_otf (MFLTFont *font, MFLTOtfSpec *spec,
846 MFLTGlyphString *in, int from, int to,
847 MFLTGlyphString *out, MFLTGlyphAdjustment *adjustment)
849 FontInfoHB *font_info = (FontInfoHB *) font;
854 HB_UShort *apply_order_save;
855 HB_UShort apply_count_save;
856 int gpos_applied = 0;
863 if (hb_buffer_new (&buf) != FT_Err_Ok)
865 for (i = from; i < to; i++)
867 if (hb_buffer_add_glyph (buf, in->glyphs[i].code, 0, i) != FT_Err_Ok)
870 ginfo = setup_otf_spec (font, spec);
873 if (ginfo->gsub.count > 0)
875 if (! font_info->gdef
876 && load_gdef (font_info) != HB_Err_Ok)
878 apply_order_save = font_info->gsub->FeatureList.ApplyOrder;
879 apply_count_save = font_info->gsub->FeatureList.ApplyCount;
880 font_info->gsub->FeatureList.ApplyOrder = ginfo->gsub.indices;
881 font_info->gsub->FeatureList.ApplyCount = ginfo->gsub.count;
882 err = HB_GSUB_Apply_String (font_info->gsub, buf);
883 font_info->gsub->FeatureList.ApplyOrder = apply_order_save;
884 font_info->gsub->FeatureList.ApplyCount = apply_count_save;
885 if (err != HB_Err_Ok && err != HB_Err_Not_Covered)
887 if (out->used + buf->in_length > out->allocated)
891 if (ginfo->gpos.count > 0
892 && (font_info->gpos || load_gpos (font_info) == HB_Err_Ok))
894 apply_order_save = font_info->gpos->FeatureList.ApplyOrder;
895 apply_count_save = font_info->gpos->FeatureList.ApplyCount;
896 font_info->gpos->FeatureList.ApplyOrder = ginfo->gpos.indices;
897 font_info->gpos->FeatureList.ApplyCount = ginfo->gpos.count;
898 err = HB_GPOS_Apply_String (&font_info->hb_font, font_info->gpos,
899 FT_LOAD_DEFAULT, buf, FALSE, FALSE);
900 font_info->gpos->FeatureList.ApplyOrder = apply_order_save;
901 font_info->gpos->FeatureList.ApplyCount = apply_count_save;
902 if (err == HB_Err_Ok)
906 for (i = 0; i < buf->in_length; i++)
908 HB_GlyphItem hg = buf->in_string + i;
909 HB_Position pos = buf->positions + i;
912 out->glyphs[out->used] = in->glyphs[hg->cluster];
913 g = out->glyphs + out->used++;
914 if (g->code != hg->gindex)
915 g->c = 0, g->code = hg->gindex;
916 adjustment[i].set = gpos_applied;
919 adjustment[i].xadv = pos->x_advance;
920 adjustment[i].yadv = pos->y_advance;
921 adjustment[i].xoff = pos->x_pos;
922 adjustment[i].yoff = - pos->y_pos;
923 adjustment[i].back = pos->back;
924 adjustment[i].advance_is_absolute = pos->new_advance;
931 hb_buffer_free (buf);
932 for (i = 0; i < len; i++)
933 out->glyphs[out->used++] = in->glyphs[from + i];
938 open_font (char *fontname, char **err)
940 FT_Face face = new_face (fontname, err);
941 FontInfoHB *font_info;
945 font_info = calloc (1, sizeof (FontInfoHB));
946 font_info->face = face;
947 font_info->hb_font.klass = &hb_fontClass;
948 font_info->hb_font.faceData = face;
949 font_info->hb_font.userData = NULL;
950 font_info->hb_font.x_ppem = face->size->metrics.x_ppem;
951 font_info->hb_font.x_scale = face->size->metrics.x_scale;
952 font_info->hb_font.y_scale = face->size->metrics.y_scale;
953 font_info->hb_font.y_ppem = face->size->metrics.y_ppem;
954 font_info->otf_spec_cache = mplist ();
955 return ((MFLTFont *) font_info);
959 close_font (MFLTFont *font)
961 FontInfoHB *font_info = (FontInfoHB *) font;
966 HB_Done_GDEF_Table (font_info->gdef);
967 free (font_info->gdef_stream.base);
970 HB_Done_GSUB_Table (font_info->gsub);
972 HB_Done_GPOS_Table (font_info->gpos);
973 FT_Done_Face ((FT_Face) (font_info->hb_font.faceData));
974 for (p = font_info->otf_spec_cache; mplist_key (p) != Mnil;
977 GsubGposInfo *ginfo = mplist_value (p);
979 if (ginfo->gsub.count > 0)
980 free (ginfo->gsub.indices);
981 if (ginfo->gpos.count > 0)
982 free (ginfo->gpos.indices);
984 m17n_object_unref (font_info->otf_spec_cache);
990 #else /* (defined (FLT_PANGO) */
995 PangoOTRuleset *ruleset;
1005 PangoFontMap *fontmap;
1006 PangoContext *context;
1007 PangoFcFont *pango_font;
1008 MPlist *otf_spec_cache;
1012 get_glyph_id (MFLTFont *font, MFLTGlyphString *gstring, int from, int to)
1014 FontInfoPango *font_info = (FontInfoPango *) font;
1016 for (; from < to; from++)
1018 MFLTGlyph *g = gstring->glyphs + from;
1021 && ! (g->code = pango_fc_font_get_glyph (font_info->pango_font,
1029 #define PANGO_SCALE_TO_26_6 (PANGO_SCALE / (1<<6))
1032 get_metric (MFLTFont *font, MFLTGlyphString *gstring, int from, int to)
1034 FontInfoPango *font_info = (FontInfoPango *) font;
1037 for (i = from; i < to; i++)
1039 MFLTGlyph *g = gstring->glyphs + from;
1043 PangoRectangle inc, logical;
1045 pango_font_get_glyph_extents (PANGO_FONT (font_info->pango_font),
1046 gstring->glyphs[i].code, &inc, &logical);
1047 g->lbearing = inc.x / PANGO_SCALE_TO_26_6;
1048 g->rbearing = (inc.x + inc.width) / PANGO_SCALE_TO_26_6;
1049 g->xadv = logical.width / PANGO_SCALE_TO_26_6;
1051 g->ascent = - inc.y / PANGO_SCALE_TO_26_6;
1052 g->descent = (inc.height + inc.y) / PANGO_SCALE_TO_26_6;
1060 #ifndef PANGO_OT_DEFAULT_LANGUAGE
1061 #define PANGO_OT_DEFAULT_LANGUAGE ((guint) 0xFFFF)
1063 #ifndef PANGO_OT_ALL_GLYPHS
1064 #define PANGO_OT_ALL_GLYPHS ((guint) 0xFFFF)
1068 setup_features (PangoOTTableType type, FontInfoPango *font_info,
1069 MFLTOtfSpec *spec, FeatureInfo *info)
1071 int count, preordered;
1072 unsigned int *features;
1073 guint script, langsys;
1074 guint req_feature, index;
1075 guint *feature_list;
1078 PangoOTInfo *ot_info;
1080 face = pango_fc_font_lock_face (font_info->pango_font);
1081 ot_info = pango_ot_info_get (face);
1082 pango_fc_font_unlock_face (font_info->pango_font);
1084 if (! pango_ot_info_find_script (ot_info, type, spec->script, &script))
1088 if (! pango_ot_info_find_language (ot_info, type, script,
1090 &langsys, &req_feature))
1095 langsys = PANGO_OT_DEFAULT_LANGUAGE;
1096 req_feature = 0xFFFF;
1098 if (type == PANGO_OT_TABLE_GSUB)
1100 count = spec->gsub_count;
1101 features = spec->gsub;
1105 count = spec->gpos_count;
1106 features = spec->gpos;
1108 feature_list = NULL;
1109 for (preordered = 0; preordered < count; preordered++)
1110 if (features[preordered] == 0)
1112 feature_list = pango_ot_info_list_features (ot_info, type, 0,
1119 for (i = 0; feature_list[i]; i++);
1122 info->indices = malloc (sizeof (guint) * ((req_feature != 0xFFFF) + i));
1124 if (req_feature != 0xFFFF)
1125 info->indices[i++] = req_feature;
1126 for (j = 0; j < preordered; j++)
1127 if (pango_ot_info_find_feature (ot_info, type, features[j],
1128 script, langsys, &index))
1129 info->indices[i++] = index;
1131 for (j = 0; feature_list[j]; j++)
1133 for (k = preordered + 1; k < count; k++)
1134 if (feature_list[j] == features[k])
1137 && pango_ot_info_find_feature (ot_info, type, feature_list[j],
1138 script, langsys, &index))
1139 info->indices[i++] = index;
1142 info->ruleset = pango_ot_ruleset_new (ot_info);
1144 for (i = 0; i < info->count; i++)
1145 pango_ot_ruleset_add_feature (info->ruleset, type, info->indices[i],
1146 PANGO_OT_ALL_GLYPHS);
1148 for (i = info->count - 1; i >= 0; i--)
1149 pango_ot_ruleset_add_feature (info->ruleset, type, info->indices[i],
1150 PANGO_OT_ALL_GLYPHS);
1155 setup_otf_spec (FontInfoPango *font_info, MFLTOtfSpec *spec)
1157 GsubGposInfo *ginfo;
1159 if (spec->gsub_count + spec->gpos_count == 0)
1161 ginfo = mplist_get (font_info->otf_spec_cache, spec->sym);
1163 return (ginfo->gsub.count + ginfo->gpos.count > 0 ? ginfo : NULL);
1164 ginfo = calloc (1, sizeof (GsubGposInfo));
1165 mplist_push (font_info->otf_spec_cache, spec->sym, ginfo);
1166 setup_features (PANGO_OT_TABLE_GSUB, font_info, spec, &(ginfo->gsub));
1167 setup_features (PANGO_OT_TABLE_GPOS, font_info, spec, &(ginfo->gpos));
1172 drive_otf (MFLTFont *font, MFLTOtfSpec *spec,
1173 MFLTGlyphString *in, int from, int to,
1174 MFLTGlyphString *out, MFLTGlyphAdjustment *adjustment)
1176 FontInfoPango *font_info = (FontInfoPango *) font;
1177 PangoOTBuffer *buffer;
1178 GsubGposInfo *ginfo;
1179 PangoGlyphString *glyphs;
1182 buffer = pango_ot_buffer_new (font_info->pango_font);
1183 for (i = from; i < to; i++)
1184 pango_ot_buffer_add_glyph (buffer, in->glyphs[i].code, 0, i);
1185 ginfo = setup_otf_spec (font_info, spec);
1188 if (ginfo->gsub.count > 0)
1189 pango_ot_ruleset_substitute (ginfo->gsub.ruleset, buffer);
1190 if (ginfo->gpos.count > 0)
1191 pango_ot_ruleset_position (ginfo->gpos.ruleset, buffer);
1192 glyphs = pango_glyph_string_new ();
1193 pango_ot_buffer_output (buffer, glyphs);
1194 for (i = 0; i < glyphs->num_glyphs; i++)
1196 PangoGlyphInfo *glyph_info = glyphs->glyphs + i;
1199 out->glyphs[out->used] = in->glyphs[glyphs->log_clusters[i]];
1200 g = out->glyphs + out->used++;
1201 if (g->code != glyph_info->glyph)
1202 g->c = 0, g->code = glyph_info->glyph;
1203 g->xoff = glyph_info->geometry.x_offset / PANGO_SCALE_TO_26_6;
1204 g->yoff = glyph_info->geometry.y_offset / PANGO_SCALE_TO_26_6;
1205 g->xadv = glyph_info->geometry.width / PANGO_SCALE_TO_26_6;
1207 adjustment[i].set = 0;
1209 pango_ot_buffer_destroy (buffer);
1210 pango_glyph_string_free (glyphs);
1214 pango_ot_buffer_destroy (buffer);
1215 for (i = from; i < to; i++)
1216 out->glyphs[out->used++] = in->glyphs[i];
1222 open_font (char *fontname, char **err)
1224 FontInfoPango *font_info = NULL;
1225 PangoFontMap *fontmap;
1226 PangoContext *context;
1227 PangoFontDescription *desc;
1228 PangoFont *pango_font;
1233 if (parse_font_name (fontname, &family, &size, err) < 0)
1235 desc = pango_font_description_new ();
1236 pango_font_description_set_family (desc, family);
1238 pango_size = size * PANGO_SCALE;
1239 pango_font_description_set_absolute_size (desc, pango_size);
1241 fontmap = pango_ft2_font_map_new ();
1242 context = pango_context_new ();
1243 pango_context_set_font_map (context, fontmap);
1244 pango_font = pango_context_load_font (context, desc);
1245 pango_font_description_free (desc);
1248 font_info = calloc (1, sizeof (FontInfoPango));
1249 font_info->fontmap = fontmap;
1250 font_info->context = context;
1251 font_info->pango_font = PANGO_FC_FONT (pango_font);
1252 font_info->otf_spec_cache = mplist ();
1256 g_object_unref (context);
1257 g_object_unref (fontmap);
1259 return (MFLTFont *) font_info;
1263 close_font (MFLTFont *font)
1265 FontInfoPango *font_info = (FontInfoPango *) font;
1267 g_object_unref (font_info->context);
1268 g_object_unref (font_info->fontmap);
1276 run_flt (MText *mt, int from, int to, MFLTFont *font, char *flt_name)
1278 MDrawControl control;
1280 memset (&control, 0, sizeof (MDrawControl));
1281 control.two_dimensional = 1;
1282 control.enable_bidi = 1;
1283 control.anti_alias = 1;
1284 /*control.disable_caching = 1;*/
1285 mtext_put_prop (mt, from, to, Mfont, font->font);
1286 mdraw_text_extents (frame, mt, from, to, &control, NULL, NULL, NULL);
1293 run_flt (MText *mt, int from, int to, MFLTFont *font, char *flt_name)
1295 static MFLT *flt = NULL;
1296 MCharTable *coverage;
1297 static MFLTGlyphString gstring;
1300 && ! (flt = mflt_get (flt_name)))
1302 fprintf (stderr, "Invalid FLT name: %s\n", flt_name);
1305 coverage = mflt_coverage (flt);
1310 for (; from < to; from++)
1311 if (mchartable_lookup (coverage, mtext_ref_char (mt, from)))
1313 for (i = from + 1; i < to; i++)
1314 if (! mchartable_lookup (coverage, mtext_ref_char (mt, i)))
1321 if (gstring.allocated < len)
1323 gstring.allocated = len * 2;
1324 gstring.glyphs = realloc (gstring.glyphs,
1325 sizeof (MFLTGlyph) * len * 2);
1327 gstring.glyph_size = sizeof (MFLTGlyph);
1328 for (i = 0; i < len; i++)
1329 gstring.glyphs[i].c = mtext_ref_char (mt, from + i);
1331 i = mflt_run (&gstring, 0, len, font, flt);
1343 main (int argc, char **argv)
1345 char *font_name, *flt_name;
1353 fprintf (stderr, "Usage: flt FONT-NAME FLT-NAME < TEXT-FILE\n");
1357 font_name = argv[1];
1360 FT_Init_FreeType (&ft_library);
1362 font = open_font (font_name, &err);
1365 fprintf (stderr, "Font error: %s: %s\n", argv[1], err);
1368 font->get_glyph_id = get_glyph_id;
1369 font->get_metric = get_metric;
1370 font->drive_otf = drive_otf;
1372 mt = mconv_decode_stream (msymbol ("utf-8"), stdin);
1373 len = mtext_len (mt);
1374 for (i = 0, j = mtext_character (mt, i, len, '\n'); i < len;
1375 i = j + 1, j = mtext_character (mt, i, len, '\n'))
1381 to = run_flt (mt, i, j, font, flt_name);
1384 fprintf (stderr, "Error in FLT processing.\n");
1389 m17n_object_unref (mt);