@@ -218,6 +218,12 @@ FT2Font::FT2Font(FT_Open_Args &open_args,
218
218
{
219
219
clear ();
220
220
FT_CHECK (FT_Open_Face, _ft2Library, &open_args, 0 , &face);
221
+
222
+ // This allows us to get back to our data if we need it, though it makes a pointer
223
+ // loop, so don't set a free-function for it.
224
+ face->generic .data = this ;
225
+ face->generic .finalizer = nullptr ;
226
+
221
227
if (open_args.stream != nullptr ) {
222
228
face->face_flags |= FT_FACE_FLAG_EXTERNAL_STREAM;
223
229
}
@@ -323,60 +329,88 @@ void FT2Font::set_text(
323
329
bbox.xMin = bbox.yMin = 32000 ;
324
330
bbox.xMax = bbox.yMax = -32000 ;
325
331
326
- FT_UInt previous = 0 ;
327
- FT2Font *previous_ft_object = nullptr ;
332
+ auto rq = raqm_create ();
333
+ if (!rq) {
334
+ throw std::runtime_error (" failed to compute text layout" );
335
+ }
336
+ [[maybe_unused]] auto const & rq_cleanup =
337
+ std::unique_ptr<std::remove_pointer_t <raqm_t >, decltype (&raqm_destroy)>(
338
+ rq, raqm_destroy);
339
+
340
+ if (!raqm_set_text (rq, reinterpret_cast <const uint32_t *>(text.data ()),
341
+ text.size ()))
342
+ {
343
+ throw std::runtime_error (" failed to set text for layout" );
344
+ }
328
345
329
- for (auto codepoint : text) {
330
- FT_UInt glyph_index = 0 ;
331
- FT_BBox glyph_bbox;
332
- FT_Pos last_advance;
346
+ if (!raqm_set_freetype_face (rq, face)) {
347
+ throw std::runtime_error (" failed to set text face for layout" );
348
+ }
333
349
334
- FT_Error charcode_error, glyph_error;
335
- std::set<FT_String*> glyph_seen_fonts;
336
- FT2Font *ft_object_with_glyph = this ;
337
- bool was_found = load_char_with_fallback (ft_object_with_glyph, glyph_index, glyphs,
338
- char_to_font, codepoint, flags,
339
- charcode_error, glyph_error, glyph_seen_fonts, false );
340
- if (!was_found) {
341
- ft_glyph_warn ((FT_ULong)codepoint, glyph_seen_fonts);
342
- // render missing glyph tofu
343
- // come back to top-most font
344
- ft_object_with_glyph = this ;
345
- char_to_font[codepoint] = ft_object_with_glyph;
346
- ft_object_with_glyph->load_glyph (glyph_index, flags);
347
- } else if (ft_object_with_glyph->warn_if_used ) {
348
- ft_glyph_warn ((FT_ULong)codepoint, glyph_seen_fonts);
349
- }
350
+ if (!raqm_set_freetype_load_flags (rq, flags)) {
351
+ throw std::runtime_error (" failed to set text flags for layout" );
352
+ }
353
+
354
+ std::set<FT_String*> glyph_seen_fonts;
355
+ glyph_seen_fonts.insert (face->family_name );
356
+
357
+ if (!raqm_layout (rq)) {
358
+ throw std::runtime_error (" failed to layout text" );
359
+ }
360
+
361
+
362
+ size_t num_glyphs = 0 ;
363
+ auto const & rq_glyphs = raqm_get_glyphs (rq, &num_glyphs);
364
+
365
+ for (size_t i = 0 ; i < num_glyphs; i++) {
366
+ auto const & rglyph = rq_glyphs[i];
350
367
351
- // retrieve kerning distance and move pen position
352
- if ((ft_object_with_glyph == previous_ft_object) && // if both fonts are the same
353
- ft_object_with_glyph->has_kerning () && // if the font knows how to kern
354
- previous && glyph_index // and we really have 2 glyphs
355
- ) {
356
- pen.x += ft_object_with_glyph->get_kerning (previous, glyph_index, FT_KERNING_DEFAULT);
368
+ // Warn for missing glyphs.
369
+ if (rglyph.index == 0 ) {
370
+ ft_glyph_warn (text[rglyph.cluster ], glyph_seen_fonts);
371
+ continue ;
372
+ }
373
+ FT2Font *wrapped_font = static_cast <FT2Font *>(rglyph.ftface ->generic .data );
374
+ if (wrapped_font->warn_if_used ) {
375
+ ft_glyph_warn (text[rglyph.cluster ], glyph_seen_fonts);
357
376
}
358
377
359
378
// extract glyph image and store it in our table
360
- FT_Glyph &thisGlyph = glyphs[glyphs.size () - 1 ];
379
+ FT_Error error;
380
+ error = FT_Load_Glyph (rglyph.ftface , rglyph.index , flags);
381
+ if (error) {
382
+ throw std::runtime_error (" failed to load glyph" );
383
+ }
384
+ FT_Glyph thisGlyph;
385
+ error = FT_Get_Glyph (rglyph.ftface ->glyph , &thisGlyph);
386
+ if (error) {
387
+ throw std::runtime_error (" failed to get glyph" );
388
+ }
389
+
390
+ pen.x += rglyph.x_offset ;
391
+ pen.y += rglyph.y_offset ;
361
392
362
- last_advance = ft_object_with_glyph->get_face ()->glyph ->advance .x ;
363
393
FT_Glyph_Transform (thisGlyph, nullptr , &pen);
364
394
FT_Glyph_Transform (thisGlyph, &matrix, nullptr );
365
395
xys.push_back (pen.x );
366
396
xys.push_back (pen.y );
367
397
398
+ FT_BBox glyph_bbox;
368
399
FT_Glyph_Get_CBox (thisGlyph, FT_GLYPH_BBOX_SUBPIXELS, &glyph_bbox);
369
400
370
401
bbox.xMin = std::min (bbox.xMin , glyph_bbox.xMin );
371
402
bbox.xMax = std::max (bbox.xMax , glyph_bbox.xMax );
372
403
bbox.yMin = std::min (bbox.yMin , glyph_bbox.yMin );
373
404
bbox.yMax = std::max (bbox.yMax , glyph_bbox.yMax );
374
405
375
- pen.x += last_advance;
376
-
377
- previous = glyph_index;
378
- previous_ft_object = ft_object_with_glyph;
406
+ if ((flags & FT_LOAD_NO_HINTING) != 0 ) {
407
+ pen.x += rglyph.x_advance - rglyph.x_offset ;
408
+ } else {
409
+ pen.x += hinting_factor * rglyph.x_advance - rglyph.x_offset ;
410
+ }
411
+ pen.y += rglyph.y_advance - rglyph.y_offset ;
379
412
413
+ glyphs.push_back (thisGlyph);
380
414
}
381
415
382
416
FT_Vector_Transform (&pen, &matrix);
0 commit comments