@@ -218,6 +218,12 @@ FT2Font::FT2Font(FT_Open_Args &open_args,
218218{
219219 clear ();
220220 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+
221227 if (open_args.stream != nullptr ) {
222228 face->face_flags |= FT_FACE_FLAG_EXTERNAL_STREAM;
223229 }
@@ -329,60 +335,88 @@ void FT2Font::set_text(
329335 bbox.xMin = bbox.yMin = 32000 ;
330336 bbox.xMax = bbox.yMax = -32000 ;
331337
332- FT_UInt previous = 0 ;
333- FT2Font *previous_ft_object = nullptr ;
338+ auto rq = raqm_create ();
339+ if (!rq) {
340+ throw std::runtime_error (" failed to compute text layout" );
341+ }
342+ [[maybe_unused]] auto const & rq_cleanup =
343+ std::unique_ptr<std::remove_pointer_t <raqm_t >, decltype (&raqm_destroy)>(
344+ rq, raqm_destroy);
345+
346+ if (!raqm_set_text (rq, reinterpret_cast <const uint32_t *>(text.data ()),
347+ text.size ()))
348+ {
349+ throw std::runtime_error (" failed to set text for layout" );
350+ }
334351
335- for (auto codepoint : text) {
336- FT_UInt glyph_index = 0 ;
337- FT_BBox glyph_bbox;
338- FT_Pos last_advance;
352+ if (!raqm_set_freetype_face (rq, face)) {
353+ throw std::runtime_error (" failed to set text face for layout" );
354+ }
339355
340- FT_Error charcode_error, glyph_error;
341- std::set<FT_String*> glyph_seen_fonts;
342- FT2Font *ft_object_with_glyph = this ;
343- bool was_found = load_char_with_fallback (ft_object_with_glyph, glyph_index, glyphs,
344- char_to_font, codepoint, flags,
345- charcode_error, glyph_error, glyph_seen_fonts, false );
346- if (!was_found) {
347- ft_glyph_warn ((FT_ULong)codepoint, glyph_seen_fonts);
348- // render missing glyph tofu
349- // come back to top-most font
350- ft_object_with_glyph = this ;
351- char_to_font[codepoint] = ft_object_with_glyph;
352- ft_object_with_glyph->load_glyph (glyph_index, flags);
353- } else if (ft_object_with_glyph->warn_if_used ) {
354- ft_glyph_warn ((FT_ULong)codepoint, glyph_seen_fonts);
355- }
356+ if (!raqm_set_freetype_load_flags (rq, flags)) {
357+ throw std::runtime_error (" failed to set text flags for layout" );
358+ }
359+
360+ std::set<FT_String*> glyph_seen_fonts;
361+ glyph_seen_fonts.insert (face->family_name );
362+
363+ if (!raqm_layout (rq)) {
364+ throw std::runtime_error (" failed to layout text" );
365+ }
366+
367+
368+ size_t num_glyphs = 0 ;
369+ auto const & rq_glyphs = raqm_get_glyphs (rq, &num_glyphs);
370+
371+ for (size_t i = 0 ; i < num_glyphs; i++) {
372+ auto const & rglyph = rq_glyphs[i];
356373
357- // retrieve kerning distance and move pen position
358- if ((ft_object_with_glyph == previous_ft_object) && // if both fonts are the same
359- ft_object_with_glyph->has_kerning () && // if the font knows how to kern
360- previous && glyph_index // and we really have 2 glyphs
361- ) {
362- pen.x += ft_object_with_glyph->get_kerning (previous, glyph_index, FT_KERNING_DEFAULT);
374+ // Warn for missing glyphs.
375+ if (rglyph.index == 0 ) {
376+ ft_glyph_warn (text[rglyph.cluster ], glyph_seen_fonts);
377+ continue ;
378+ }
379+ FT2Font *wrapped_font = static_cast <FT2Font *>(rglyph.ftface ->generic .data );
380+ if (wrapped_font->warn_if_used ) {
381+ ft_glyph_warn (text[rglyph.cluster ], glyph_seen_fonts);
363382 }
364383
365384 // extract glyph image and store it in our table
366- FT_Glyph &thisGlyph = glyphs[glyphs.size () - 1 ];
385+ FT_Error error;
386+ error = FT_Load_Glyph (rglyph.ftface , rglyph.index , flags);
387+ if (error) {
388+ throw std::runtime_error (" failed to load glyph" );
389+ }
390+ FT_Glyph thisGlyph;
391+ error = FT_Get_Glyph (rglyph.ftface ->glyph , &thisGlyph);
392+ if (error) {
393+ throw std::runtime_error (" failed to get glyph" );
394+ }
395+
396+ pen.x += rglyph.x_offset ;
397+ pen.y += rglyph.y_offset ;
367398
368- last_advance = ft_object_with_glyph->get_face ()->glyph ->advance .x ;
369399 FT_Glyph_Transform (thisGlyph, nullptr , &pen);
370400 FT_Glyph_Transform (thisGlyph, &matrix, nullptr );
371401 xys.push_back (pen.x );
372402 xys.push_back (pen.y );
373403
404+ FT_BBox glyph_bbox;
374405 FT_Glyph_Get_CBox (thisGlyph, FT_GLYPH_BBOX_SUBPIXELS, &glyph_bbox);
375406
376407 bbox.xMin = std::min (bbox.xMin , glyph_bbox.xMin );
377408 bbox.xMax = std::max (bbox.xMax , glyph_bbox.xMax );
378409 bbox.yMin = std::min (bbox.yMin , glyph_bbox.yMin );
379410 bbox.yMax = std::max (bbox.yMax , glyph_bbox.yMax );
380411
381- pen.x += last_advance;
382-
383- previous = glyph_index;
384- previous_ft_object = ft_object_with_glyph;
412+ if ((flags & FT_LOAD_NO_HINTING) != 0 ) {
413+ pen.x += rglyph.x_advance - rglyph.x_offset ;
414+ } else {
415+ pen.x += hinting_factor * rglyph.x_advance - rglyph.x_offset ;
416+ }
417+ pen.y += rglyph.y_advance - rglyph.y_offset ;
385418
419+ glyphs.push_back (thisGlyph);
386420 }
387421
388422 FT_Vector_Transform (&pen, &matrix);
0 commit comments