2 * Copyright © 2018-2019 Ebrahim Byagowi
4 * This is part of HarfBuzz, a text shaping library.
6 * Permission is hereby granted, without written agreement and without
7 * license or royalty fees, to use, copy, modify, and distribute this
8 * software and its documentation for any purpose, provided that the
9 * above copyright notice and the following two paragraphs appear in
10 * all copies of this software.
12 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
13 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
14 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
15 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
18 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
19 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
21 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
22 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
27 #include "hb-ot-var-mvar-table.hh"
28 #include "hb-ot-gasp-table.hh" // Just so we compile it; unused otherwise.
29 #include "hb-ot-os2-table.hh"
30 #include "hb-ot-post-table.hh"
31 #include "hb-ot-hhea-table.hh"
32 #include "hb-ot-metrics.hh"
33 #include "hb-ot-face.hh"
37 * SECTION:hb-ot-metrics
38 * @title: hb-ot-metrics
39 * @short_description: OpenType Metrics
42 * Functions for fetching metrics from fonts.
46 _fix_ascender_descender (float value
, hb_ot_metrics_tag_t metrics_tag
)
48 if (metrics_tag
== HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER
||
49 metrics_tag
== HB_OT_METRICS_TAG_VERTICAL_ASCENDER
)
50 return fabs ((double) value
);
51 if (metrics_tag
== HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER
||
52 metrics_tag
== HB_OT_METRICS_TAG_VERTICAL_DESCENDER
)
53 return -fabs ((double) value
);
57 /* The common part of _get_position logic needed on hb-ot-font and here
58 to be able to have slim builds without the not always needed parts */
60 _hb_ot_metrics_get_position_common (hb_font_t
*font
,
61 hb_ot_metrics_tag_t metrics_tag
,
62 hb_position_t
*position
/* OUT. May be NULL. */)
64 hb_face_t
*face
= font
->face
;
65 switch ((unsigned) metrics_tag
)
68 #define GET_VAR face->table.MVAR->get_var (metrics_tag, font->coords, font->num_coords)
72 #define GET_METRIC_X(TABLE, ATTR) \
73 (face->table.TABLE->has_data () && \
74 ((void) (position && (*position = font->em_scalef_x (_fix_ascender_descender ( \
75 face->table.TABLE->ATTR + GET_VAR, metrics_tag)))), true))
76 #define GET_METRIC_Y(TABLE, ATTR) \
77 (face->table.TABLE->has_data () && \
78 ((void) (position && (*position = font->em_scalef_y (_fix_ascender_descender ( \
79 face->table.TABLE->ATTR + GET_VAR, metrics_tag)))), true))
81 case HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER
:
82 return (face
->table
.OS2
->use_typo_metrics () && GET_METRIC_Y (OS2
, sTypoAscender
)) ||
83 GET_METRIC_Y (hhea
, ascender
);
84 case HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER
:
85 return (face
->table
.OS2
->use_typo_metrics () && GET_METRIC_Y (OS2
, sTypoDescender
)) ||
86 GET_METRIC_Y (hhea
, descender
);
87 case HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP
:
88 return (face
->table
.OS2
->use_typo_metrics () && GET_METRIC_Y (OS2
, sTypoLineGap
)) ||
89 GET_METRIC_Y (hhea
, lineGap
);
91 #ifndef HB_NO_VERTICAL
92 case HB_OT_METRICS_TAG_VERTICAL_ASCENDER
: return GET_METRIC_X (vhea
, ascender
);
93 case HB_OT_METRICS_TAG_VERTICAL_DESCENDER
: return GET_METRIC_X (vhea
, descender
);
94 case HB_OT_METRICS_TAG_VERTICAL_LINE_GAP
: return GET_METRIC_X (vhea
, lineGap
);
100 default: assert (0); return false;
104 #ifndef HB_NO_METRICS
108 _get_gasp (hb_face_t
*face
, float *result
, hb_ot_metrics_tag_t metrics_tag
)
110 const OT::GaspRange
& range
= face
->table
.gasp
->get_gasp_range (metrics_tag
- HB_TAG ('g','s','p','0'));
111 if (&range
== &Null (OT::GaspRange
)) return false;
112 if (result
) *result
= range
.rangeMaxPPEM
+ font
->face
->table
.MVAR
->get_var (metrics_tag
, font
->coords
, font
->num_coords
);
117 /* Private tags for https://github.com/harfbuzz/harfbuzz/issues/1866 */
118 #define _HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER_OS2 HB_TAG ('O','a','s','c')
119 #define _HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER_HHEA HB_TAG ('H','a','s','c')
120 #define _HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER_OS2 HB_TAG ('O','d','s','c')
121 #define _HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER_HHEA HB_TAG ('H','d','s','c')
122 #define _HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP_OS2 HB_TAG ('O','l','g','p')
123 #define _HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP_HHEA HB_TAG ('H','l','g','p')
126 * hb_ot_metrics_get_position:
127 * @font: an #hb_font_t object.
128 * @metrics_tag: tag of metrics value you like to fetch.
129 * @position: (out) (optional): result of metrics value from the font.
131 * Fetches metrics value corresponding to @metrics_tag from @font.
133 * Returns: Whether found the requested metrics in the font.
137 hb_ot_metrics_get_position (hb_font_t
*font
,
138 hb_ot_metrics_tag_t metrics_tag
,
139 hb_position_t
*position
/* OUT. May be NULL. */)
141 hb_face_t
*face
= font
->face
;
142 switch ((unsigned) metrics_tag
)
144 case HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER
:
145 case HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER
:
146 case HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP
:
147 case HB_OT_METRICS_TAG_VERTICAL_ASCENDER
:
148 case HB_OT_METRICS_TAG_VERTICAL_DESCENDER
:
149 case HB_OT_METRICS_TAG_VERTICAL_LINE_GAP
: return _hb_ot_metrics_get_position_common (font
, metrics_tag
, position
);
151 #define GET_VAR hb_ot_metrics_get_variation (font, metrics_tag)
155 #define GET_METRIC_X(TABLE, ATTR) \
156 (face->table.TABLE->has_data () && \
157 ((void) (position && (*position = font->em_scalef_x (face->table.TABLE->ATTR + GET_VAR))), true))
158 #define GET_METRIC_Y(TABLE, ATTR) \
159 (face->table.TABLE->has_data () && \
160 ((void) (position && (*position = font->em_scalef_y (face->table.TABLE->ATTR + GET_VAR))), true))
161 case HB_OT_METRICS_TAG_HORIZONTAL_CLIPPING_ASCENT
: return GET_METRIC_Y (OS2
, usWinAscent
);
162 case HB_OT_METRICS_TAG_HORIZONTAL_CLIPPING_DESCENT
: return GET_METRIC_Y (OS2
, usWinDescent
);
164 case HB_OT_METRICS_TAG_HORIZONTAL_CARET_RISE
:
165 case HB_OT_METRICS_TAG_HORIZONTAL_CARET_RUN
:
171 unsigned rise
= face
->table
.hhea
->caretSlopeRise
;
172 unsigned upem
= face
->get_upem ();
173 mult
= (rise
&& rise
< upem
) ? hb_min (upem
/ rise
, 256u) : 1u;
176 if (metrics_tag
== HB_OT_METRICS_TAG_HORIZONTAL_CARET_RISE
)
178 bool ret
= GET_METRIC_Y (hhea
, caretSlopeRise
);
187 hb_position_t rise
= 0;
189 if (font
->slant
&& position
&& GET_METRIC_Y (hhea
, caretSlopeRise
))
192 bool ret
= GET_METRIC_X (hhea
, caretSlopeRun
);
199 *position
+= roundf (mult
* font
->slant_xy
* rise
);
205 case HB_OT_METRICS_TAG_HORIZONTAL_CARET_OFFSET
: return GET_METRIC_X (hhea
, caretOffset
);
207 #ifndef HB_NO_VERTICAL
208 case HB_OT_METRICS_TAG_VERTICAL_CARET_RISE
: return GET_METRIC_X (vhea
, caretSlopeRise
);
209 case HB_OT_METRICS_TAG_VERTICAL_CARET_RUN
: return GET_METRIC_Y (vhea
, caretSlopeRun
);
210 case HB_OT_METRICS_TAG_VERTICAL_CARET_OFFSET
: return GET_METRIC_Y (vhea
, caretOffset
);
212 case HB_OT_METRICS_TAG_X_HEIGHT
: return GET_METRIC_Y (OS2
->v2 (), sxHeight
);
213 case HB_OT_METRICS_TAG_CAP_HEIGHT
: return GET_METRIC_Y (OS2
->v2 (), sCapHeight
);
214 case HB_OT_METRICS_TAG_SUBSCRIPT_EM_X_SIZE
: return GET_METRIC_X (OS2
, ySubscriptXSize
);
215 case HB_OT_METRICS_TAG_SUBSCRIPT_EM_Y_SIZE
: return GET_METRIC_Y (OS2
, ySubscriptYSize
);
216 case HB_OT_METRICS_TAG_SUBSCRIPT_EM_X_OFFSET
: return GET_METRIC_X (OS2
, ySubscriptXOffset
);
217 case HB_OT_METRICS_TAG_SUBSCRIPT_EM_Y_OFFSET
: return GET_METRIC_Y (OS2
, ySubscriptYOffset
);
218 case HB_OT_METRICS_TAG_SUPERSCRIPT_EM_X_SIZE
: return GET_METRIC_X (OS2
, ySuperscriptXSize
);
219 case HB_OT_METRICS_TAG_SUPERSCRIPT_EM_Y_SIZE
: return GET_METRIC_Y (OS2
, ySuperscriptYSize
);
220 case HB_OT_METRICS_TAG_SUPERSCRIPT_EM_X_OFFSET
: return GET_METRIC_X (OS2
, ySuperscriptXOffset
);
221 case HB_OT_METRICS_TAG_SUPERSCRIPT_EM_Y_OFFSET
: return GET_METRIC_Y (OS2
, ySuperscriptYOffset
);
222 case HB_OT_METRICS_TAG_STRIKEOUT_SIZE
: return GET_METRIC_Y (OS2
, yStrikeoutSize
);
223 case HB_OT_METRICS_TAG_STRIKEOUT_OFFSET
: return GET_METRIC_Y (OS2
, yStrikeoutPosition
);
224 case HB_OT_METRICS_TAG_UNDERLINE_SIZE
: return GET_METRIC_Y (post
->table
, underlineThickness
);
225 case HB_OT_METRICS_TAG_UNDERLINE_OFFSET
: return GET_METRIC_Y (post
->table
, underlinePosition
);
228 case _HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER_OS2
: return GET_METRIC_Y (OS2
, sTypoAscender
);
229 case _HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER_HHEA
: return GET_METRIC_Y (hhea
, ascender
);
230 case _HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER_OS2
: return GET_METRIC_Y (OS2
, sTypoDescender
);
231 case _HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER_HHEA
: return GET_METRIC_Y (hhea
, descender
);
232 case _HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP_OS2
: return GET_METRIC_Y (OS2
, sTypoLineGap
);
233 case _HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP_HHEA
: return GET_METRIC_Y (hhea
, lineGap
);
237 default: return false;
242 * hb_ot_metrics_get_position_with_fallback:
243 * @font: an #hb_font_t object.
244 * @metrics_tag: tag of metrics value you like to fetch.
245 * @position: (out) (optional): result of metrics value from the font.
247 * Fetches metrics value corresponding to @metrics_tag from @font,
248 * and synthesizes a value if it the value is missing in the font.
253 hb_ot_metrics_get_position_with_fallback (hb_font_t
*font
,
254 hb_ot_metrics_tag_t metrics_tag
,
255 hb_position_t
*position
/* OUT */)
257 hb_font_extents_t font_extents
;
258 hb_codepoint_t glyph
;
259 hb_glyph_extents_t extents
;
261 if (hb_ot_metrics_get_position (font
, metrics_tag
, position
))
263 if ((metrics_tag
!= HB_OT_METRICS_TAG_STRIKEOUT_SIZE
&&
264 metrics_tag
!= HB_OT_METRICS_TAG_UNDERLINE_SIZE
) ||
271 case HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER
:
272 case HB_OT_METRICS_TAG_HORIZONTAL_CLIPPING_ASCENT
:
273 hb_font_get_extents_for_direction (font
, HB_DIRECTION_LTR
, &font_extents
);
274 *position
= font_extents
.ascender
;
277 case HB_OT_METRICS_TAG_VERTICAL_ASCENDER
:
278 hb_font_get_extents_for_direction (font
, HB_DIRECTION_TTB
, &font_extents
);
279 *position
= font_extents
.ascender
;
282 case HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER
:
283 case HB_OT_METRICS_TAG_HORIZONTAL_CLIPPING_DESCENT
:
284 hb_font_get_extents_for_direction (font
, HB_DIRECTION_LTR
, &font_extents
);
285 *position
= font_extents
.descender
;
288 case HB_OT_METRICS_TAG_VERTICAL_DESCENDER
:
289 hb_font_get_extents_for_direction (font
, HB_DIRECTION_TTB
, &font_extents
);
290 *position
= font_extents
.ascender
;
293 case HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP
:
294 hb_font_get_extents_for_direction (font
, HB_DIRECTION_LTR
, &font_extents
);
295 *position
= font_extents
.line_gap
;
298 case HB_OT_METRICS_TAG_VERTICAL_LINE_GAP
:
299 hb_font_get_extents_for_direction (font
, HB_DIRECTION_TTB
, &font_extents
);
300 *position
= font_extents
.line_gap
;
303 case HB_OT_METRICS_TAG_HORIZONTAL_CARET_RISE
:
304 case HB_OT_METRICS_TAG_VERTICAL_CARET_RISE
:
308 case HB_OT_METRICS_TAG_HORIZONTAL_CARET_RUN
:
309 case HB_OT_METRICS_TAG_VERTICAL_CARET_RUN
:
313 case HB_OT_METRICS_TAG_HORIZONTAL_CARET_OFFSET
:
314 case HB_OT_METRICS_TAG_VERTICAL_CARET_OFFSET
:
318 case HB_OT_METRICS_TAG_X_HEIGHT
:
319 if (hb_font_get_nominal_glyph (font
, 'x', &glyph
) &&
320 hb_font_get_glyph_extents (font
, glyph
, &extents
))
321 *position
= extents
.y_bearing
;
323 *position
= font
->y_scale
/ 2;
326 case HB_OT_METRICS_TAG_CAP_HEIGHT
:
327 if (hb_font_get_nominal_glyph (font
, 'O', &glyph
) &&
328 hb_font_get_glyph_extents (font
, glyph
, &extents
))
329 *position
= extents
.height
+ 2 * extents
.y_bearing
;
331 *position
= font
->y_scale
* 2 / 3;
334 case HB_OT_METRICS_TAG_STRIKEOUT_SIZE
:
335 case HB_OT_METRICS_TAG_UNDERLINE_SIZE
:
336 *position
= font
->y_scale
/ 18;
339 case HB_OT_METRICS_TAG_STRIKEOUT_OFFSET
:
341 hb_position_t ascender
;
342 hb_ot_metrics_get_position_with_fallback (font
,
343 HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER
,
345 *position
= ascender
/ 2;
349 case HB_OT_METRICS_TAG_UNDERLINE_OFFSET
:
350 *position
= - font
->y_scale
/ 18;
353 case HB_OT_METRICS_TAG_SUBSCRIPT_EM_X_SIZE
:
354 case HB_OT_METRICS_TAG_SUPERSCRIPT_EM_X_SIZE
:
355 *position
= font
->x_scale
* 10 / 12;
358 case HB_OT_METRICS_TAG_SUBSCRIPT_EM_Y_SIZE
:
359 case HB_OT_METRICS_TAG_SUPERSCRIPT_EM_Y_SIZE
:
360 *position
= font
->y_scale
* 10 / 12;
363 case HB_OT_METRICS_TAG_SUBSCRIPT_EM_X_OFFSET
:
364 case HB_OT_METRICS_TAG_SUPERSCRIPT_EM_X_OFFSET
:
368 case HB_OT_METRICS_TAG_SUBSCRIPT_EM_Y_OFFSET
:
369 case HB_OT_METRICS_TAG_SUPERSCRIPT_EM_Y_OFFSET
:
370 *position
= font
->y_scale
/ 5;
373 case _HB_OT_METRICS_TAG_MAX_VALUE
:
382 * hb_ot_metrics_get_variation:
383 * @font: an #hb_font_t object.
384 * @metrics_tag: tag of metrics value you like to fetch.
386 * Fetches metrics value corresponding to @metrics_tag from @font with the
387 * current font variation settings applied.
389 * Returns: The requested metric value.
394 hb_ot_metrics_get_variation (hb_font_t
*font
, hb_ot_metrics_tag_t metrics_tag
)
396 return font
->face
->table
.MVAR
->get_var (metrics_tag
, font
->coords
, font
->num_coords
);
400 * hb_ot_metrics_get_x_variation:
401 * @font: an #hb_font_t object.
402 * @metrics_tag: tag of metrics value you like to fetch.
404 * Fetches horizontal metrics value corresponding to @metrics_tag from @font
405 * with the current font variation settings applied.
407 * Returns: The requested metric value.
412 hb_ot_metrics_get_x_variation (hb_font_t
*font
, hb_ot_metrics_tag_t metrics_tag
)
414 return font
->em_scalef_x (hb_ot_metrics_get_variation (font
, metrics_tag
));
418 * hb_ot_metrics_get_y_variation:
419 * @font: an #hb_font_t object.
420 * @metrics_tag: tag of metrics value you like to fetch.
422 * Fetches vertical metrics value corresponding to @metrics_tag from @font with
423 * the current font variation settings applied.
425 * Returns: The requested metric value.
430 hb_ot_metrics_get_y_variation (hb_font_t
*font
, hb_ot_metrics_tag_t metrics_tag
)
432 return font
->em_scalef_y (hb_ot_metrics_get_variation (font
, metrics_tag
));