aboutsummaryrefslogtreecommitdiffhomepage
path: root/third_party/harfbuzz/contrib/harfbuzz-freetype.c
blob: a2962df48f60aa668c5b59668aff1ce690cd3a8f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
#include <stdint.h>

#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_TRUETYPE_TABLES_H

#if 0
#include <freetype/freetype.h>
#include <freetype/tttables.h>
#endif

#include <harfbuzz-shaper.h>
#include "harfbuzz-unicode.h"

static HB_Bool
hb_freetype_string_to_glyphs(HB_Font font,
                             const HB_UChar16 *chars, hb_uint32 len,
                             HB_Glyph *glyphs, hb_uint32 *numGlyphs,
                             HB_Bool is_rtl) {
  FT_Face face = (FT_Face) font->userData;
  if (len > *numGlyphs)
    return 0;

  size_t i = 0, j = 0;
  while (i < len) {
    const uint32_t cp = utf16_to_code_point(chars, len, &i);
    glyphs[j++] = FT_Get_Char_Index(face, cp);
  }

  *numGlyphs = j;

  return 1;
}

static void
hb_freetype_advances_get(HB_Font font, const HB_Glyph *glyphs, hb_uint32 len,
                         HB_Fixed *advances, int flags) {
  FT_Face face = (FT_Face) font->userData;

  hb_uint32 i;
  for (i = 0; i < len; ++i) {
    const FT_Error error = FT_Load_Glyph(face, glyphs[i], FT_LOAD_DEFAULT);
    if (error) {
      advances[i] = 0;
      continue;
    }

    advances[i] = face->glyph->advance.x;
  }
}

static HB_Bool
hb_freetype_can_render(HB_Font font, const HB_UChar16 *chars, hb_uint32 len) {
  FT_Face face = (FT_Face)font->userData;

  size_t i = 0;
  while (i < len) {
    const uint32_t cp = utf16_to_code_point(chars, len, &i);
    if (FT_Get_Char_Index(face, cp) == 0)
      return 0;
  }

  return 1;
}

static HB_Error
hb_freetype_outline_point_get(HB_Font font, HB_Glyph glyph, int flags,
                              hb_uint32 point, HB_Fixed *xpos, HB_Fixed *ypos,
                              hb_uint32 *n_points) {
  HB_Error error = HB_Err_Ok;
  FT_Face face = (FT_Face) font->userData;

  int load_flags = (flags & HB_ShaperFlag_UseDesignMetrics) ? FT_LOAD_NO_HINTING : FT_LOAD_DEFAULT;

  if ((error = (HB_Error) FT_Load_Glyph(face, glyph, load_flags)))
    return error;

  if (face->glyph->format != ft_glyph_format_outline)
    return (HB_Error)HB_Err_Invalid_SubTable;

  *n_points = face->glyph->outline.n_points;
  if (!(*n_points))
    return HB_Err_Ok;

  if (point > *n_points)
    return (HB_Error)HB_Err_Invalid_SubTable;

  *xpos = face->glyph->outline.points[point].x;
  *ypos = face->glyph->outline.points[point].y;

  return HB_Err_Ok;
}

static void
hb_freetype_glyph_metrics_get(HB_Font font, HB_Glyph glyph,
                              HB_GlyphMetrics *metrics) {
  FT_Face face = (FT_Face) font->userData;

  const FT_Error error = FT_Load_Glyph(face, glyph, FT_LOAD_DEFAULT);
  if (error) {
    metrics->x = metrics->y = metrics->width = metrics->height = 0;
    metrics->xOffset = metrics->yOffset = 0;
    return;
  }

  const FT_Glyph_Metrics *ftmetrics = &face->glyph->metrics;
  metrics->width = ftmetrics->width;
  metrics->height = ftmetrics->height;
  metrics->x = ftmetrics->horiAdvance;
  metrics->y = 0;  // unclear what this is
  metrics->xOffset = ftmetrics->horiBearingX;
  metrics->yOffset = ftmetrics->horiBearingY;
}

static HB_Fixed
hb_freetype_font_metric_get(HB_Font font, HB_FontMetric metric) {
  FT_Face face = (FT_Face) font->userData;

  switch (metric) {
  case HB_FontAscent:
    // Note that we aren't scanning the VDMX table which we probably would in
    // an ideal world.
    return face->ascender;
  default:
    return 0;
  }
}

const HB_FontClass hb_freetype_class = {
  hb_freetype_string_to_glyphs,
  hb_freetype_advances_get,
  hb_freetype_can_render,
  hb_freetype_outline_point_get,
  hb_freetype_glyph_metrics_get,
  hb_freetype_font_metric_get,
};

HB_Error
hb_freetype_table_sfnt_get(void *voidface, const HB_Tag tag, HB_Byte *buffer, HB_UInt *len) {
  FT_Face face = (FT_Face) voidface;
  FT_ULong ftlen = *len;

  if (!FT_IS_SFNT(face))
    return HB_Err_Invalid_Argument;

  const FT_Error error = FT_Load_Sfnt_Table(face, tag, 0, buffer, &ftlen);
  *len = ftlen;
  return (HB_Error) error;
}