xref: /aosp_15_r20/external/harfbuzz_ng/src/hb-coretext-font.cc (revision 2d1272b857b1f7575e6e246373e1cb218663db8a)
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