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 
61 struct 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 
96 struct 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   float ptem;
112 
113   /* Font variation coordinates. */
114   unsigned int num_coords;
115   int *coords;
116 
117   hb_font_funcs_t   *klass;
118   void              *user_data;
119   hb_destroy_func_t  destroy;
120 
121   struct hb_shaper_data_t shaper_data;
122 
123 
124   /* Convert from font-space to user-space */
dir_scalehb_font_t125   inline int dir_scale (hb_direction_t direction)
126   { return HB_DIRECTION_IS_VERTICAL(direction) ? y_scale : x_scale; }
em_scale_xhb_font_t127   inline hb_position_t em_scale_x (int16_t v) { return em_scale (v, x_scale); }
em_scale_yhb_font_t128   inline hb_position_t em_scale_y (int16_t v) { return em_scale (v, y_scale); }
em_scalef_xhb_font_t129   inline hb_position_t em_scalef_x (float v) { return em_scalef (v, this->x_scale); }
em_scalef_yhb_font_t130   inline hb_position_t em_scalef_y (float v) { return em_scalef (v, this->y_scale); }
em_scale_dirhb_font_t131   inline hb_position_t em_scale_dir (int16_t v, hb_direction_t direction)
132   { return em_scale (v, dir_scale (direction)); }
133 
134   /* Convert from parent-font user-space to our user-space */
parent_scale_x_distancehb_font_t135   inline hb_position_t parent_scale_x_distance (hb_position_t v) {
136     if (unlikely (parent && parent->x_scale != x_scale))
137       return (hb_position_t) (v * (int64_t) this->x_scale / this->parent->x_scale);
138     return v;
139   }
parent_scale_y_distancehb_font_t140   inline hb_position_t parent_scale_y_distance (hb_position_t v) {
141     if (unlikely (parent && parent->y_scale != y_scale))
142       return (hb_position_t) (v * (int64_t) this->y_scale / this->parent->y_scale);
143     return v;
144   }
parent_scale_x_positionhb_font_t145   inline hb_position_t parent_scale_x_position (hb_position_t v) {
146     return parent_scale_x_distance (v);
147   }
parent_scale_y_positionhb_font_t148   inline hb_position_t parent_scale_y_position (hb_position_t v) {
149     return parent_scale_y_distance (v);
150   }
151 
parent_scale_distancehb_font_t152   inline void parent_scale_distance (hb_position_t *x, hb_position_t *y) {
153     *x = parent_scale_x_distance (*x);
154     *y = parent_scale_y_distance (*y);
155   }
parent_scale_positionhb_font_t156   inline void parent_scale_position (hb_position_t *x, hb_position_t *y) {
157     *x = parent_scale_x_position (*x);
158     *y = parent_scale_y_position (*y);
159   }
160 
161 
162   /* Public getters */
163 
164   HB_INTERNAL bool has_func (unsigned int i);
165 
166   /* has_* ... */
167 #define HB_FONT_FUNC_IMPLEMENT(name) \
168   bool \
169   has_##name##_func (void) \
170   { \
171     hb_font_funcs_t *funcs = this->klass; \
172     unsigned int i = offsetof (hb_font_funcs_t::get_t::get_funcs_t, name) / sizeof (funcs->get.array[0]); \
173     return has_func (i); \
174   }
175   HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
176 #undef HB_FONT_FUNC_IMPLEMENT
177 
get_font_h_extentshb_font_t178   inline hb_bool_t get_font_h_extents (hb_font_extents_t *extents)
179   {
180     memset (extents, 0, sizeof (*extents));
181     return klass->get.f.font_h_extents (this, user_data,
182 					extents,
183 					klass->user_data.font_h_extents);
184   }
get_font_v_extentshb_font_t185   inline hb_bool_t get_font_v_extents (hb_font_extents_t *extents)
186   {
187     memset (extents, 0, sizeof (*extents));
188     return klass->get.f.font_v_extents (this, user_data,
189 					extents,
190 					klass->user_data.font_v_extents);
191   }
192 
has_glyphhb_font_t193   inline bool has_glyph (hb_codepoint_t unicode)
194   {
195     hb_codepoint_t glyph;
196     return get_nominal_glyph (unicode, &glyph);
197   }
198 
get_nominal_glyphhb_font_t199   inline hb_bool_t get_nominal_glyph (hb_codepoint_t unicode,
200 				      hb_codepoint_t *glyph)
201   {
202     *glyph = 0;
203     return klass->get.f.nominal_glyph (this, user_data,
204 				       unicode, glyph,
205 				       klass->user_data.nominal_glyph);
206   }
207 
get_variation_glyphhb_font_t208   inline hb_bool_t get_variation_glyph (hb_codepoint_t unicode, hb_codepoint_t variation_selector,
209 					hb_codepoint_t *glyph)
210   {
211     *glyph = 0;
212     return klass->get.f.variation_glyph (this, user_data,
213 					 unicode, variation_selector, glyph,
214 					 klass->user_data.variation_glyph);
215   }
216 
get_glyph_h_advancehb_font_t217   inline hb_position_t get_glyph_h_advance (hb_codepoint_t glyph)
218   {
219     return klass->get.f.glyph_h_advance (this, user_data,
220 					 glyph,
221 					 klass->user_data.glyph_h_advance);
222   }
223 
get_glyph_v_advancehb_font_t224   inline hb_position_t get_glyph_v_advance (hb_codepoint_t glyph)
225   {
226     return klass->get.f.glyph_v_advance (this, user_data,
227 					 glyph,
228 					 klass->user_data.glyph_v_advance);
229   }
230 
get_glyph_h_originhb_font_t231   inline hb_bool_t get_glyph_h_origin (hb_codepoint_t glyph,
232 				       hb_position_t *x, hb_position_t *y)
233   {
234     *x = *y = 0;
235     return klass->get.f.glyph_h_origin (this, user_data,
236 					glyph, x, y,
237 					klass->user_data.glyph_h_origin);
238   }
239 
get_glyph_v_originhb_font_t240   inline hb_bool_t get_glyph_v_origin (hb_codepoint_t glyph,
241 				       hb_position_t *x, hb_position_t *y)
242   {
243     *x = *y = 0;
244     return klass->get.f.glyph_v_origin (this, user_data,
245 					glyph, x, y,
246 					klass->user_data.glyph_v_origin);
247   }
248 
get_glyph_h_kerninghb_font_t249   inline hb_position_t get_glyph_h_kerning (hb_codepoint_t left_glyph, hb_codepoint_t right_glyph)
250   {
251     return klass->get.f.glyph_h_kerning (this, user_data,
252 					 left_glyph, right_glyph,
253 					 klass->user_data.glyph_h_kerning);
254   }
255 
get_glyph_v_kerninghb_font_t256   inline hb_position_t get_glyph_v_kerning (hb_codepoint_t top_glyph, hb_codepoint_t bottom_glyph)
257   {
258     return klass->get.f.glyph_v_kerning (this, user_data,
259 					 top_glyph, bottom_glyph,
260 					 klass->user_data.glyph_v_kerning);
261   }
262 
get_glyph_extentshb_font_t263   inline hb_bool_t get_glyph_extents (hb_codepoint_t glyph,
264 				      hb_glyph_extents_t *extents)
265   {
266     memset (extents, 0, sizeof (*extents));
267     return klass->get.f.glyph_extents (this, user_data,
268 				       glyph,
269 				       extents,
270 				       klass->user_data.glyph_extents);
271   }
272 
get_glyph_contour_pointhb_font_t273   inline hb_bool_t get_glyph_contour_point (hb_codepoint_t glyph, unsigned int point_index,
274 					    hb_position_t *x, hb_position_t *y)
275   {
276     *x = *y = 0;
277     return klass->get.f.glyph_contour_point (this, user_data,
278 					     glyph, point_index,
279 					     x, y,
280 					     klass->user_data.glyph_contour_point);
281   }
282 
get_glyph_namehb_font_t283   inline hb_bool_t get_glyph_name (hb_codepoint_t glyph,
284 				   char *name, unsigned int size)
285   {
286     if (size) *name = '\0';
287     return klass->get.f.glyph_name (this, user_data,
288 				    glyph,
289 				    name, size,
290 				    klass->user_data.glyph_name);
291   }
292 
get_glyph_from_namehb_font_t293   inline hb_bool_t get_glyph_from_name (const char *name, int len, /* -1 means nul-terminated */
294 					hb_codepoint_t *glyph)
295   {
296     *glyph = 0;
297     if (len == -1) len = strlen (name);
298     return klass->get.f.glyph_from_name (this, user_data,
299 					 name, len,
300 					 glyph,
301 					 klass->user_data.glyph_from_name);
302   }
303 
304 
305   /* A bit higher-level, and with fallback */
306 
get_h_extents_with_fallbackhb_font_t307   inline void get_h_extents_with_fallback (hb_font_extents_t *extents)
308   {
309     if (!get_font_h_extents (extents))
310     {
311       extents->ascender = y_scale * .8;
312       extents->descender = extents->ascender - y_scale;
313       extents->line_gap = 0;
314     }
315   }
get_v_extents_with_fallbackhb_font_t316   inline void get_v_extents_with_fallback (hb_font_extents_t *extents)
317   {
318     if (!get_font_v_extents (extents))
319     {
320       extents->ascender = x_scale / 2;
321       extents->descender = extents->ascender - x_scale;
322       extents->line_gap = 0;
323     }
324   }
325 
get_extents_for_directionhb_font_t326   inline void get_extents_for_direction (hb_direction_t direction,
327 					 hb_font_extents_t *extents)
328   {
329     if (likely (HB_DIRECTION_IS_HORIZONTAL (direction)))
330       get_h_extents_with_fallback (extents);
331     else
332       get_v_extents_with_fallback (extents);
333   }
334 
get_glyph_advance_for_directionhb_font_t335   inline void get_glyph_advance_for_direction (hb_codepoint_t glyph,
336 					       hb_direction_t direction,
337 					       hb_position_t *x, hb_position_t *y)
338   {
339     if (likely (HB_DIRECTION_IS_HORIZONTAL (direction))) {
340       *x = get_glyph_h_advance (glyph);
341       *y = 0;
342     } else {
343       *x = 0;
344       *y = get_glyph_v_advance (glyph);
345     }
346   }
347 
guess_v_origin_minus_h_originhb_font_t348   inline void guess_v_origin_minus_h_origin (hb_codepoint_t glyph,
349 					     hb_position_t *x, hb_position_t *y)
350   {
351     *x = get_glyph_h_advance (glyph) / 2;
352 
353     /* TODO cache this somehow?! */
354     hb_font_extents_t extents;
355     get_h_extents_with_fallback (&extents);
356     *y = extents.ascender;
357   }
358 
get_glyph_h_origin_with_fallbackhb_font_t359   inline void get_glyph_h_origin_with_fallback (hb_codepoint_t glyph,
360 						hb_position_t *x, hb_position_t *y)
361   {
362     if (!get_glyph_h_origin (glyph, x, y) &&
363 	 get_glyph_v_origin (glyph, x, y))
364     {
365       hb_position_t dx, dy;
366       guess_v_origin_minus_h_origin (glyph, &dx, &dy);
367       *x -= dx; *y -= dy;
368     }
369   }
get_glyph_v_origin_with_fallbackhb_font_t370   inline void get_glyph_v_origin_with_fallback (hb_codepoint_t glyph,
371 						hb_position_t *x, hb_position_t *y)
372   {
373     if (!get_glyph_v_origin (glyph, x, y) &&
374 	 get_glyph_h_origin (glyph, x, y))
375     {
376       hb_position_t dx, dy;
377       guess_v_origin_minus_h_origin (glyph, &dx, &dy);
378       *x += dx; *y += dy;
379     }
380   }
381 
get_glyph_origin_for_directionhb_font_t382   inline void get_glyph_origin_for_direction (hb_codepoint_t glyph,
383 					      hb_direction_t direction,
384 					      hb_position_t *x, hb_position_t *y)
385   {
386     if (likely (HB_DIRECTION_IS_HORIZONTAL (direction)))
387       get_glyph_h_origin_with_fallback (glyph, x, y);
388     else
389       get_glyph_v_origin_with_fallback (glyph, x, y);
390   }
391 
add_glyph_h_originhb_font_t392   inline void add_glyph_h_origin (hb_codepoint_t glyph,
393 				  hb_position_t *x, hb_position_t *y)
394   {
395     hb_position_t origin_x, origin_y;
396 
397     get_glyph_h_origin_with_fallback (glyph, &origin_x, &origin_y);
398 
399     *x += origin_x;
400     *y += origin_y;
401   }
add_glyph_v_originhb_font_t402   inline void add_glyph_v_origin (hb_codepoint_t glyph,
403 				  hb_position_t *x, hb_position_t *y)
404   {
405     hb_position_t origin_x, origin_y;
406 
407     get_glyph_v_origin_with_fallback (glyph, &origin_x, &origin_y);
408 
409     *x += origin_x;
410     *y += origin_y;
411   }
add_glyph_origin_for_directionhb_font_t412   inline void add_glyph_origin_for_direction (hb_codepoint_t glyph,
413 					      hb_direction_t direction,
414 					      hb_position_t *x, hb_position_t *y)
415   {
416     hb_position_t origin_x, origin_y;
417 
418     get_glyph_origin_for_direction (glyph, direction, &origin_x, &origin_y);
419 
420     *x += origin_x;
421     *y += origin_y;
422   }
423 
subtract_glyph_h_originhb_font_t424   inline void subtract_glyph_h_origin (hb_codepoint_t glyph,
425 				       hb_position_t *x, hb_position_t *y)
426   {
427     hb_position_t origin_x, origin_y;
428 
429     get_glyph_h_origin_with_fallback (glyph, &origin_x, &origin_y);
430 
431     *x -= origin_x;
432     *y -= origin_y;
433   }
subtract_glyph_v_originhb_font_t434   inline void subtract_glyph_v_origin (hb_codepoint_t glyph,
435 				       hb_position_t *x, hb_position_t *y)
436   {
437     hb_position_t origin_x, origin_y;
438 
439     get_glyph_v_origin_with_fallback (glyph, &origin_x, &origin_y);
440 
441     *x -= origin_x;
442     *y -= origin_y;
443   }
subtract_glyph_origin_for_directionhb_font_t444   inline void subtract_glyph_origin_for_direction (hb_codepoint_t glyph,
445 						   hb_direction_t direction,
446 						   hb_position_t *x, hb_position_t *y)
447   {
448     hb_position_t origin_x, origin_y;
449 
450     get_glyph_origin_for_direction (glyph, direction, &origin_x, &origin_y);
451 
452     *x -= origin_x;
453     *y -= origin_y;
454   }
455 
get_glyph_kerning_for_directionhb_font_t456   inline void get_glyph_kerning_for_direction (hb_codepoint_t first_glyph, hb_codepoint_t second_glyph,
457 					       hb_direction_t direction,
458 					       hb_position_t *x, hb_position_t *y)
459   {
460     if (likely (HB_DIRECTION_IS_HORIZONTAL (direction))) {
461       *x = get_glyph_h_kerning (first_glyph, second_glyph);
462       *y = 0;
463     } else {
464       *x = 0;
465       *y = get_glyph_v_kerning (first_glyph, second_glyph);
466     }
467   }
468 
get_glyph_extents_for_originhb_font_t469   inline hb_bool_t get_glyph_extents_for_origin (hb_codepoint_t glyph,
470 						 hb_direction_t direction,
471 						 hb_glyph_extents_t *extents)
472   {
473     hb_bool_t ret = get_glyph_extents (glyph, extents);
474 
475     if (ret)
476       subtract_glyph_origin_for_direction (glyph, direction, &extents->x_bearing, &extents->y_bearing);
477 
478     return ret;
479   }
480 
get_glyph_contour_point_for_originhb_font_t481   inline hb_bool_t get_glyph_contour_point_for_origin (hb_codepoint_t glyph, unsigned int point_index,
482 						       hb_direction_t direction,
483 						       hb_position_t *x, hb_position_t *y)
484   {
485     hb_bool_t ret = get_glyph_contour_point (glyph, point_index, x, y);
486 
487     if (ret)
488       subtract_glyph_origin_for_direction (glyph, direction, x, y);
489 
490     return ret;
491   }
492 
493   /* Generates gidDDD if glyph has no name. */
494   inline void
glyph_to_stringhb_font_t495   glyph_to_string (hb_codepoint_t glyph,
496 		   char *s, unsigned int size)
497   {
498     if (get_glyph_name (glyph, s, size)) return;
499 
500     if (size && snprintf (s, size, "gid%u", glyph) < 0)
501       *s = '\0';
502   }
503 
504   /* Parses gidDDD and uniUUUU strings automatically. */
505   inline hb_bool_t
glyph_from_stringhb_font_t506   glyph_from_string (const char *s, int len, /* -1 means nul-terminated */
507 		     hb_codepoint_t *glyph)
508   {
509     if (get_glyph_from_name (s, len, glyph)) return true;
510 
511     if (len == -1) len = strlen (s);
512 
513     /* Straight glyph index. */
514     if (hb_codepoint_parse (s, len, 10, glyph))
515       return true;
516 
517     if (len > 3)
518     {
519       /* gidDDD syntax for glyph indices. */
520       if (0 == strncmp (s, "gid", 3) &&
521 	  hb_codepoint_parse (s + 3, len - 3, 10, glyph))
522 	return true;
523 
524       /* uniUUUU and other Unicode character indices. */
525       hb_codepoint_t unichar;
526       if (0 == strncmp (s, "uni", 3) &&
527 	  hb_codepoint_parse (s + 3, len - 3, 16, &unichar) &&
528 	  get_nominal_glyph (unichar, glyph))
529 	return true;
530     }
531 
532     return false;
533   }
534 
em_scalehb_font_t535   inline hb_position_t em_scale (int16_t v, int scale)
536   {
537     int upem = face->get_upem ();
538     int64_t scaled = v * (int64_t) scale;
539     scaled += scaled >= 0 ? upem/2 : -upem/2; /* Round. */
540     return (hb_position_t) (scaled / upem);
541   }
em_scalefhb_font_t542   inline hb_position_t em_scalef (float v, int scale)
543   {
544     return (hb_position_t) (v * scale / face->get_upem ());
545   }
546 };
547 
548 #define HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS
549 #define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_PROTOTYPE(shaper, font);
550 #include "hb-shaper-list.hh"
551 #undef HB_SHAPER_IMPLEMENT
552 #undef HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS
553 
554 
555 #endif /* HB_FONT_PRIVATE_HH */
556