@@ -271,6 +271,11 @@ FT2Font::FT2Font(FT_Open_Args &open_args,
271271 throw_ft_error (" Can not load face" , error);
272272 }
273273
274+ // This allows us to get back to our data if we need it, though it makes a pointer
275+ // loop, so don't set a free-function for it.
276+ face->generic .data = this ;
277+ face->generic .finalizer = nullptr ;
278+
274279 // set a default fontsize 12 pt at 72dpi
275280 error = FT_Set_Char_Size (face, 12 * 64 , 0 , 72 * (unsigned int )hinting_factor, 72 );
276281 if (error) {
@@ -417,62 +422,86 @@ void FT2Font::set_text(
417422 bbox.xMin = bbox.yMin = 32000 ;
418423 bbox.xMax = bbox.yMax = -32000 ;
419424
420- FT_UInt previous = 0 ;
421- FT2Font *previous_ft_object = nullptr ;
425+ auto rq = raqm_create ();
426+ if (!rq) {
427+ throw std::runtime_error (" failed to compute text layout" );
428+ }
429+ [[maybe_unused]] auto const & rq_cleanup =
430+ std::unique_ptr<std::remove_pointer_t <raqm_t >, decltype (&raqm_destroy)>(
431+ rq, raqm_destroy);
422432
423- for (auto codepoint : text) {
424- FT_UInt glyph_index = 0 ;
425- FT_BBox glyph_bbox;
426- FT_Pos last_advance;
433+ if (!raqm_set_text (rq, reinterpret_cast <const uint32_t *>(text.data ()), text.size ())) {
434+ throw std::runtime_error (" failed to set text for layout" );
435+ }
427436
428- FT_Error charcode_error, glyph_error;
429- std::set<FT_String*> glyph_seen_fonts;
430- FT2Font *ft_object_with_glyph = this ;
431- bool was_found = load_char_with_fallback (ft_object_with_glyph, glyph_index, glyphs,
432- char_to_font, glyph_to_font, codepoint, flags,
433- charcode_error, glyph_error, glyph_seen_fonts, false );
434- if (!was_found) {
435- ft_glyph_warn ((FT_ULong)codepoint, glyph_seen_fonts);
436- // render missing glyph tofu
437- // come back to top-most font
438- ft_object_with_glyph = this ;
439- char_to_font[codepoint] = ft_object_with_glyph;
440- glyph_to_font[glyph_index] = ft_object_with_glyph;
441- ft_object_with_glyph->load_glyph (glyph_index, flags, ft_object_with_glyph, false );
442- } else if (ft_object_with_glyph->warn_if_used ) {
443- ft_glyph_warn ((FT_ULong)codepoint, glyph_seen_fonts);
444- }
437+ if (!raqm_set_freetype_face (rq, face)) {
438+ throw std::runtime_error (" failed to set text face for layout" );
439+ }
440+
441+ if (!raqm_set_freetype_load_flags (rq, flags)) {
442+ throw std::runtime_error (" failed to set text flags for layout" );
443+ }
444+
445+ std::set<FT_String*> glyph_seen_fonts;
446+ glyph_seen_fonts.insert (face->family_name );
447+
448+ if (!raqm_layout (rq)) {
449+ throw std::runtime_error (" failed to layout text" );
450+ }
445451
446- // retrieve kerning distance and move pen position
447- if ((ft_object_with_glyph == previous_ft_object) && // if both fonts are the same
448- ft_object_with_glyph->has_kerning () && // if the font knows how to kern
449- previous && glyph_index // and we really have 2 glyphs
450- ) {
451- FT_Vector delta;
452- pen.x += ft_object_with_glyph->get_kerning (previous, glyph_index, FT_KERNING_DEFAULT, delta);
452+
453+ size_t num_glyphs = 0 ;
454+ auto const & rq_glyphs = raqm_get_glyphs (rq, &num_glyphs);
455+
456+ for (size_t i = 0 ; i < num_glyphs; i++) {
457+ auto const & rglyph = rq_glyphs[i];
458+
459+ // Warn for missing glyphs.
460+ if (rglyph.index == 0 ) {
461+ ft_glyph_warn (text[rglyph.cluster ], glyph_seen_fonts);
462+ continue ;
463+ }
464+ FT2Font *wrapped_font = static_cast <FT2Font *>(rglyph.ftface ->generic .data );
465+ if (wrapped_font->warn_if_used ) {
466+ ft_glyph_warn (text[rglyph.cluster ], glyph_seen_fonts);
453467 }
454468
455469 // extract glyph image and store it in our table
456- FT_Glyph &thisGlyph = glyphs[glyphs.size () - 1 ];
470+ FT_Error error;
471+ error = FT_Load_Glyph (rglyph.ftface , rglyph.index , flags);
472+ if (error) {
473+ throw std::runtime_error (" failed to load glyph" );
474+ }
475+ FT_Glyph thisGlyph;
476+ error = FT_Get_Glyph (rglyph.ftface ->glyph , &thisGlyph);
477+ if (error) {
478+ throw std::runtime_error (" failed to get glyph" );
479+ }
480+
481+ pen.x += rglyph.x_offset ;
482+ pen.y += rglyph.y_offset ;
457483
458- last_advance = ft_object_with_glyph->get_face ()->glyph ->advance .x ;
459484 FT_Glyph_Transform (thisGlyph, nullptr , &pen);
460485 FT_Glyph_Transform (thisGlyph, &matrix, nullptr );
461486 xys.push_back (pen.x );
462487 xys.push_back (pen.y );
463488
489+ FT_BBox glyph_bbox;
464490 FT_Glyph_Get_CBox (thisGlyph, FT_GLYPH_BBOX_SUBPIXELS, &glyph_bbox);
465491
466492 bbox.xMin = std::min (bbox.xMin , glyph_bbox.xMin );
467493 bbox.xMax = std::max (bbox.xMax , glyph_bbox.xMax );
468494 bbox.yMin = std::min (bbox.yMin , glyph_bbox.yMin );
469495 bbox.yMax = std::max (bbox.yMax , glyph_bbox.yMax );
470496
471- pen.x += last_advance;
472-
473- previous = glyph_index;
474- previous_ft_object = ft_object_with_glyph;
497+ if ((flags & FT_LOAD_NO_HINTING) != 0 ) {
498+ pen.x += rglyph.x_advance - rglyph.x_offset ;
499+ } else {
500+ pen.x += hinting_factor * rglyph.x_advance - rglyph.x_offset ;
501+ }
502+ pen.y += rglyph.y_advance - rglyph.y_offset ;
475503
504+ glyphs.push_back (thisGlyph);
476505 }
477506
478507 FT_Vector_Transform (&pen, &matrix);
0 commit comments