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>
38 #include <m17n-misc.h>
40 static FT_Library ft_library;
43 parse_font_name (char *fontname, char **family, int *size, char **err)
49 pat = FcNameParse ((FcChar8 *) fontname);
52 *err = "invalid name format";
55 if (FcPatternGetString (pat, FC_FAMILY, 0, &fam) != FcResultMatch)
57 FcPatternDestroy (pat);
58 *err = "no family name";
61 if (FcPatternGetDouble (pat, FC_PIXEL_SIZE, 0, &pixelsize) != FcResultMatch)
63 *family = strdup ((char *) fam);
65 FcPatternDestroy (pat);
70 new_face (char *fontname, char **err)
80 if (parse_font_name (fontname, (char **) &fam, &size, err) < 0)
83 pat = FcPatternBuild (0,
84 FC_FAMILY, FcTypeString, fam,
85 FC_SCALABLE, FcTypeBool, FcTrue,
88 os = FcObjectSetBuild (FC_FILE, NULL);
89 fs = FcFontList (NULL, pat, os);
92 *err = "no matching font";
95 FcPatternGetString (fs->fonts[0], FC_FILE, 0, &file);
97 if (FT_New_Face (ft_library, (char *) file, 0, &face))
99 FcFontSetDestroy (fs);
100 FcObjectSetDestroy (os);
101 FcPatternDestroy (pat);
102 *err = "font open fail";
105 FcFontSetDestroy (fs);
106 FcObjectSetDestroy (os);
107 FcPatternDestroy (pat);
108 if (FT_Set_Pixel_Sizes (face, pixelsize, pixelsize))
110 *err = "set pixelsize fail";
119 typedef struct _MFLTFont MFLTFont;
124 void (*get_glyph_id) (void);
125 void (*get_metrics) (void);
126 void (*suitable_p) (void);
127 void (*drive_otf) (void);
132 void get_glyph_id (void) {}
133 void get_metrics (void) {}
134 void suitable_p (void) {}
135 void drive_otf (void) {}
140 open_font (char *fontname, char **err)
142 FT_Face ft_face = new_face (fontname, err);
152 fontset = mfontset ("generic");
153 mface_put_prop (face, Mfontset, fontset);
154 mplist_add (plist, Mface, face);
155 mplist_add (plist, Mdevice, Mnil);
156 frame = mframe (plist);
157 m17n_object_unref (plist);
158 m17n_object_unref (face);
159 m17n_object_unref (fontset);
161 font = calloc (1, sizeof (MFLTFont));
162 font->font = mfont_encapsulate (frame, Mfreetype, ft_face);
163 font->face = ft_face;
168 close_font (MFLTFont *font)
170 FT_Done_Face (font->face);
172 m17n_object_unref (frame);
175 #elif defined (FLT_OTF) || defined (FLT_HB)
183 get_glyph_id (MFLTFont *font, MFLTGlyphString *gstring, int from, int to)
185 FT_Face face = ((FontInfo *) font)->face;
187 for (; from < to; from++)
189 MFLTGlyph *g = gstring->glyphs + from;
192 && ! (g->code = FT_Get_Char_Index (face, g->code)))
200 get_metrics (MFLTFont *font, MFLTGlyphString *gstring, int from, int to)
202 FT_Face face = ((FontInfo *) font)->face;
204 for (; from < to; from++)
206 MFLTGlyph *g = gstring->glyphs + from;
210 FT_Glyph_Metrics *metrics;
212 if (FT_Load_Glyph (face, g->code, FT_LOAD_DEFAULT))
214 metrics = &face->glyph->metrics;
215 g->lbearing = metrics->horiBearingX;
216 g->rbearing = metrics->horiBearingX + metrics->width;
217 g->xadv = metrics->horiAdvance;
218 g->yadv = metrics->vertAdvance;
219 g->ascent = metrics->horiBearingY;
220 g->descent = metrics->height - metrics->horiBearingY;
235 #define DEVICE_DELTA(table, size) \
236 (((size) >= (table).StartSize && (size) <= (table).EndSize) \
237 ? ((table).DeltaValue[(size) - (table).StartSize] << 6) \
241 adjust_anchor (OTF_Anchor *anchor, FT_Face face,
242 unsigned code, unsigned x_ppem, unsigned y_ppem, int *x, int *y)
244 if (anchor->AnchorFormat == 2)
247 int ap = anchor->f.f1.AnchorPoint;
249 FT_Load_Glyph (face, (FT_UInt) code, FT_LOAD_MONOCHROME);
250 outline = &face->glyph->outline;
251 if (ap < outline->n_points)
253 *x = outline->points[ap].x;
254 *y = outline->points[ap].y;
257 else if (anchor->AnchorFormat == 3)
259 if (anchor->f.f2.XDeviceTable.offset)
260 *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, x_ppem);
261 if (anchor->f.f2.YDeviceTable.offset)
262 *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, y_ppem);
267 tag_name (char *str, unsigned tag)
270 *str++ = (tag >> 16) & 0xFF;
271 *str++ = (tag >> 8) & 0xFF;
277 encode_features (char *str, int count, unsigned *features)
282 for (i = 0; i < count; i++)
284 unsigned tag = features[i];
294 str = tag_name (str, tag);
307 drive_otf (MFLTFont *font, MFLTOtfSpec *spec,
308 MFLTGlyphString *in, int from, int to,
309 MFLTGlyphString *out, MFLTGlyphAdjustment *adjustment)
313 OTF *otf = ((FontInfoOTF *) font)->otf;
314 OTF_GlyphString otf_gstring;
316 char script[4], langsys[4];
317 char *gsub_features = NULL, *gpos_features = NULL;
324 otf_gstring.glyphs = NULL;
325 if (OTF_get_table (otf, "head") < 0)
328 ((FontInfoOTF *) font)->otf = NULL;
332 tag_name (script, spec->script);
333 tag_name (langsys, spec->langsys);
335 if (spec->gsub_count > 0)
337 gsub_features = alloca (6 * spec->gsub_count);
340 if (OTF_check_table (otf, "GSUB") < 0)
341 gsub_features = NULL;
343 encode_features (gsub_features, spec->gsub_count, spec->gsub);
346 if (spec->gpos_count)
348 gpos_features = alloca (6 * spec->gpos_count);
351 if (OTF_check_table (otf, "GPOS") < 0)
352 gpos_features = NULL;
354 encode_features (gpos_features, spec->gpos_count, spec->gpos);
358 otf_gstring.size = otf_gstring.used = len;
359 otf_gstring.glyphs = (OTF_Glyph *) malloc (sizeof (OTF_Glyph) * len);
360 memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * len);
361 for (i = 0; i < len; i++)
363 otf_gstring.glyphs[i].c = in->glyphs[from + i].c;
364 otf_gstring.glyphs[i].glyph_id = in->glyphs[from + i].code;
367 OTF_drive_gdef (otf, &otf_gstring);
372 if (OTF_drive_gsub (otf, &otf_gstring, script, langsys, gsub_features)
375 if (out->allocated < out->used + otf_gstring.used)
377 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++, otfg++)
379 MFLTGlyph *g = out->glyphs + out->used;
382 *g = in->glyphs[from + otfg->f.index.from];
384 for (j = from + otfg->f.index.from; j <= from + otfg->f.index.to; j++)
385 if (in->glyphs[j].code == otfg->glyph_id)
387 g->c = in->glyphs[j].c;
390 if (g->code != otfg->glyph_id)
392 g->code = otfg->glyph_id;
400 if (out->allocated < out->used + len)
402 for (i = 0; i < len; i++)
403 out->glyphs[out->used++] = in->glyphs[from + i];
409 MFLTGlyph *base = NULL, *mark = NULL, *g;
410 int x_ppem, y_ppem, x_scale, y_scale;
412 if (OTF_drive_gpos (otf, &otf_gstring, script, langsys, gpos_features)
416 face = ((FontInfo *) font)->face;
417 x_ppem = face->size->metrics.x_ppem;
418 y_ppem = face->size->metrics.y_ppem;
419 x_scale = face->size->metrics.x_scale;
420 y_scale = face->size->metrics.y_scale;
422 for (i = 0, otfg = otf_gstring.glyphs, g = out->glyphs + gidx;
423 i < otf_gstring.used; i++, otfg++, g++)
427 if (! otfg->glyph_id)
429 switch (otfg->positioning_type)
435 int format = otfg->f.f1.format;
437 if (format & OTF_XPlacement)
439 = otfg->f.f1.value->XPlacement * x_scale / 0x10000;
440 if (format & OTF_XPlaDevice)
442 += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, x_ppem);
443 if (format & OTF_YPlacement)
445 = - (otfg->f.f1.value->YPlacement * y_scale / 0x10000);
446 if (format & OTF_YPlaDevice)
448 -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, y_ppem);
449 if (format & OTF_XAdvance)
451 += otfg->f.f1.value->XAdvance * x_scale / 0x10000;
452 if (format & OTF_XAdvDevice)
454 += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, x_ppem);
455 if (format & OTF_YAdvance)
457 += otfg->f.f1.value->YAdvance * y_scale / 0x10000;
458 if (format & OTF_YAdvDevice)
460 += DEVICE_DELTA (otfg->f.f1.value->YAdvDevice, y_ppem);
461 adjustment[i].set = 1;
465 /* Not yet supported. */
471 goto label_adjust_anchor;
472 default: /* i.e. case 6 */
479 int base_x, base_y, mark_x, mark_y;
481 base_x = otfg->f.f4.base_anchor->XCoordinate * x_scale / 0x10000;
482 base_y = otfg->f.f4.base_anchor->YCoordinate * y_scale / 0x10000;
483 mark_x = otfg->f.f4.mark_anchor->XCoordinate * x_scale / 0x10000;
484 mark_y = otfg->f.f4.mark_anchor->YCoordinate * y_scale / 0x10000;;
486 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
487 adjust_anchor (otfg->f.f4.base_anchor, face, prev->code,
488 x_ppem, y_ppem, &base_x, &base_y);
489 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
490 adjust_anchor (otfg->f.f4.mark_anchor, face, g->code,
491 x_ppem, y_ppem, &mark_x, &mark_y);
492 adjustment[i].xoff = (base_x - mark_x);
493 adjustment[i].yoff = - (base_y - mark_y);
494 adjustment[i].back = (g - prev);
495 adjustment[i].set = 1;
498 if (otfg->GlyphClass == OTF_GlyphClass0)
500 else if (otfg->GlyphClass == OTF_GlyphClassMark)
506 free (otf_gstring.glyphs);
510 font->get_metrics (font, in, from, to);
511 for (i = 0; i < len; i++)
513 MFLTGlyph *g = in->glyphs + (from + i);
515 out->glyphs[out->used++] = *g;
517 if (otf_gstring.glyphs)
518 free (otf_gstring.glyphs);
523 open_font (char *fontname, char **err)
525 FT_Face face = new_face (fontname, err);
526 FontInfoOTF *font_info;
530 font_info = malloc (sizeof (FontInfoOTF));
531 font_info->face = face;
532 font_info->otf = OTF_open_ft_face (face);
533 return ((MFLTFont *) font_info);
537 close_font (MFLTFont *font)
539 FontInfoOTF *font_info = (FontInfoOTF *) font;
541 OTF_close (font_info->otf);
542 FT_Done_Face (font_info->face);
562 HB_StreamRec gdef_stream;
566 MPlist *otf_spec_cache;
570 convertStringToGlyphIndices (HB_Font font, const HB_UChar16 *string,
571 hb_uint32 length, HB_Glyph *glyphs,
572 hb_uint32 *numGlyphs, HB_Bool rightToLeft)
578 getGlyphAdvances (HB_Font font, const HB_Glyph *glyphs, hb_uint32 numGlyphs,
579 HB_Fixed *advances, int flags /*HB_ShaperFlag*/)
583 for (i = 0; i < numGlyphs; i++)
588 canRender (HB_Font font, const HB_UChar16 *string, hb_uint32 length)
594 getPointInOutline (HB_Font font, HB_Glyph glyph, int flags /*HB_ShaperFlag*/,
595 hb_uint32 point, HB_Fixed *xpos, HB_Fixed *ypos,
598 FT_Face face = font->faceData;
601 if ((error = (HB_Error) FT_Load_Glyph (face, glyph, flags)))
603 if (face->glyph->format != ft_glyph_format_outline)
604 return (HB_Error) HB_Err_Invalid_GPOS_SubTable;
605 *nPoints = face->glyph->outline.n_points;
608 if (point > *nPoints)
609 return (HB_Error) HB_Err_Invalid_GPOS_SubTable;
611 *xpos = face->glyph->outline.points[point].x;
612 *ypos = face->glyph->outline.points[point].y;
618 getGlyphMetrics (HB_Font font, HB_Glyph glyph, HB_GlyphMetrics *metrics)
623 getFontMetric (HB_Font font, HB_FontMetric metric)
628 #define MAKE_TAG(name) ((((FT_ULong) (name)[0]) << 24) \
629 | (((FT_ULong) (name)[1]) << 16) \
630 | (((FT_ULong) (name)[2]) << 8) \
634 new_stream (FT_Face face, char *tagname, HB_Stream stream)
636 FT_ULong tag = MAKE_TAG (tagname);
640 if (! FT_IS_SFNT (face))
641 return HB_Err_Invalid_Argument;
643 if (FT_Load_Sfnt_Table (face, tag, 0, NULL, &len))
644 return HB_Err_Table_Missing;
647 return HB_Err_Out_Of_Memory;
648 if (FT_Load_Sfnt_Table (face, tag, 0, buf, &len))
651 return HB_Err_Table_Missing;
653 stream->base = (HB_Byte *) buf;
656 stream->cursor = NULL;
662 load_gdef (FontInfoHB *font_info)
666 if (! font_info->gdef_stream.base)
668 err = new_stream ((FT_Face) font_info->hb_font.faceData, "GDEF",
669 &font_info->gdef_stream);
670 if (err != HB_Err_Ok)
673 return HB_Load_GDEF_Table (&font_info->gdef_stream, &font_info->gdef);
677 load_gsub (FontInfoHB *font_info)
681 HB_LookupList *lookup_list;
684 if (! font_info->gdef)
686 if ((err = load_gdef (font_info)) != HB_Err_Ok)
689 err = new_stream ((FT_Face) font_info->hb_font.faceData, "GSUB", &stream);
690 if (err != HB_Err_Ok)
692 err = HB_Load_GSUB_Table (&stream, &font_info->gsub,
693 font_info->gdef, &font_info->gdef_stream);
695 lookup_list = &font_info->gsub->LookupList;
696 for (i = 0; i < lookup_list->LookupCount; i++)
697 lookup_list->Properties[i] = HB_GLYPH_PROPERTIES_UNKNOWN;
702 load_gpos (FontInfoHB *font_info)
706 HB_LookupList *lookup_list;
709 if (! font_info->gdef)
711 if ((err = load_gdef (font_info)) != HB_Err_Ok)
714 err = new_stream ((FT_Face) font_info->hb_font.faceData, "GPOS", &stream);
715 if (err != HB_Err_Ok)
717 err = HB_Load_GPOS_Table (&stream, &font_info->gpos,
718 font_info->gdef, &font_info->gdef_stream);
720 lookup_list = &font_info->gpos->LookupList;
721 for (i = 0; i < lookup_list->LookupCount; i++)
722 lookup_list->Properties[i] = HB_GLYPH_PROPERTIES_UNKNOWN;
726 const HB_FontClass hb_fontClass = {
727 convertStringToGlyphIndices, getGlyphAdvances, canRender,
728 getPointInOutline, getGlyphMetrics, getFontMetric
732 setup_features (int gsubp, FontInfoHB *font_info, MFLTOtfSpec *spec,
735 int count, preordered;
736 unsigned int *features;
737 FT_UShort script, langsys;
738 FT_UShort req_feature, index;
739 FT_UInt *feature_list;
744 if (! font_info->gsub)
746 if (load_gsub (font_info) != HB_Err_Ok)
749 if (HB_GSUB_Select_Script (font_info->gsub, spec->script, &script)
754 if (HB_GSUB_Select_Language (font_info->gsub, spec->langsys,
755 script, &langsys, &req_feature)
760 langsys = req_feature = 0xFFFF;
761 count = spec->gsub_count;
762 features = spec->gsub;
766 if (! font_info->gpos)
768 if (load_gpos (font_info) != HB_Err_Ok)
771 if (HB_GPOS_Select_Script (font_info->gpos, spec->script, &script)
776 if (HB_GPOS_Select_Language (font_info->gpos, spec->langsys,
777 script, &langsys, &req_feature)
782 langsys = req_feature = 0xFFFF;
783 count = spec->gpos_count;
784 features = spec->gpos;
787 for (preordered = 0; preordered < count; preordered++)
788 if (features[preordered] == 0)
790 if ((gsubp ? HB_GSUB_Query_Features (font_info->gsub, script, langsys,
792 : HB_GPOS_Query_Features (font_info->gpos, script, langsys,
799 for (i = 0; feature_list[i]; i++);
802 info->indices = malloc (sizeof (FT_UShort) * ((req_feature != 0xFFFF) + i));
804 if (req_feature != 0xFFFF)
805 info->indices[i++] = req_feature;
806 for (j = 0; j < preordered; j++)
807 if ((gsubp ? HB_GSUB_Select_Feature (font_info->gsub, features[j],
808 script, langsys, &index)
809 : HB_GPOS_Select_Feature (font_info->gpos, features[j],
810 script, langsys, &index))
812 info->indices[i++] = index;
814 for (j = 0; feature_list[j]; j++)
816 for (k = preordered + 1; k < count; k++)
817 if (feature_list[j] == features[k])
821 ? HB_GSUB_Select_Feature (font_info->gsub, feature_list[j],
822 script, langsys, &index)
823 : HB_GPOS_Select_Feature (font_info->gpos, feature_list[j],
824 script, langsys, &index))
826 info->indices[i++] = index;
832 setup_otf_spec (MFLTFont *font, MFLTOtfSpec *spec)
834 FontInfoHB *font_info = (FontInfoHB *) font;
837 if (spec->gsub_count + spec->gpos_count == 0)
839 ginfo = mplist_get (font_info->otf_spec_cache, spec->sym);
841 return (ginfo->gsub.count + ginfo->gpos.count > 0 ? ginfo : NULL);
842 ginfo = calloc (1, sizeof (GsubGposInfo));
843 mplist_push (font_info->otf_spec_cache, spec->sym, ginfo);
844 setup_features (1, font_info, spec, &(ginfo->gsub));
845 setup_features (0, font_info, spec, &(ginfo->gpos));
850 drive_otf (MFLTFont *font, MFLTOtfSpec *spec,
851 MFLTGlyphString *in, int from, int to,
852 MFLTGlyphString *out, MFLTGlyphAdjustment *adjustment)
854 FontInfoHB *font_info = (FontInfoHB *) font;
859 HB_UShort *apply_order_save;
860 HB_UShort apply_count_save;
861 int gpos_applied = 0;
868 if (hb_buffer_new (&buf) != FT_Err_Ok)
870 for (i = from; i < to; i++)
872 if (hb_buffer_add_glyph (buf, in->glyphs[i].code, 0, i) != FT_Err_Ok)
875 ginfo = setup_otf_spec (font, spec);
878 if (ginfo->gsub.count > 0)
880 if (! font_info->gdef
881 && load_gdef (font_info) != HB_Err_Ok)
883 apply_order_save = font_info->gsub->FeatureList.ApplyOrder;
884 apply_count_save = font_info->gsub->FeatureList.ApplyCount;
885 font_info->gsub->FeatureList.ApplyOrder = ginfo->gsub.indices;
886 font_info->gsub->FeatureList.ApplyCount = ginfo->gsub.count;
887 err = HB_GSUB_Apply_String (font_info->gsub, buf);
888 font_info->gsub->FeatureList.ApplyOrder = apply_order_save;
889 font_info->gsub->FeatureList.ApplyCount = apply_count_save;
890 if (err != HB_Err_Ok && err != HB_Err_Not_Covered)
892 if (out->used + buf->in_length > out->allocated)
896 if (ginfo->gpos.count > 0
897 && (font_info->gpos || load_gpos (font_info) == HB_Err_Ok))
899 apply_order_save = font_info->gpos->FeatureList.ApplyOrder;
900 apply_count_save = font_info->gpos->FeatureList.ApplyCount;
901 font_info->gpos->FeatureList.ApplyOrder = ginfo->gpos.indices;
902 font_info->gpos->FeatureList.ApplyCount = ginfo->gpos.count;
903 err = HB_GPOS_Apply_String (&font_info->hb_font, font_info->gpos,
904 FT_LOAD_DEFAULT, buf, FALSE, FALSE);
905 font_info->gpos->FeatureList.ApplyOrder = apply_order_save;
906 font_info->gpos->FeatureList.ApplyCount = apply_count_save;
907 if (err == HB_Err_Ok)
911 for (i = 0; i < buf->in_length; i++)
913 HB_GlyphItem hg = buf->in_string + i;
914 HB_Position pos = buf->positions + i;
917 out->glyphs[out->used] = in->glyphs[hg->cluster];
918 g = out->glyphs + out->used++;
919 if (g->code != hg->gindex)
922 g->code = hg->gindex;
925 adjustment[i].set = gpos_applied;
928 adjustment[i].xadv = pos->x_advance;
929 adjustment[i].yadv = pos->y_advance;
930 adjustment[i].xoff = pos->x_pos;
931 adjustment[i].yoff = - pos->y_pos;
932 adjustment[i].back = pos->back;
933 adjustment[i].advance_is_absolute = pos->new_advance;
940 hb_buffer_free (buf);
941 for (i = 0; i < len; i++)
942 out->glyphs[out->used++] = in->glyphs[from + i];
947 open_font (char *fontname, char **err)
949 FT_Face face = new_face (fontname, err);
950 FontInfoHB *font_info;
954 font_info = calloc (1, sizeof (FontInfoHB));
955 font_info->face = face;
956 font_info->hb_font.klass = &hb_fontClass;
957 font_info->hb_font.faceData = face;
958 font_info->hb_font.userData = NULL;
959 font_info->hb_font.x_ppem = face->size->metrics.x_ppem;
960 font_info->hb_font.x_scale = face->size->metrics.x_scale;
961 font_info->hb_font.y_scale = face->size->metrics.y_scale;
962 font_info->hb_font.y_ppem = face->size->metrics.y_ppem;
963 font_info->otf_spec_cache = mplist ();
964 return ((MFLTFont *) font_info);
968 close_font (MFLTFont *font)
970 FontInfoHB *font_info = (FontInfoHB *) font;
975 HB_Done_GDEF_Table (font_info->gdef);
976 free (font_info->gdef_stream.base);
979 HB_Done_GSUB_Table (font_info->gsub);
981 HB_Done_GPOS_Table (font_info->gpos);
982 FT_Done_Face ((FT_Face) (font_info->hb_font.faceData));
983 for (p = font_info->otf_spec_cache; mplist_key (p) != Mnil;
986 GsubGposInfo *ginfo = mplist_value (p);
988 if (ginfo->gsub.count > 0)
989 free (ginfo->gsub.indices);
990 if (ginfo->gpos.count > 0)
991 free (ginfo->gpos.indices);
993 m17n_object_unref (font_info->otf_spec_cache);
999 #else /* (defined (FLT_PANGO) */
1004 PangoOTRuleset *ruleset;
1014 PangoFontMap *fontmap;
1015 PangoContext *context;
1016 PangoFcFont *pango_font;
1017 MPlist *otf_spec_cache;
1021 get_glyph_id (MFLTFont *font, MFLTGlyphString *gstring, int from, int to)
1023 FontInfoPango *font_info = (FontInfoPango *) font;
1025 for (; from < to; from++)
1027 MFLTGlyph *g = gstring->glyphs + from;
1030 && ! (g->code = pango_fc_font_get_glyph (font_info->pango_font,
1038 #define PANGO_SCALE_TO_26_6 (PANGO_SCALE / (1<<6))
1041 get_metrics (MFLTFont *font, MFLTGlyphString *gstring, int from, int to)
1043 FontInfoPango *font_info = (FontInfoPango *) font;
1046 for (i = from; i < to; i++)
1048 MFLTGlyph *g = gstring->glyphs + from;
1052 PangoRectangle inc, logical;
1054 pango_font_get_glyph_extents (PANGO_FONT (font_info->pango_font),
1055 gstring->glyphs[i].code, &inc, &logical);
1056 g->lbearing = inc.x / PANGO_SCALE_TO_26_6;
1057 g->rbearing = (inc.x + inc.width) / PANGO_SCALE_TO_26_6;
1058 g->xadv = logical.width / PANGO_SCALE_TO_26_6;
1060 g->ascent = - inc.y / PANGO_SCALE_TO_26_6;
1061 g->descent = (inc.height + inc.y) / PANGO_SCALE_TO_26_6;
1069 #ifndef PANGO_OT_DEFAULT_LANGUAGE
1070 #define PANGO_OT_DEFAULT_LANGUAGE ((guint) 0xFFFF)
1072 #ifndef PANGO_OT_ALL_GLYPHS
1073 #define PANGO_OT_ALL_GLYPHS ((guint) 0xFFFF)
1077 setup_features (PangoOTTableType type, FontInfoPango *font_info,
1078 MFLTOtfSpec *spec, FeatureInfo *info)
1080 int count, preordered;
1081 unsigned int *features;
1082 guint script, langsys;
1083 guint req_feature, index;
1084 guint *feature_list;
1087 PangoOTInfo *ot_info;
1089 face = pango_fc_font_lock_face (font_info->pango_font);
1090 ot_info = pango_ot_info_get (face);
1091 pango_fc_font_unlock_face (font_info->pango_font);
1093 if (! pango_ot_info_find_script (ot_info, type, spec->script, &script))
1097 if (! pango_ot_info_find_language (ot_info, type, script,
1099 &langsys, &req_feature))
1104 langsys = PANGO_OT_DEFAULT_LANGUAGE;
1105 req_feature = 0xFFFF;
1107 if (type == PANGO_OT_TABLE_GSUB)
1109 count = spec->gsub_count;
1110 features = spec->gsub;
1114 count = spec->gpos_count;
1115 features = spec->gpos;
1117 feature_list = NULL;
1118 for (preordered = 0; preordered < count; preordered++)
1119 if (features[preordered] == 0)
1121 feature_list = pango_ot_info_list_features (ot_info, type, 0,
1128 for (i = 0; feature_list[i]; i++);
1131 info->indices = malloc (sizeof (guint) * ((req_feature != 0xFFFF) + i));
1133 if (req_feature != 0xFFFF)
1134 info->indices[i++] = req_feature;
1135 for (j = 0; j < preordered; j++)
1136 if (pango_ot_info_find_feature (ot_info, type, features[j],
1137 script, langsys, &index))
1138 info->indices[i++] = index;
1140 for (j = 0; feature_list[j]; j++)
1142 for (k = preordered + 1; k < count; k++)
1143 if (feature_list[j] == features[k])
1146 && pango_ot_info_find_feature (ot_info, type, feature_list[j],
1147 script, langsys, &index))
1148 info->indices[i++] = index;
1151 info->ruleset = pango_ot_ruleset_new (ot_info);
1153 for (i = 0; i < info->count; i++)
1154 pango_ot_ruleset_add_feature (info->ruleset, type, info->indices[i],
1155 PANGO_OT_ALL_GLYPHS);
1157 for (i = info->count - 1; i >= 0; i--)
1158 pango_ot_ruleset_add_feature (info->ruleset, type, info->indices[i],
1159 PANGO_OT_ALL_GLYPHS);
1164 setup_otf_spec (FontInfoPango *font_info, MFLTOtfSpec *spec)
1166 GsubGposInfo *ginfo;
1168 if (spec->gsub_count + spec->gpos_count == 0)
1170 ginfo = mplist_get (font_info->otf_spec_cache, spec->sym);
1172 return (ginfo->gsub.count + ginfo->gpos.count > 0 ? ginfo : NULL);
1173 ginfo = calloc (1, sizeof (GsubGposInfo));
1174 mplist_push (font_info->otf_spec_cache, spec->sym, ginfo);
1175 setup_features (PANGO_OT_TABLE_GSUB, font_info, spec, &(ginfo->gsub));
1176 setup_features (PANGO_OT_TABLE_GPOS, font_info, spec, &(ginfo->gpos));
1181 drive_otf (MFLTFont *font, MFLTOtfSpec *spec,
1182 MFLTGlyphString *in, int from, int to,
1183 MFLTGlyphString *out, MFLTGlyphAdjustment *adjustment)
1185 FontInfoPango *font_info = (FontInfoPango *) font;
1186 PangoOTBuffer *buffer;
1187 GsubGposInfo *ginfo;
1188 PangoGlyphString *glyphs;
1191 buffer = pango_ot_buffer_new (font_info->pango_font);
1192 for (i = from; i < to; i++)
1193 pango_ot_buffer_add_glyph (buffer, in->glyphs[i].code, 0, i);
1194 ginfo = setup_otf_spec (font_info, spec);
1197 if (ginfo->gsub.count > 0)
1198 pango_ot_ruleset_substitute (ginfo->gsub.ruleset, buffer);
1199 if (ginfo->gpos.count > 0)
1200 pango_ot_ruleset_position (ginfo->gpos.ruleset, buffer);
1201 glyphs = pango_glyph_string_new ();
1202 pango_ot_buffer_output (buffer, glyphs);
1203 for (i = 0; i < glyphs->num_glyphs; i++)
1205 PangoGlyphInfo *glyph_info = glyphs->glyphs + i;
1208 out->glyphs[out->used] = in->glyphs[glyphs->log_clusters[i]];
1209 g = out->glyphs + out->used++;
1210 if (g->code != glyph_info->glyph)
1213 g->code = glyph_info->glyph;
1216 g->xoff = glyph_info->geometry.x_offset / PANGO_SCALE_TO_26_6;
1217 g->yoff = glyph_info->geometry.y_offset / PANGO_SCALE_TO_26_6;
1218 g->xadv = glyph_info->geometry.width / PANGO_SCALE_TO_26_6;
1220 adjustment[i].set = 0;
1222 pango_ot_buffer_destroy (buffer);
1223 pango_glyph_string_free (glyphs);
1227 pango_ot_buffer_destroy (buffer);
1228 for (i = from; i < to; i++)
1229 out->glyphs[out->used++] = in->glyphs[i];
1235 open_font (char *fontname, char **err)
1237 FontInfoPango *font_info = NULL;
1238 PangoFontMap *fontmap;
1239 PangoContext *context;
1240 PangoFontDescription *desc;
1241 PangoFont *pango_font;
1246 if (parse_font_name (fontname, &family, &size, err) < 0)
1248 desc = pango_font_description_new ();
1249 pango_font_description_set_family (desc, family);
1251 pango_size = size * PANGO_SCALE;
1252 pango_font_description_set_absolute_size (desc, pango_size);
1254 fontmap = pango_ft2_font_map_new ();
1255 context = pango_context_new ();
1256 pango_context_set_font_map (context, fontmap);
1257 pango_font = pango_context_load_font (context, desc);
1258 pango_font_description_free (desc);
1261 font_info = calloc (1, sizeof (FontInfoPango));
1262 font_info->fontmap = fontmap;
1263 font_info->context = context;
1264 font_info->pango_font = PANGO_FC_FONT (pango_font);
1265 font_info->otf_spec_cache = mplist ();
1269 g_object_unref (context);
1270 g_object_unref (fontmap);
1272 return (MFLTFont *) font_info;
1276 close_font (MFLTFont *font)
1278 FontInfoPango *font_info = (FontInfoPango *) font;
1280 g_object_unref (font_info->context);
1281 g_object_unref (font_info->fontmap);
1289 run_flt (MText *mt, int from, int to, MFLTFont *font, char *flt_name)
1291 MDrawControl control;
1293 memset (&control, 0, sizeof (MDrawControl));
1294 control.two_dimensional = 1;
1295 control.enable_bidi = 1;
1296 control.anti_alias = 1;
1297 /*control.disable_caching = 1;*/
1298 mtext_put_prop (mt, from, to, Mfont, font->font);
1299 mdraw_text_extents (frame, mt, from, to, &control, NULL, NULL, NULL);
1306 run_flt (MText *mt, int from, int to, MFLTFont *font, char *flt_name)
1308 static MFLT *flt = NULL;
1309 MCharTable *coverage;
1310 static MFLTGlyphString gstring;
1313 && ! (flt = mflt_get (flt_name)))
1315 fprintf (stderr, "Invalid FLT name: %s\n", flt_name);
1318 coverage = mflt_coverage (flt);
1323 for (; from < to; from++)
1324 if (mchartable_lookup (coverage, mtext_ref_char (mt, from)))
1326 for (i = from + 1; i < to; i++)
1327 if (! mchartable_lookup (coverage, mtext_ref_char (mt, i)))
1334 if (gstring.allocated < len)
1336 gstring.allocated = len * 2;
1337 gstring.glyphs = realloc (gstring.glyphs,
1338 sizeof (MFLTGlyph) * len * 2);
1340 gstring.glyph_size = sizeof (MFLTGlyph);
1341 for (i = 0; i < len; i++)
1342 gstring.glyphs[i].c = mtext_ref_char (mt, from + i);
1344 i = mflt_run (&gstring, 0, len, font, flt);
1356 main (int argc, char **argv)
1358 char *font_name, *flt_name;
1367 fprintf (stderr, "Usage: flt FONT-NAME FLT-NAME < TEXT-FILE\n");
1371 font_name = argv[1];
1374 FT_Init_FreeType (&ft_library);
1376 font = open_font (font_name, &err);
1379 fprintf (stderr, "Font error: %s: %s\n", argv[1], err);
1382 font->get_glyph_id = get_glyph_id;
1383 font->get_metrics = get_metrics;
1384 font->drive_otf = drive_otf;
1387 buf = malloc (4096);
1388 while ((j = fread (buf + i, 1, 4096, stdin)) == 4096)
1391 buf = realloc (buf, i + 4096);
1393 mt = mtext_from_data (buf, i, MTEXT_FORMAT_UTF_8);
1394 len = mtext_len (mt);
1395 for (i = 0, j = mtext_character (mt, i, len, '\n'); i < len;
1396 i = j + 1, j = mtext_character (mt, i, len, '\n'))
1402 to = run_flt (mt, i, j, font, flt_name);
1405 fprintf (stderr, "Error in FLT processing.\n");
1410 m17n_object_unref (mt);