1 /*
2 * Copyright © 2024 Google, Inc.
3 *
4 * This is part of HarfBuzz, a text shaping library.
5 *
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.
11 *
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
16 * DAMAGE.
17 *
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.
23 *
24 * Author(s): Behdad Esfahbod
25 */
26
27 #include "hb.hh"
28
29 #ifdef HAVE_CORETEXT
30
31 #include "hb-coretext.h"
32
33 #include "hb-draw.hh"
34 #include "hb-font.hh"
35 #include "hb-machinery.hh"
36
37 #if MAC_OS_X_VERSION_MIN_REQUIRED < 101100
38 # define kCTFontOrientationDefault kCTFontDefaultOrientation
39 #endif
40
41 #define MAX_GLYPHS 64u
42
43 static void
_hb_coretext_font_destroy(void * font_data)44 _hb_coretext_font_destroy (void *font_data)
45 {
46 CTFontRef ct_font = (CTFontRef) font_data;
47
48 CFRelease (ct_font);
49 }
50
51 static hb_bool_t
hb_coretext_get_nominal_glyph(hb_font_t * font HB_UNUSED,void * font_data,hb_codepoint_t unicode,hb_codepoint_t * glyph,void * user_data HB_UNUSED)52 hb_coretext_get_nominal_glyph (hb_font_t *font HB_UNUSED,
53 void *font_data,
54 hb_codepoint_t unicode,
55 hb_codepoint_t *glyph,
56 void *user_data HB_UNUSED)
57 {
58 CTFontRef ct_font = (CTFontRef) font_data;
59 UniChar ch = unicode;
60 CGGlyph cg_glyph;
61 if (CTFontGetGlyphsForCharacters (ct_font, &ch, &cg_glyph, 1))
62 {
63 *glyph = cg_glyph;
64 return true;
65 }
66 return false;
67 }
68
69 static unsigned int
hb_coretext_get_nominal_glyphs(hb_font_t * font HB_UNUSED,void * font_data,unsigned int count,const hb_codepoint_t * first_unicode,unsigned int unicode_stride,hb_codepoint_t * first_glyph,unsigned int glyph_stride,void * user_data HB_UNUSED)70 hb_coretext_get_nominal_glyphs (hb_font_t *font HB_UNUSED,
71 void *font_data,
72 unsigned int count,
73 const hb_codepoint_t *first_unicode,
74 unsigned int unicode_stride,
75 hb_codepoint_t *first_glyph,
76 unsigned int glyph_stride,
77 void *user_data HB_UNUSED)
78 {
79 CTFontRef ct_font = (CTFontRef) font_data;
80
81 UniChar ch[MAX_GLYPHS];
82 CGGlyph cg_glyph[MAX_GLYPHS];
83 for (unsigned i = 0; i < count; i += MAX_GLYPHS)
84 {
85 unsigned c = (unsigned) hb_min ((int) MAX_GLYPHS, (int) count - (int) i);
86 for (unsigned j = 0; j < c; j++)
87 {
88 ch[j] = *first_unicode;
89 first_unicode = &StructAtOffset<const hb_codepoint_t> (first_unicode, unicode_stride);
90 }
91 CTFontGetGlyphsForCharacters (ct_font, ch, cg_glyph, c);
92 for (unsigned j = 0; j < c; j++)
93 {
94 *first_glyph = cg_glyph[j];
95 first_glyph = &StructAtOffset<hb_codepoint_t> (first_glyph, glyph_stride);
96 }
97 }
98
99 return count;
100 }
101
102 static hb_bool_t
hb_coretext_get_variation_glyph(hb_font_t * font HB_UNUSED,void * font_data,hb_codepoint_t unicode,hb_codepoint_t variation_selector,hb_codepoint_t * glyph,void * user_data HB_UNUSED)103 hb_coretext_get_variation_glyph (hb_font_t *font HB_UNUSED,
104 void *font_data,
105 hb_codepoint_t unicode,
106 hb_codepoint_t variation_selector,
107 hb_codepoint_t *glyph,
108 void *user_data HB_UNUSED)
109 {
110 CTFontRef ct_font = (CTFontRef) font_data;
111
112 UniChar ch[2] = { unicode, variation_selector };
113 CGGlyph cg_glyph[2];
114
115 CTFontGetGlyphsForCharacters (ct_font, ch, cg_glyph, 2);
116
117 if (cg_glyph[1])
118 return false;
119
120 *glyph = cg_glyph[0];
121 return true;
122 }
123
124 static void
hb_coretext_get_glyph_h_advances(hb_font_t * font,void * font_data,unsigned count,const hb_codepoint_t * first_glyph,unsigned glyph_stride,hb_position_t * first_advance,unsigned advance_stride,void * user_data HB_UNUSED)125 hb_coretext_get_glyph_h_advances (hb_font_t* font, void* font_data,
126 unsigned count,
127 const hb_codepoint_t *first_glyph,
128 unsigned glyph_stride,
129 hb_position_t *first_advance,
130 unsigned advance_stride,
131 void *user_data HB_UNUSED)
132 {
133 CTFontRef ct_font = (CTFontRef) font_data;
134
135 CGFloat ct_font_size = CTFontGetSize (ct_font);
136 CGFloat x_mult = (CGFloat) font->x_scale / ct_font_size;
137
138 CGGlyph cg_glyph[MAX_GLYPHS];
139 CGSize advances[MAX_GLYPHS];
140 for (unsigned i = 0; i < count; i += MAX_GLYPHS)
141 {
142 unsigned c = (unsigned) hb_min ((int) MAX_GLYPHS, (int) count - (int) i);
143 for (unsigned j = 0; j < c; j++)
144 {
145 cg_glyph[j] = *first_glyph;
146 first_glyph = &StructAtOffset<const hb_codepoint_t> (first_glyph, glyph_stride);
147 }
148 CTFontGetAdvancesForGlyphs (ct_font, kCTFontOrientationHorizontal, cg_glyph, advances, c);
149 for (unsigned j = 0; j < c; j++)
150 {
151 *first_advance = round (advances[j].width * x_mult);
152 first_advance = &StructAtOffset<hb_position_t> (first_advance, advance_stride);
153 }
154 }
155 }
156
157 #ifndef HB_NO_VERTICAL
158 static void
hb_coretext_get_glyph_v_advances(hb_font_t * font,void * font_data,unsigned count,const hb_codepoint_t * first_glyph,unsigned glyph_stride,hb_position_t * first_advance,unsigned advance_stride,void * user_data HB_UNUSED)159 hb_coretext_get_glyph_v_advances (hb_font_t* font, void* font_data,
160 unsigned count,
161 const hb_codepoint_t *first_glyph,
162 unsigned glyph_stride,
163 hb_position_t *first_advance,
164 unsigned advance_stride,
165 void *user_data HB_UNUSED)
166 {
167 CTFontRef ct_font = (CTFontRef) font_data;
168
169 CGFloat ct_font_size = CTFontGetSize (ct_font);
170 CGFloat y_mult = (CGFloat) -font->y_scale / ct_font_size;
171
172 CGGlyph cg_glyph[MAX_GLYPHS];
173 CGSize advances[MAX_GLYPHS];
174 for (unsigned i = 0; i < count; i += MAX_GLYPHS)
175 {
176 unsigned c = (unsigned) hb_min ((int) MAX_GLYPHS, (int) count - (int) i);
177 for (unsigned j = 0; j < c; j++)
178 {
179 cg_glyph[j] = *first_glyph;
180 first_glyph = &StructAtOffset<const hb_codepoint_t> (first_glyph, glyph_stride);
181 }
182 CTFontGetAdvancesForGlyphs (ct_font, kCTFontOrientationVertical, cg_glyph, advances, c);
183 for (unsigned j = 0; j < c; j++)
184 {
185 *first_advance = round (advances[j].width * y_mult);
186 first_advance = &StructAtOffset<hb_position_t> (first_advance, advance_stride);
187 }
188 }
189 }
190 #endif
191
192 #ifndef HB_NO_VERTICAL
193 static hb_bool_t
hb_coretext_get_glyph_v_origin(hb_font_t * font,void * font_data,hb_codepoint_t glyph,hb_position_t * x,hb_position_t * y,void * user_data HB_UNUSED)194 hb_coretext_get_glyph_v_origin (hb_font_t *font,
195 void *font_data,
196 hb_codepoint_t glyph,
197 hb_position_t *x,
198 hb_position_t *y,
199 void *user_data HB_UNUSED)
200 {
201 CTFontRef ct_font = (CTFontRef) font_data;
202
203 CGFloat ct_font_size = CTFontGetSize (ct_font);
204 CGFloat x_mult = (CGFloat) -font->x_scale / ct_font_size;
205 CGFloat y_mult = (CGFloat) -font->y_scale / ct_font_size;
206
207 const CGGlyph glyphs = glyph;
208 CGSize origin;
209 CTFontGetVerticalTranslationsForGlyphs (ct_font, &glyphs, &origin, 1);
210
211 *x = round (x_mult * origin.width);
212 *y = round (y_mult * origin.height);
213
214 return true;
215 }
216 #endif
217
218 static hb_bool_t
hb_coretext_get_glyph_extents(hb_font_t * font,void * font_data,hb_codepoint_t glyph,hb_glyph_extents_t * extents,void * user_data HB_UNUSED)219 hb_coretext_get_glyph_extents (hb_font_t *font,
220 void *font_data,
221 hb_codepoint_t glyph,
222 hb_glyph_extents_t *extents,
223 void *user_data HB_UNUSED)
224 {
225 CTFontRef ct_font = (CTFontRef) font_data;
226
227 CGFloat ct_font_size = CTFontGetSize (ct_font);
228 CGFloat x_mult = (CGFloat) font->x_scale / ct_font_size;
229 CGFloat y_mult = (CGFloat) font->y_scale / ct_font_size;
230
231 CGGlyph glyphs[1] = { glyph };
232 CGRect bounds = ::CTFontGetBoundingRectsForGlyphs(ct_font,
233 kCTFontOrientationDefault, glyphs, NULL, 1);
234
235 extents->x_bearing = round (bounds.origin.x * x_mult);
236 extents->y_bearing = round (bounds.origin.y * y_mult);
237 extents->width = round (bounds.size.width * x_mult);
238 extents->height = round (bounds.size.height * y_mult);
239
240 return true;
241 }
242
243 static hb_bool_t
hb_coretext_get_font_h_extents(hb_font_t * font,void * font_data,hb_font_extents_t * metrics,void * user_data HB_UNUSED)244 hb_coretext_get_font_h_extents (hb_font_t *font,
245 void *font_data,
246 hb_font_extents_t *metrics,
247 void *user_data HB_UNUSED)
248 {
249 CTFontRef ct_font = (CTFontRef) font_data;
250 CGFloat ct_font_size = CTFontGetSize (ct_font);
251 CGFloat y_mult = (CGFloat) font->y_scale / ct_font_size;
252
253 metrics->ascender = round (CTFontGetAscent (ct_font) * y_mult);
254 metrics->descender = -round (CTFontGetDescent (ct_font) * y_mult);
255 metrics->line_gap = round (CTFontGetLeading (ct_font) * y_mult);
256
257 return true;
258 }
259
260 #ifndef HB_NO_DRAW
261
262 static void
ct_apply_func(void * info,const CGPathElement * element)263 ct_apply_func (void *info, const CGPathElement *element)
264 {
265 hb_draw_session_t *draws = (hb_draw_session_t *) info;
266
267 switch (element->type)
268 {
269 case kCGPathElementMoveToPoint:
270 draws->move_to (element->points[0].x, element->points[0].y);
271 break;
272 case kCGPathElementAddLineToPoint:
273 draws->line_to (element->points[0].x, element->points[0].y);
274 break;
275 case kCGPathElementAddQuadCurveToPoint:
276 draws->quadratic_to (element->points[0].x, element->points[0].y,
277 element->points[1].x, element->points[1].y);
278 break;
279 case kCGPathElementAddCurveToPoint:
280 draws->cubic_to (element->points[0].x, element->points[0].y,
281 element->points[1].x, element->points[1].y,
282 element->points[2].x, element->points[2].y);
283 break;
284 case kCGPathElementCloseSubpath:
285 draws->close_path ();
286 break;
287 }
288 }
289
290 static void
hb_coretext_draw_glyph(hb_font_t * font,void * font_data HB_UNUSED,hb_codepoint_t glyph,hb_draw_funcs_t * draw_funcs,void * draw_data,void * user_data)291 hb_coretext_draw_glyph (hb_font_t *font,
292 void *font_data HB_UNUSED,
293 hb_codepoint_t glyph,
294 hb_draw_funcs_t *draw_funcs, void *draw_data,
295 void *user_data)
296 {
297 CTFontRef ct_font = (CTFontRef) font_data;
298
299 CGFloat ct_font_size = CTFontGetSize (ct_font);
300 CGFloat x_mult = (CGFloat) font->x_scale / ct_font_size;
301 CGFloat y_mult = (CGFloat) font->y_scale / ct_font_size;
302
303 CGAffineTransform transform = CGAffineTransformIdentity;
304 transform = CGAffineTransformScale (transform, x_mult, y_mult);
305
306 CGPathRef path = CTFontCreatePathForGlyph (ct_font, glyph, &transform);
307 if (!path)
308 return;
309
310 hb_draw_session_t drawing = {draw_funcs, draw_data, font->slant};
311
312 CGPathApply (path, &drawing, ct_apply_func);
313
314 CFRelease (path);
315 }
316 #endif
317
318 static hb_bool_t
hb_coretext_get_glyph_name(hb_font_t * font,void * font_data HB_UNUSED,hb_codepoint_t glyph,char * name,unsigned int size,void * user_data HB_UNUSED)319 hb_coretext_get_glyph_name (hb_font_t *font,
320 void *font_data HB_UNUSED,
321 hb_codepoint_t glyph,
322 char *name, unsigned int size,
323 void *user_data HB_UNUSED)
324 {
325 CGFontRef cg_font = (CGFontRef) (const void *) font->face->data.coretext;
326
327 CGGlyph cg_glyph = glyph;
328 CFStringRef cf_name = CGFontCopyGlyphNameForGlyph (cg_font, cg_glyph);
329 if (!cf_name)
330 return false;
331
332 CFIndex len = CFStringGetLength (cf_name);
333 if (len > size - 1)
334 len = size - 1;
335
336 CFStringGetBytes (cf_name, CFRangeMake (0, len),
337 kCFStringEncodingUTF8, 0, false,
338 (UInt8 *) name, size, &len);
339
340 name[len] = '\0';
341 return true;
342 }
343
344 static hb_bool_t
hb_coretext_get_glyph_from_name(hb_font_t * font HB_UNUSED,void * font_data,const char * name,int len,hb_codepoint_t * glyph,void * user_data HB_UNUSED)345 hb_coretext_get_glyph_from_name (hb_font_t *font HB_UNUSED,
346 void *font_data,
347 const char *name, int len,
348 hb_codepoint_t *glyph,
349 void *user_data HB_UNUSED)
350 {
351 CTFontRef ct_font = (CTFontRef) font_data;
352
353 if (len == -1)
354 len = strlen (name);
355
356 CFStringRef cf_name = CFStringCreateWithBytes (kCFAllocatorDefault,
357 (const UInt8 *) name, len,
358 kCFStringEncodingUTF8, false);
359 CGGlyph cg_glyph = CTFontGetGlyphWithName (ct_font, cf_name);
360 *glyph = cg_glyph;
361
362 CFRelease (cf_name);
363
364 // TODO Return true for .notdef; hb-ft does that.
365
366 return cg_glyph != 0;
367 }
368
369
370 static inline void free_static_coretext_funcs ();
371
372 static struct hb_coretext_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_coretext_font_funcs_lazy_loader_t>
373 {
createhb_coretext_font_funcs_lazy_loader_t374 static hb_font_funcs_t *create ()
375 {
376 hb_font_funcs_t *funcs = hb_font_funcs_create ();
377
378 hb_font_funcs_set_nominal_glyph_func (funcs, hb_coretext_get_nominal_glyph, nullptr, nullptr);
379 hb_font_funcs_set_nominal_glyphs_func (funcs, hb_coretext_get_nominal_glyphs, nullptr, nullptr);
380 hb_font_funcs_set_variation_glyph_func (funcs, hb_coretext_get_variation_glyph, nullptr, nullptr);
381
382 hb_font_funcs_set_font_h_extents_func (funcs, hb_coretext_get_font_h_extents, nullptr, nullptr);
383 hb_font_funcs_set_glyph_h_advances_func (funcs, hb_coretext_get_glyph_h_advances, nullptr, nullptr);
384 //hb_font_funcs_set_glyph_h_origin_func (funcs, hb_coretext_get_glyph_h_origin, nullptr, nullptr);
385
386 #ifndef HB_NO_VERTICAL
387 //hb_font_funcs_set_font_v_extents_func (funcs, hb_coretext_get_font_v_extents, nullptr, nullptr);
388 hb_font_funcs_set_glyph_v_advances_func (funcs, hb_coretext_get_glyph_v_advances, nullptr, nullptr);
389 hb_font_funcs_set_glyph_v_origin_func (funcs, hb_coretext_get_glyph_v_origin, nullptr, nullptr);
390 #endif
391
392 #ifndef HB_NO_DRAW
393 hb_font_funcs_set_draw_glyph_func (funcs, hb_coretext_draw_glyph, nullptr, nullptr);
394 #endif
395
396 hb_font_funcs_set_glyph_extents_func (funcs, hb_coretext_get_glyph_extents, nullptr, nullptr);
397
398 #ifndef HB_NO_OT_FONT_GLYPH_NAMES
399 hb_font_funcs_set_glyph_name_func (funcs, hb_coretext_get_glyph_name, nullptr, nullptr);
400 hb_font_funcs_set_glyph_from_name_func (funcs, hb_coretext_get_glyph_from_name, nullptr, nullptr);
401 #endif
402
403 hb_font_funcs_make_immutable (funcs);
404
405 hb_atexit (free_static_coretext_funcs);
406
407 return funcs;
408 }
409 } static_coretext_funcs;
410
411 static inline
free_static_coretext_funcs()412 void free_static_coretext_funcs ()
413 {
414 static_coretext_funcs.free_instance ();
415 }
416
417 static hb_font_funcs_t *
_hb_coretext_get_font_funcs()418 _hb_coretext_get_font_funcs ()
419 {
420 return static_coretext_funcs.get_unconst ();
421 }
422
423
424 /**
425 * hb_coretext_font_set_funcs:
426 * @font: #hb_font_t to work upon
427 *
428 * Configures the font-functions structure of the specified
429 * #hb_font_t font object to use CoreText font functions.
430 *
431 * In particular, you can use this function to configure an
432 * existing #hb_face_t face object for use with CoreText font
433 * functions even if that #hb_face_t face object was initially
434 * created with hb_face_create(), and therefore was not
435 * initially configured to use CoreText font functions.
436 *
437 * An #hb_font_t object created with hb_coretext_font_create()
438 * is preconfigured for CoreText font functions and does not
439 * require this function to be used.
440 *
441 * <note>Note: Internally, this function creates a CTFont.
442 * </note>
443 *
444 * Since: 10.1.0
445 **/
446 void
hb_coretext_font_set_funcs(hb_font_t * font)447 hb_coretext_font_set_funcs (hb_font_t *font)
448 {
449 CTFontRef ct_font = hb_coretext_font_get_ct_font (font);
450 if (unlikely (!ct_font))
451 return;
452
453 hb_font_set_funcs (font,
454 _hb_coretext_get_font_funcs (),
455 (void *) CFRetain (ct_font),
456 _hb_coretext_font_destroy);
457 }
458
459 #undef MAX_GLYPHS
460
461 #endif
462