@@ -227,6 +227,11 @@ void FT2Font::open(FT_Open_Args &open_args)
227227 if (open_args.stream != nullptr ) {
228228 face->face_flags |= FT_FACE_FLAG_EXTERNAL_STREAM;
229229 }
230+
231+ // This allows us to get back to our data if we need it, though it makes a pointer
232+ // loop, so don't set a free-function for it.
233+ face->generic .data = this ;
234+ face->generic .finalizer = nullptr ;
230235}
231236
232237void FT2Font::close ()
@@ -333,60 +338,88 @@ void FT2Font::set_text(
333338 bbox.xMin = bbox.yMin = 32000 ;
334339 bbox.xMax = bbox.yMax = -32000 ;
335340
336- FT_UInt previous = 0 ;
337- FT2Font *previous_ft_object = nullptr ;
341+ auto rq = raqm_create ();
342+ if (!rq) {
343+ throw std::runtime_error (" failed to compute text layout" );
344+ }
345+ [[maybe_unused]] auto const & rq_cleanup =
346+ std::unique_ptr<std::remove_pointer_t <raqm_t >, decltype (&raqm_destroy)>(
347+ rq, raqm_destroy);
348+
349+ if (!raqm_set_text (rq, reinterpret_cast <const uint32_t *>(text.data ()),
350+ text.size ()))
351+ {
352+ throw std::runtime_error (" failed to set text for layout" );
353+ }
338354
339- for (auto codepoint : text) {
340- FT_UInt glyph_index = 0 ;
341- FT_BBox glyph_bbox;
342- FT_Pos last_advance;
355+ if (!raqm_set_freetype_face (rq, face)) {
356+ throw std::runtime_error (" failed to set text face for layout" );
357+ }
343358
344- FT_Error charcode_error, glyph_error;
345- std::set<FT_String*> glyph_seen_fonts;
346- FT2Font *ft_object_with_glyph = this ;
347- bool was_found = load_char_with_fallback (ft_object_with_glyph, glyph_index, glyphs,
348- char_to_font, codepoint, flags,
349- charcode_error, glyph_error, glyph_seen_fonts, false );
350- if (!was_found) {
351- ft_glyph_warn ((FT_ULong)codepoint, glyph_seen_fonts);
352- // render missing glyph tofu
353- // come back to top-most font
354- ft_object_with_glyph = this ;
355- char_to_font[codepoint] = ft_object_with_glyph;
356- ft_object_with_glyph->load_glyph (glyph_index, flags);
357- } else if (ft_object_with_glyph->warn_if_used ) {
358- ft_glyph_warn ((FT_ULong)codepoint, glyph_seen_fonts);
359- }
359+ if (!raqm_set_freetype_load_flags (rq, flags)) {
360+ throw std::runtime_error (" failed to set text flags for layout" );
361+ }
362+
363+ std::set<FT_String*> glyph_seen_fonts;
364+ glyph_seen_fonts.insert (face->family_name );
365+
366+ if (!raqm_layout (rq)) {
367+ throw std::runtime_error (" failed to layout text" );
368+ }
360369
361- // retrieve kerning distance and move pen position
362- if ((ft_object_with_glyph == previous_ft_object) && // if both fonts are the same
363- ft_object_with_glyph->has_kerning () && // if the font knows how to kern
364- previous && glyph_index // and we really have 2 glyphs
365- ) {
366- pen.x += ft_object_with_glyph->get_kerning (previous, glyph_index, FT_KERNING_DEFAULT);
370+
371+ size_t num_glyphs = 0 ;
372+ auto const & rq_glyphs = raqm_get_glyphs (rq, &num_glyphs);
373+
374+ for (size_t i = 0 ; i < num_glyphs; i++) {
375+ auto const & rglyph = rq_glyphs[i];
376+
377+ // Warn for missing glyphs.
378+ if (rglyph.index == 0 ) {
379+ ft_glyph_warn (text[rglyph.cluster ], glyph_seen_fonts);
380+ continue ;
381+ }
382+ FT2Font *wrapped_font = static_cast <FT2Font *>(rglyph.ftface ->generic .data );
383+ if (wrapped_font->warn_if_used ) {
384+ ft_glyph_warn (text[rglyph.cluster ], glyph_seen_fonts);
367385 }
368386
369387 // extract glyph image and store it in our table
370- FT_Glyph &thisGlyph = glyphs[glyphs.size () - 1 ];
388+ FT_Error error;
389+ error = FT_Load_Glyph (rglyph.ftface , rglyph.index , flags);
390+ if (error) {
391+ throw std::runtime_error (" failed to load glyph" );
392+ }
393+ FT_Glyph thisGlyph;
394+ error = FT_Get_Glyph (rglyph.ftface ->glyph , &thisGlyph);
395+ if (error) {
396+ throw std::runtime_error (" failed to get glyph" );
397+ }
398+
399+ pen.x += rglyph.x_offset ;
400+ pen.y += rglyph.y_offset ;
371401
372- last_advance = ft_object_with_glyph->get_face ()->glyph ->advance .x ;
373402 FT_Glyph_Transform (thisGlyph, nullptr , &pen);
374403 FT_Glyph_Transform (thisGlyph, &matrix, nullptr );
375404 xys.push_back (pen.x );
376405 xys.push_back (pen.y );
377406
407+ FT_BBox glyph_bbox;
378408 FT_Glyph_Get_CBox (thisGlyph, FT_GLYPH_BBOX_SUBPIXELS, &glyph_bbox);
379409
380410 bbox.xMin = std::min (bbox.xMin , glyph_bbox.xMin );
381411 bbox.xMax = std::max (bbox.xMax , glyph_bbox.xMax );
382412 bbox.yMin = std::min (bbox.yMin , glyph_bbox.yMin );
383413 bbox.yMax = std::max (bbox.yMax , glyph_bbox.yMax );
384414
385- pen.x += last_advance;
386-
387- previous = glyph_index;
388- previous_ft_object = ft_object_with_glyph;
415+ if ((flags & FT_LOAD_NO_HINTING) != 0 ) {
416+ pen.x += rglyph.x_advance - rglyph.x_offset ;
417+ } else {
418+ pen.x += hinting_factor * rglyph.x_advance - rglyph.x_offset ;
419+ }
420+ pen.y += rglyph.y_advance - rglyph.y_offset ;
389421
422+ glyphs.push_back (thisGlyph);
390423 }
391424
392425 FT_Vector_Transform (&pen, &matrix);
0 commit comments