hb-directwrite-font.cc (11940B)
1 /* 2 * Copyright © 2025 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_DIRECTWRITE 30 31 #include "hb-directwrite.h" 32 33 #include <d2d1.h> 34 35 #include "hb-draw.hh" 36 #include "hb-font.hh" 37 #include "hb-machinery.hh" 38 39 #define MAX_GLYPHS 256u 40 41 static unsigned int 42 hb_directwrite_get_nominal_glyphs (hb_font_t *font, 43 void *font_data HB_UNUSED, 44 unsigned int count, 45 const hb_codepoint_t *first_unicode, 46 unsigned int unicode_stride, 47 hb_codepoint_t *first_glyph, 48 unsigned int glyph_stride, 49 void *user_data HB_UNUSED) 50 { 51 IDWriteFontFace *dw_face = (IDWriteFontFace *) (const void *) font->data.directwrite; 52 53 for (unsigned i = 0; i < count;) 54 { 55 UINT32 unicodes[MAX_GLYPHS]; 56 UINT16 gids[MAX_GLYPHS]; 57 58 unsigned n = hb_min (MAX_GLYPHS, count - i); 59 60 for (unsigned j = 0; j < n; j++) 61 { 62 unicodes[j] = *first_unicode; 63 first_unicode = &StructAtOffset<const hb_codepoint_t> (first_unicode, unicode_stride); 64 } 65 66 if (!SUCCEEDED (dw_face->GetGlyphIndices (unicodes, n, gids))) 67 return i; 68 69 for (unsigned j = 0; j < n; j++) 70 { 71 if (!gids[j]) 72 return i + j; 73 *first_glyph = gids[j]; 74 first_glyph = &StructAtOffset<hb_codepoint_t> (first_glyph, glyph_stride); 75 } 76 77 i += n; 78 } 79 80 return count; 81 } 82 83 static hb_bool_t 84 hb_directwrite_get_font_h_extents (hb_font_t *font, 85 void *font_data HB_UNUSED, 86 hb_font_extents_t *metrics, 87 void *user_data HB_UNUSED) 88 { 89 IDWriteFontFace *dw_face = (IDWriteFontFace *) (const void *) font->data.directwrite; 90 91 DWRITE_FONT_METRICS dw_metrics; 92 dw_face->GetMetrics (&dw_metrics); 93 94 metrics->ascender = font->em_scale_y (dw_metrics.ascent); 95 metrics->descender = -font->em_scale_y (dw_metrics.descent); 96 metrics->line_gap = font->em_scale_y (dw_metrics.lineGap); 97 98 return true; 99 } 100 101 static void 102 hb_directwrite_get_glyph_h_advances (hb_font_t* font, 103 void* font_data HB_UNUSED, 104 unsigned count, 105 const hb_codepoint_t *first_glyph, 106 unsigned glyph_stride, 107 hb_position_t *first_advance, 108 unsigned advance_stride, 109 void *user_data HB_UNUSED) 110 { 111 IDWriteFontFace *dw_face = (IDWriteFontFace *) (const void *) font->data.directwrite; 112 113 IDWriteFontFace1 *dw_face1 = nullptr; 114 dw_face->QueryInterface (__uuidof(IDWriteFontFace1), (void**)&dw_face1); 115 assert (dw_face1); 116 117 unsigned int num_glyphs = font->face->get_num_glyphs (); 118 119 for (unsigned i = 0; i < count;) 120 { 121 UINT16 gids[MAX_GLYPHS]; 122 INT32 advances[MAX_GLYPHS]; 123 124 unsigned n = hb_min (MAX_GLYPHS, count - i); 125 126 for (unsigned j = 0; j < n; j++) 127 { 128 gids[j] = *first_glyph; 129 advances[j] = 0; 130 first_glyph = &StructAtOffset<const hb_codepoint_t> (first_glyph, glyph_stride); 131 } 132 dw_face1->GetDesignGlyphAdvances (n, gids, advances, false); 133 for (unsigned j = 0; j < n; j++) 134 { 135 // https://github.com/harfbuzz/harfbuzz/issues/5319 136 auto advance = gids[j] < num_glyphs ? advances[j] : 0; 137 *first_advance = font->em_scale_x (advance); 138 first_advance = &StructAtOffset<hb_position_t> (first_advance, advance_stride); 139 } 140 141 i += n; 142 } 143 } 144 145 #ifndef HB_NO_VERTICAL 146 147 static void 148 hb_directwrite_get_glyph_v_advances (hb_font_t* font, 149 void* font_data HB_UNUSED, 150 unsigned count, 151 const hb_codepoint_t *first_glyph, 152 unsigned glyph_stride, 153 hb_position_t *first_advance, 154 unsigned advance_stride, 155 void *user_data HB_UNUSED) 156 { 157 IDWriteFontFace *dw_face = (IDWriteFontFace *) (const void *) font->data.directwrite; 158 159 IDWriteFontFace1 *dw_face1 = nullptr; 160 dw_face->QueryInterface (__uuidof(IDWriteFontFace1), (void**)&dw_face1); 161 assert (dw_face1); 162 163 for (unsigned i = 0; i < count;) 164 { 165 UINT16 gids[MAX_GLYPHS]; 166 INT32 advances[MAX_GLYPHS]; 167 168 unsigned n = hb_min (MAX_GLYPHS, count - i); 169 170 for (unsigned j = 0; j < n; j++) 171 { 172 gids[j] = *first_glyph; 173 advances[j] = 0; 174 first_glyph = &StructAtOffset<const hb_codepoint_t> (first_glyph, glyph_stride); 175 } 176 dw_face1->GetDesignGlyphAdvances (n, gids, advances, true); 177 for (unsigned j = 0; j < n; j++) 178 { 179 *first_advance = -font->em_scale_y (advances[j]); 180 first_advance = &StructAtOffset<hb_position_t> (first_advance, advance_stride); 181 } 182 183 i += n; 184 } 185 } 186 187 static hb_bool_t 188 hb_directwrite_get_glyph_v_origin (hb_font_t *font, 189 void *font_data HB_UNUSED, 190 hb_codepoint_t glyph, 191 hb_position_t *x, 192 hb_position_t *y, 193 void *user_data HB_UNUSED) 194 { 195 IDWriteFontFace *dw_face = (IDWriteFontFace *) (const void *) font->data.directwrite; 196 197 UINT16 gid = glyph; 198 DWRITE_GLYPH_METRICS metrics; 199 200 if (FAILED (dw_face->GetDesignGlyphMetrics (&gid, 1, &metrics))) 201 return false; 202 203 *x = font->em_scale_x (metrics.advanceWidth / 2); 204 *y = font->em_scale_y (metrics.verticalOriginY); // Untested 205 206 return true; 207 } 208 #endif 209 210 static hb_bool_t 211 hb_directwrite_get_glyph_extents (hb_font_t *font, 212 void *font_data HB_UNUSED, 213 hb_codepoint_t glyph, 214 hb_glyph_extents_t *extents, 215 void *user_data HB_UNUSED) 216 { 217 IDWriteFontFace *dw_face = (IDWriteFontFace *) (const void *) font->data.directwrite; 218 219 UINT16 gid = glyph; 220 DWRITE_GLYPH_METRICS metrics; 221 222 if (FAILED (dw_face->GetDesignGlyphMetrics (&gid, 1, &metrics))) 223 return false; 224 225 extents->x_bearing = font->em_scale_x (metrics.leftSideBearing); 226 extents->y_bearing = font->em_scale_y (metrics.verticalOriginY - metrics.topSideBearing); 227 extents->width = font->em_scale_x (metrics.advanceWidth - metrics.rightSideBearing) - extents->x_bearing; 228 extents->height = font->em_scale_y (metrics.verticalOriginY - metrics.advanceHeight + metrics.bottomSideBearing) - extents->y_bearing; // Magic 229 230 return true; 231 } 232 233 234 #ifndef HB_NO_DRAW 235 236 class GeometrySink : public IDWriteGeometrySink 237 { 238 hb_font_t *font; 239 hb_draw_session_t drawing; 240 241 public: 242 GeometrySink(hb_font_t *font, 243 hb_draw_funcs_t *draw_funcs, 244 void *draw_data) 245 : font (font), drawing ({draw_funcs, draw_data}) {} 246 247 virtual ~GeometrySink() {} 248 249 HRESULT STDMETHODCALLTYPE Close() override { return S_OK; } 250 void STDMETHODCALLTYPE SetFillMode(D2D1_FILL_MODE) override {} 251 void STDMETHODCALLTYPE SetSegmentFlags(D2D1_PATH_SEGMENT) override {} 252 253 IFACEMETHOD(QueryInterface)(REFIID, void **) override { return E_NOINTERFACE; } 254 IFACEMETHOD_(ULONG, AddRef)() override { return 1; } 255 IFACEMETHOD_(ULONG, Release)() override { return 1; } 256 257 void STDMETHODCALLTYPE BeginFigure(D2D1_POINT_2F startPoint, D2D1_FIGURE_BEGIN) override 258 { 259 drawing.move_to (font->em_scalef_x (startPoint.x), -font->em_scalef_y (startPoint.y)); 260 } 261 262 void STDMETHODCALLTYPE AddBeziers(const D2D1_BEZIER_SEGMENT *beziers, UINT beziersCount) override 263 { 264 for (unsigned i = 0; i < beziersCount; ++i) 265 drawing.cubic_to (font->em_scalef_x (beziers[i].point1.x), -font->em_scalef_y (beziers[i].point1.y), 266 font->em_scalef_x (beziers[i].point2.x), -font->em_scalef_y (beziers[i].point2.y), 267 font->em_scalef_x (beziers[i].point3.x), -font->em_scalef_y (beziers[i].point3.y)); 268 } 269 270 void STDMETHODCALLTYPE AddLines(const D2D1_POINT_2F *points, UINT pointsCount) override 271 { 272 for (unsigned i = 0; i < pointsCount; ++i) 273 drawing.line_to (font->em_scalef_x (points[i].x), -font->em_scalef_y (points[i].y)); 274 } 275 276 void STDMETHODCALLTYPE EndFigure(D2D1_FIGURE_END) override 277 { 278 drawing.close_path (); 279 } 280 }; 281 282 static hb_bool_t 283 hb_directwrite_draw_glyph_or_fail (hb_font_t *font, 284 void *font_data HB_UNUSED, 285 hb_codepoint_t glyph, 286 hb_draw_funcs_t *draw_funcs, void *draw_data, 287 void *user_data) 288 { 289 IDWriteFontFace *dw_face = (IDWriteFontFace *) (const void *) font->data.directwrite; 290 291 GeometrySink sink (font, draw_funcs, draw_data); 292 UINT16 gid = static_cast<UINT16>(glyph); 293 unsigned upem = font->face->get_upem(); 294 295 return S_OK == dw_face->GetGlyphRunOutline (upem, 296 &gid, nullptr, nullptr, 297 1, 298 false, false, 299 &sink); 300 } 301 302 #endif 303 304 static inline void free_static_directwrite_funcs (); 305 306 static struct hb_directwrite_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_directwrite_font_funcs_lazy_loader_t> 307 { 308 static hb_font_funcs_t *create () 309 { 310 hb_font_funcs_t *funcs = hb_font_funcs_create (); 311 312 hb_font_funcs_set_nominal_glyphs_func (funcs, hb_directwrite_get_nominal_glyphs, nullptr, nullptr); 313 //hb_font_funcs_set_variation_glyph_func (funcs, hb_directwrite_get_variation_glyph, nullptr, nullptr); 314 315 hb_font_funcs_set_font_h_extents_func (funcs, hb_directwrite_get_font_h_extents, nullptr, nullptr); 316 hb_font_funcs_set_glyph_h_advances_func (funcs, hb_directwrite_get_glyph_h_advances, nullptr, nullptr); 317 318 #ifndef HB_NO_VERTICAL 319 hb_font_funcs_set_glyph_v_advances_func (funcs, hb_directwrite_get_glyph_v_advances, nullptr, nullptr); 320 hb_font_funcs_set_glyph_v_origin_func (funcs, hb_directwrite_get_glyph_v_origin, nullptr, nullptr); 321 #endif 322 323 #ifndef HB_NO_DRAW 324 hb_font_funcs_set_draw_glyph_or_fail_func (funcs, hb_directwrite_draw_glyph_or_fail, nullptr, nullptr); 325 #endif 326 327 hb_font_funcs_set_glyph_extents_func (funcs, hb_directwrite_get_glyph_extents, nullptr, nullptr); 328 329 #ifndef HB_NO_OT_FONT_GLYPH_NAMES 330 //hb_font_funcs_set_glyph_name_func (funcs, hb_directwrite_get_glyph_name, nullptr, nullptr); 331 //hb_font_funcs_set_glyph_from_name_func (funcs, hb_directwrite_get_glyph_from_name, nullptr, nullptr); 332 #endif 333 334 hb_font_funcs_make_immutable (funcs); 335 336 hb_atexit (free_static_directwrite_funcs); 337 338 return funcs; 339 } 340 } static_directwrite_funcs; 341 342 static inline 343 void free_static_directwrite_funcs () 344 { 345 static_directwrite_funcs.free_instance (); 346 } 347 348 static hb_font_funcs_t * 349 _hb_directwrite_get_font_funcs () 350 { 351 return static_directwrite_funcs.get_unconst (); 352 } 353 354 /** 355 * hb_directwrite_font_set_funcs: 356 * @font: #hb_font_t to work upon 357 * 358 * Configures the font-functions structure of the specified 359 * #hb_font_t font object to use DirectWrite font functions. 360 * 361 * In particular, you can use this function to configure an 362 * existing #hb_face_t face object for use with DirectWrite font 363 * functions even if that #hb_face_t face object was initially 364 * created with hb_face_create(), and therefore was not 365 * initially configured to use DirectWrite font functions. 366 * 367 * <note>Note: Internally, this function creates a DirectWrite font. 368 * </note> 369 * 370 * Since: 11.0.0 371 **/ 372 void 373 hb_directwrite_font_set_funcs (hb_font_t *font) 374 { 375 IDWriteFontFace *dw_face = (IDWriteFontFace *) (const void *) font->data.directwrite; 376 if (unlikely (!dw_face)) 377 { 378 hb_font_set_funcs (font, 379 hb_font_funcs_get_empty (), 380 nullptr, nullptr); 381 return; 382 } 383 384 dw_face->AddRef (); 385 hb_font_set_funcs (font, 386 _hb_directwrite_get_font_funcs (), 387 nullptr, nullptr); 388 } 389 390 #undef MAX_GLYPHS 391 392 #endif