1/*
2 * Copyright �� 2009  Red Hat, Inc.
3 * Copyright �� 2011  Google, Inc.
4 *
5 *  This is part of HarfBuzz, a text shaping library.
6 *
7 * Permission is hereby granted, without written agreement and without
8 * license or royalty fees, to use, copy, modify, and distribute this
9 * software and its documentation for any purpose, provided that the
10 * above copyright notice and the following two paragraphs appear in
11 * all copies of this software.
12 *
13 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
14 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
15 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
16 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
17 * DAMAGE.
18 *
19 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
20 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
21 * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
22 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
23 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
24 *
25 * Red Hat Author(s): Behdad Esfahbod
26 * Google Author(s): Behdad Esfahbod
27 */
28
29#ifndef HB_FONT_PRIVATE_HH
30#define HB_FONT_PRIVATE_HH
31
32#include "hb-private.hh"
33
34#include "hb-object-private.hh"
35#include "hb-face-private.hh"
36#include "hb-shaper-private.hh"
37
38
39
40/*
41 * hb_font_funcs_t
42 */
43
44#define HB_FONT_FUNCS_IMPLEMENT_CALLBACKS \
45  HB_FONT_FUNC_IMPLEMENT (font_h_extents) \
46  HB_FONT_FUNC_IMPLEMENT (font_v_extents) \
47  HB_FONT_FUNC_IMPLEMENT (nominal_glyph) \
48  HB_FONT_FUNC_IMPLEMENT (variation_glyph) \
49  HB_FONT_FUNC_IMPLEMENT (glyph_h_advance) \
50  HB_FONT_FUNC_IMPLEMENT (glyph_v_advance) \
51  HB_FONT_FUNC_IMPLEMENT (glyph_h_origin) \
52  HB_FONT_FUNC_IMPLEMENT (glyph_v_origin) \
53  HB_FONT_FUNC_IMPLEMENT (glyph_h_kerning) \
54  HB_FONT_FUNC_IMPLEMENT (glyph_v_kerning) \
55  HB_FONT_FUNC_IMPLEMENT (glyph_extents) \
56  HB_FONT_FUNC_IMPLEMENT (glyph_contour_point) \
57  HB_FONT_FUNC_IMPLEMENT (glyph_name) \
58  HB_FONT_FUNC_IMPLEMENT (glyph_from_name) \
59  /* ^--- Add new callbacks here */
60
61struct hb_font_funcs_t {
62  hb_object_header_t header;
63  ASSERT_POD ();
64
65  hb_bool_t immutable;
66
67  struct {
68#define HB_FONT_FUNC_IMPLEMENT(name) void *name;
69    HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
70#undef HB_FONT_FUNC_IMPLEMENT
71  } user_data;
72
73  struct {
74#define HB_FONT_FUNC_IMPLEMENT(name) hb_destroy_func_t name;
75    HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
76#undef HB_FONT_FUNC_IMPLEMENT
77  } destroy;
78
79  /* Don't access these directly.  Call font->get_*() instead. */
80  union get_t {
81    struct get_funcs_t {
82#define HB_FONT_FUNC_IMPLEMENT(name) hb_font_get_##name##_func_t name;
83      HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
84#undef HB_FONT_FUNC_IMPLEMENT
85    } f;
86    void (*array[VAR]) (void);
87  } get;
88};
89
90
91
92/*
93 * hb_font_t
94 */
95
96struct hb_font_t {
97  hb_object_header_t header;
98  ASSERT_POD ();
99
100  hb_bool_t immutable;
101
102  hb_font_t *parent;
103  hb_face_t *face;
104
105  int x_scale;
106  int y_scale;
107
108  unsigned int x_ppem;
109  unsigned int y_ppem;
110
111  /* Font variation coordinates. */
112  unsigned int num_coords;
113  int *coords;
114
115  hb_font_funcs_t   *klass;
116  void              *user_data;
117  hb_destroy_func_t  destroy;
118
119  struct hb_shaper_data_t shaper_data;
120
121
122  /* Convert from font-space to user-space */
123  inline int dir_scale (hb_direction_t direction)
124  { return HB_DIRECTION_IS_VERTICAL(direction) ? y_scale : x_scale; }
125  inline hb_position_t em_scale_x (int16_t v) { return em_scale (v, x_scale); }
126  inline hb_position_t em_scale_y (int16_t v) { return em_scale (v, y_scale); }
127  inline hb_position_t em_scalef_x (float v) { return em_scalef (v, this->x_scale); }
128  inline hb_position_t em_scalef_y (float v) { return em_scalef (v, this->y_scale); }
129  inline hb_position_t em_scale_dir (int16_t v, hb_direction_t direction)
130  { return em_scale (v, dir_scale (direction)); }
131
132  /* Convert from parent-font user-space to our user-space */
133  inline hb_position_t parent_scale_x_distance (hb_position_t v) {
134    if (unlikely (parent && parent->x_scale != x_scale))
135      return (hb_position_t) (v * (int64_t) this->x_scale / this->parent->x_scale);
136    return v;
137  }
138  inline hb_position_t parent_scale_y_distance (hb_position_t v) {
139    if (unlikely (parent && parent->y_scale != y_scale))
140      return (hb_position_t) (v * (int64_t) this->y_scale / this->parent->y_scale);
141    return v;
142  }
143  inline hb_position_t parent_scale_x_position (hb_position_t v) {
144    return parent_scale_x_distance (v);
145  }
146  inline hb_position_t parent_scale_y_position (hb_position_t v) {
147    return parent_scale_y_distance (v);
148  }
149
150  inline void parent_scale_distance (hb_position_t *x, hb_position_t *y) {
151    *x = parent_scale_x_distance (*x);
152    *y = parent_scale_y_distance (*y);
153  }
154  inline void parent_scale_position (hb_position_t *x, hb_position_t *y) {
155    *x = parent_scale_x_position (*x);
156    *y = parent_scale_y_position (*y);
157  }
158
159
160  /* Public getters */
161
162  HB_INTERNAL bool has_func (unsigned int i);
163
164  /* has_* ... */
165#define HB_FONT_FUNC_IMPLEMENT(name) \
166  bool \
167  has_##name##_func (void) \
168  { \
169    hb_font_funcs_t *funcs = this->klass; \
170    unsigned int i = offsetof (hb_font_funcs_t::get_t::get_funcs_t, name) / sizeof (funcs->get.array[0]); \
171    return has_func (i); \
172  }
173  HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
174#undef HB_FONT_FUNC_IMPLEMENT
175
176  inline hb_bool_t get_font_h_extents (hb_font_extents_t *extents)
177  {
178    memset (extents, 0, sizeof (*extents));
179    return klass->get.f.font_h_extents (this, user_data,
180                                        extents,
181                                        klass->user_data.font_h_extents);
182  }
183  inline hb_bool_t get_font_v_extents (hb_font_extents_t *extents)
184  {
185    memset (extents, 0, sizeof (*extents));
186    return klass->get.f.font_v_extents (this, user_data,
187                                        extents,
188                                        klass->user_data.font_v_extents);
189  }
190
191  inline bool has_glyph (hb_codepoint_t unicode)
192  {
193    hb_codepoint_t glyph;
194    return get_nominal_glyph (unicode, &glyph);
195  }
196
197  inline hb_bool_t get_nominal_glyph (hb_codepoint_t unicode,
198                                      hb_codepoint_t *glyph)
199  {
200    *glyph = 0;
201    return klass->get.f.nominal_glyph (this, user_data,
202                                       unicode, glyph,
203                                       klass->user_data.nominal_glyph);
204  }
205
206  inline hb_bool_t get_variation_glyph (hb_codepoint_t unicode, hb_codepoint_t variation_selector,
207                                        hb_codepoint_t *glyph)
208  {
209    *glyph = 0;
210    return klass->get.f.variation_glyph (this, user_data,
211                                         unicode, variation_selector, glyph,
212                                         klass->user_data.variation_glyph);
213  }
214
215  inline hb_position_t get_glyph_h_advance (hb_codepoint_t glyph)
216  {
217    return klass->get.f.glyph_h_advance (this, user_data,
218                                         glyph,
219                                         klass->user_data.glyph_h_advance);
220  }
221
222  inline hb_position_t get_glyph_v_advance (hb_codepoint_t glyph)
223  {
224    return klass->get.f.glyph_v_advance (this, user_data,
225                                         glyph,
226                                         klass->user_data.glyph_v_advance);
227  }
228
229  inline hb_bool_t get_glyph_h_origin (hb_codepoint_t glyph,
230                                       hb_position_t *x, hb_position_t *y)
231  {
232    *x = *y = 0;
233    return klass->get.f.glyph_h_origin (this, user_data,
234                                        glyph, x, y,
235                                        klass->user_data.glyph_h_origin);
236  }
237
238  inline hb_bool_t get_glyph_v_origin (hb_codepoint_t glyph,
239                                       hb_position_t *x, hb_position_t *y)
240  {
241    *x = *y = 0;
242    return klass->get.f.glyph_v_origin (this, user_data,
243                                        glyph, x, y,
244                                        klass->user_data.glyph_v_origin);
245  }
246
247  inline hb_position_t get_glyph_h_kerning (hb_codepoint_t left_glyph, hb_codepoint_t right_glyph)
248  {
249    return klass->get.f.glyph_h_kerning (this, user_data,
250                                         left_glyph, right_glyph,
251                                         klass->user_data.glyph_h_kerning);
252  }
253
254  inline hb_position_t get_glyph_v_kerning (hb_codepoint_t top_glyph, hb_codepoint_t bottom_glyph)
255  {
256    return klass->get.f.glyph_v_kerning (this, user_data,
257                                         top_glyph, bottom_glyph,
258                                         klass->user_data.glyph_v_kerning);
259  }
260
261  inline hb_bool_t get_glyph_extents (hb_codepoint_t glyph,
262                                      hb_glyph_extents_t *extents)
263  {
264    memset (extents, 0, sizeof (*extents));
265    return klass->get.f.glyph_extents (this, user_data,
266                                       glyph,
267                                       extents,
268                                       klass->user_data.glyph_extents);
269  }
270
271  inline hb_bool_t get_glyph_contour_point (hb_codepoint_t glyph, unsigned int point_index,
272                                            hb_position_t *x, hb_position_t *y)
273  {
274    *x = *y = 0;
275    return klass->get.f.glyph_contour_point (this, user_data,
276                                             glyph, point_index,
277                                             x, y,
278                                             klass->user_data.glyph_contour_point);
279  }
280
281  inline hb_bool_t get_glyph_name (hb_codepoint_t glyph,
282                                   char *name, unsigned int size)
283  {
284    if (size) *name = '\0';
285    return klass->get.f.glyph_name (this, user_data,
286                                    glyph,
287                                    name, size,
288                                    klass->user_data.glyph_name);
289  }
290
291  inline hb_bool_t get_glyph_from_name (const char *name, int len, /* -1 means nul-terminated */
292                                        hb_codepoint_t *glyph)
293  {
294    *glyph = 0;
295    if (len == -1) len = strlen (name);
296    return klass->get.f.glyph_from_name (this, user_data,
297                                         name, len,
298                                         glyph,
299                                         klass->user_data.glyph_from_name);
300  }
301
302
303  /* A bit higher-level, and with fallback */
304
305  inline void get_h_extents_with_fallback (hb_font_extents_t *extents)
306  {
307    if (!get_font_h_extents (extents))
308    {
309      extents->ascender = y_scale * .8;
310      extents->descender = extents->ascender - y_scale;
311      extents->line_gap = 0;
312    }
313  }
314  inline void get_v_extents_with_fallback (hb_font_extents_t *extents)
315  {
316    if (!get_font_v_extents (extents))
317    {
318      extents->ascender = x_scale / 2;
319      extents->descender = extents->ascender - x_scale;
320      extents->line_gap = 0;
321    }
322  }
323
324  inline void get_extents_for_direction (hb_direction_t direction,
325                                         hb_font_extents_t *extents)
326  {
327    if (likely (HB_DIRECTION_IS_HORIZONTAL (direction)))
328      get_h_extents_with_fallback (extents);
329    else
330      get_v_extents_with_fallback (extents);
331  }
332
333  inline void get_glyph_advance_for_direction (hb_codepoint_t glyph,
334                                               hb_direction_t direction,
335                                               hb_position_t *x, hb_position_t *y)
336  {
337    if (likely (HB_DIRECTION_IS_HORIZONTAL (direction))) {
338      *x = get_glyph_h_advance (glyph);
339      *y = 0;
340    } else {
341      *x = 0;
342      *y = get_glyph_v_advance (glyph);
343    }
344  }
345
346  inline void guess_v_origin_minus_h_origin (hb_codepoint_t glyph,
347                                             hb_position_t *x, hb_position_t *y)
348  {
349    *x = get_glyph_h_advance (glyph) / 2;
350
351    /* TODO cache this somehow?! */
352    hb_font_extents_t extents;
353    get_h_extents_with_fallback (&extents);
354    *y = extents.ascender;
355  }
356
357  inline void get_glyph_h_origin_with_fallback (hb_codepoint_t glyph,
358                                                hb_position_t *x, hb_position_t *y)
359  {
360    if (!get_glyph_h_origin (glyph, x, y) &&
361         get_glyph_v_origin (glyph, x, y))
362    {
363      hb_position_t dx, dy;
364      guess_v_origin_minus_h_origin (glyph, &dx, &dy);
365      *x -= dx; *y -= dy;
366    }
367  }
368  inline void get_glyph_v_origin_with_fallback (hb_codepoint_t glyph,
369                                                hb_position_t *x, hb_position_t *y)
370  {
371    if (!get_glyph_v_origin (glyph, x, y) &&
372         get_glyph_h_origin (glyph, x, y))
373    {
374      hb_position_t dx, dy;
375      guess_v_origin_minus_h_origin (glyph, &dx, &dy);
376      *x += dx; *y += dy;
377    }
378  }
379
380  inline void get_glyph_origin_for_direction (hb_codepoint_t glyph,
381                                              hb_direction_t direction,
382                                              hb_position_t *x, hb_position_t *y)
383  {
384    if (likely (HB_DIRECTION_IS_HORIZONTAL (direction)))
385      get_glyph_h_origin_with_fallback (glyph, x, y);
386    else
387      get_glyph_v_origin_with_fallback (glyph, x, y);
388  }
389
390  inline void add_glyph_h_origin (hb_codepoint_t glyph,
391                                  hb_position_t *x, hb_position_t *y)
392  {
393    hb_position_t origin_x, origin_y;
394
395    get_glyph_h_origin_with_fallback (glyph, &origin_x, &origin_y);
396
397    *x += origin_x;
398    *y += origin_y;
399  }
400  inline void add_glyph_v_origin (hb_codepoint_t glyph,
401                                  hb_position_t *x, hb_position_t *y)
402  {
403    hb_position_t origin_x, origin_y;
404
405    get_glyph_v_origin_with_fallback (glyph, &origin_x, &origin_y);
406
407    *x += origin_x;
408    *y += origin_y;
409  }
410  inline void add_glyph_origin_for_direction (hb_codepoint_t glyph,
411                                              hb_direction_t direction,
412                                              hb_position_t *x, hb_position_t *y)
413  {
414    hb_position_t origin_x, origin_y;
415
416    get_glyph_origin_for_direction (glyph, direction, &origin_x, &origin_y);
417
418    *x += origin_x;
419    *y += origin_y;
420  }
421
422  inline void subtract_glyph_h_origin (hb_codepoint_t glyph,
423                                       hb_position_t *x, hb_position_t *y)
424  {
425    hb_position_t origin_x, origin_y;
426
427    get_glyph_h_origin_with_fallback (glyph, &origin_x, &origin_y);
428
429    *x -= origin_x;
430    *y -= origin_y;
431  }
432  inline void subtract_glyph_v_origin (hb_codepoint_t glyph,
433                                       hb_position_t *x, hb_position_t *y)
434  {
435    hb_position_t origin_x, origin_y;
436
437    get_glyph_v_origin_with_fallback (glyph, &origin_x, &origin_y);
438
439    *x -= origin_x;
440    *y -= origin_y;
441  }
442  inline void subtract_glyph_origin_for_direction (hb_codepoint_t glyph,
443                                                   hb_direction_t direction,
444                                                   hb_position_t *x, hb_position_t *y)
445  {
446    hb_position_t origin_x, origin_y;
447
448    get_glyph_origin_for_direction (glyph, direction, &origin_x, &origin_y);
449
450    *x -= origin_x;
451    *y -= origin_y;
452  }
453
454  inline void get_glyph_kerning_for_direction (hb_codepoint_t first_glyph, hb_codepoint_t second_glyph,
455                                               hb_direction_t direction,
456                                               hb_position_t *x, hb_position_t *y)
457  {
458    if (likely (HB_DIRECTION_IS_HORIZONTAL (direction))) {
459      *x = get_glyph_h_kerning (first_glyph, second_glyph);
460      *y = 0;
461    } else {
462      *x = 0;
463      *y = get_glyph_v_kerning (first_glyph, second_glyph);
464    }
465  }
466
467  inline hb_bool_t get_glyph_extents_for_origin (hb_codepoint_t glyph,
468                                                 hb_direction_t direction,
469                                                 hb_glyph_extents_t *extents)
470  {
471    hb_bool_t ret = get_glyph_extents (glyph, extents);
472
473    if (ret)
474      subtract_glyph_origin_for_direction (glyph, direction, &extents->x_bearing, &extents->y_bearing);
475
476    return ret;
477  }
478
479  inline hb_bool_t get_glyph_contour_point_for_origin (hb_codepoint_t glyph, unsigned int point_index,
480                                                       hb_direction_t direction,
481                                                       hb_position_t *x, hb_position_t *y)
482  {
483    hb_bool_t ret = get_glyph_contour_point (glyph, point_index, x, y);
484
485    if (ret)
486      subtract_glyph_origin_for_direction (glyph, direction, x, y);
487
488    return ret;
489  }
490
491  /* Generates gidDDD if glyph has no name. */
492  inline void
493  glyph_to_string (hb_codepoint_t glyph,
494                   char *s, unsigned int size)
495  {
496    if (get_glyph_name (glyph, s, size)) return;
497
498    if (size && snprintf (s, size, "gid%u", glyph) < 0)
499      *s = '\0';
500  }
501
502  /* Parses gidDDD and uniUUUU strings automatically. */
503  inline hb_bool_t
504  glyph_from_string (const char *s, int len, /* -1 means nul-terminated */
505                     hb_codepoint_t *glyph)
506  {
507    if (get_glyph_from_name (s, len, glyph)) return true;
508
509    if (len == -1) len = strlen (s);
510
511    /* Straight glyph index. */
512    if (hb_codepoint_parse (s, len, 10, glyph))
513      return true;
514
515    if (len > 3)
516    {
517      /* gidDDD syntax for glyph indices. */
518      if (0 == strncmp (s, "gid", 3) &&
519          hb_codepoint_parse (s + 3, len - 3, 10, glyph))
520        return true;
521
522      /* uniUUUU and other Unicode character indices. */
523      hb_codepoint_t unichar;
524      if (0 == strncmp (s, "uni", 3) &&
525          hb_codepoint_parse (s + 3, len - 3, 16, &unichar) &&
526          get_nominal_glyph (unichar, glyph))
527        return true;
528    }
529
530    return false;
531  }
532
533  inline hb_position_t em_scale (int16_t v, int scale)
534  {
535    int upem = face->get_upem ();
536    int64_t scaled = v * (int64_t) scale;
537    scaled += scaled >= 0 ? upem/2 : -upem/2; /* Round. */
538    return (hb_position_t) (scaled / upem);
539  }
540  inline hb_position_t em_scalef (float v, int scale)
541  {
542    return (hb_position_t) (v * scale / face->get_upem ());
543  }
544};
545
546#define HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS
547#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_PROTOTYPE(shaper, font);
548#include "hb-shaper-list.hh"
549#undef HB_SHAPER_IMPLEMENT
550#undef HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS
551
552
553#endif /* HB_FONT_PRIVATE_HH */
554