Home | History | Annotate | Download | only in contrib
      1 #include <stdint.h>
      2 
      3 #include <ft2build.h>
      4 #include FT_FREETYPE_H
      5 #include FT_TRUETYPE_TABLES_H
      6 
      7 #if 0
      8 #include <freetype/freetype.h>
      9 #include <freetype/tttables.h>
     10 #endif
     11 
     12 #include <harfbuzz-shaper.h>
     13 #include "harfbuzz-unicode.h"
     14 
     15 static HB_Bool
     16 hb_freetype_string_to_glyphs(HB_Font font,
     17                              const HB_UChar16 *chars, hb_uint32 len,
     18                              HB_Glyph *glyphs, hb_uint32 *numGlyphs,
     19                              HB_Bool is_rtl) {
     20   FT_Face face = (FT_Face) font->userData;
     21   if (len > *numGlyphs)
     22     return 0;
     23 
     24   size_t i = 0, j = 0;
     25   while (i < len) {
     26     const uint32_t cp = utf16_to_code_point(chars, len, &i);
     27     glyphs[j++] = FT_Get_Char_Index(face, cp);
     28   }
     29 
     30   *numGlyphs = j;
     31 
     32   return 1;
     33 }
     34 
     35 static void
     36 hb_freetype_advances_get(HB_Font font, const HB_Glyph *glyphs, hb_uint32 len,
     37                          HB_Fixed *advances, int flags) {
     38   FT_Face face = (FT_Face) font->userData;
     39 
     40   hb_uint32 i;
     41   for (i = 0; i < len; ++i) {
     42     const FT_Error error = FT_Load_Glyph(face, glyphs[i], FT_LOAD_DEFAULT);
     43     if (error) {
     44       advances[i] = 0;
     45       continue;
     46     }
     47 
     48     advances[i] = face->glyph->advance.x;
     49   }
     50 }
     51 
     52 static HB_Bool
     53 hb_freetype_can_render(HB_Font font, const HB_UChar16 *chars, hb_uint32 len) {
     54   FT_Face face = (FT_Face)font->userData;
     55 
     56   size_t i = 0;
     57   while (i < len) {
     58     const uint32_t cp = utf16_to_code_point(chars, len, &i);
     59     if (FT_Get_Char_Index(face, cp) == 0)
     60       return 0;
     61   }
     62 
     63   return 1;
     64 }
     65 
     66 static HB_Error
     67 hb_freetype_outline_point_get(HB_Font font, HB_Glyph glyph, int flags,
     68                               hb_uint32 point, HB_Fixed *xpos, HB_Fixed *ypos,
     69                               hb_uint32 *n_points) {
     70   HB_Error error = HB_Err_Ok;
     71   FT_Face face = (FT_Face) font->userData;
     72 
     73   int load_flags = (flags & HB_ShaperFlag_UseDesignMetrics) ? FT_LOAD_NO_HINTING : FT_LOAD_DEFAULT;
     74 
     75   if ((error = (HB_Error) FT_Load_Glyph(face, glyph, load_flags)))
     76     return error;
     77 
     78   if (face->glyph->format != ft_glyph_format_outline)
     79     return (HB_Error)HB_Err_Invalid_SubTable;
     80 
     81   *n_points = face->glyph->outline.n_points;
     82   if (!(*n_points))
     83     return HB_Err_Ok;
     84 
     85   if (point > *n_points)
     86     return (HB_Error)HB_Err_Invalid_SubTable;
     87 
     88   *xpos = face->glyph->outline.points[point].x;
     89   *ypos = face->glyph->outline.points[point].y;
     90 
     91   return HB_Err_Ok;
     92 }
     93 
     94 static void
     95 hb_freetype_glyph_metrics_get(HB_Font font, HB_Glyph glyph,
     96                               HB_GlyphMetrics *metrics) {
     97   FT_Face face = (FT_Face) font->userData;
     98 
     99   const FT_Error error = FT_Load_Glyph(face, glyph, FT_LOAD_DEFAULT);
    100   if (error) {
    101     metrics->x = metrics->y = metrics->width = metrics->height = 0;
    102     metrics->xOffset = metrics->yOffset = 0;
    103     return;
    104   }
    105 
    106   const FT_Glyph_Metrics *ftmetrics = &face->glyph->metrics;
    107   metrics->width = ftmetrics->width;
    108   metrics->height = ftmetrics->height;
    109   metrics->x = ftmetrics->horiAdvance;
    110   metrics->y = 0;  // unclear what this is
    111   metrics->xOffset = ftmetrics->horiBearingX;
    112   metrics->yOffset = ftmetrics->horiBearingY;
    113 }
    114 
    115 static HB_Fixed
    116 hb_freetype_font_metric_get(HB_Font font, HB_FontMetric metric) {
    117   FT_Face face = (FT_Face) font->userData;
    118 
    119   switch (metric) {
    120   case HB_FontAscent:
    121     // Note that we aren't scanning the VDMX table which we probably would in
    122     // an ideal world.
    123     return face->ascender;
    124   default:
    125     return 0;
    126   }
    127 }
    128 
    129 const HB_FontClass hb_freetype_class = {
    130   hb_freetype_string_to_glyphs,
    131   hb_freetype_advances_get,
    132   hb_freetype_can_render,
    133   hb_freetype_outline_point_get,
    134   hb_freetype_glyph_metrics_get,
    135   hb_freetype_font_metric_get,
    136 };
    137 
    138 HB_Error
    139 hb_freetype_table_sfnt_get(void *voidface, const HB_Tag tag, HB_Byte *buffer, HB_UInt *len) {
    140   FT_Face face = (FT_Face) voidface;
    141   FT_ULong ftlen = *len;
    142 
    143   if (!FT_IS_SFNT(face))
    144     return HB_Err_Invalid_Argument;
    145 
    146   const FT_Error error = FT_Load_Sfnt_Table(face, tag, 0, buffer, &ftlen);
    147   *len = ftlen;
    148   return (HB_Error) error;
    149 }
    150