@@ -236,6 +236,26 @@ MCHarfbuzzSkiaFace *MCHarfbuzzGetFaceForSkiaTypeface(SkTypeface *p_typeface, uin
236236 return nil;
237237}
238238
239+ // Check if the font supports all glyphs in a given cluster from shape info
240+ static bool cluster_is_supported (hb_glyph_info_t * p_info, uindex_t p_index, uindex_t p_count, uindex_t & r_cluster_end)
241+ {
242+ bool t_supported = true ;
243+ uindex_t t_cluster = p_info[p_index] . cluster;
244+ while (++p_index < p_count &&
245+ p_info[p_index] . cluster == t_cluster)
246+ {
247+ if (p_info[p_index] . codepoint == 0 )
248+ {
249+ // If any of these glyphs' codepoints are 0 then the
250+ // whole cluster is unsupported
251+ t_supported = false ;
252+ }
253+ }
254+
255+ r_cluster_end = p_index;
256+ return t_supported;
257+ }
258+
239259static uindex_t shape_text_and_add_to_glyph_array (const unichar_t * p_text, uindex_t p_char_count, bool p_rtl, const MCGFont &p_font, bool p_use_fallback, MCGPoint* x_location, MCAutoArray<MCGlyphRun>& x_runs)
240260{
241261 if (p_font . fid == nil)
@@ -284,19 +304,21 @@ static uindex_t shape_text_and_add_to_glyph_array(const unichar_t* p_text, uinde
284304 hb_glyph_position_t *glyph_pos = hb_buffer_get_glyph_positions (buffer, 0 );
285305
286306 uindex_t t_cur_glyph = 0 , t_start = 0 , t_run_count = 0 ;
287-
307+ uindex_t t_cluster_end = 0 ;
308+
288309 // deal with runs of supported and unsupported glyphs
289310 while (t_cur_glyph < glyph_count)
290311 {
291312 MCGlyphRun t_run;
292313 t_start = t_cur_glyph;
293314
294- // Run of successfully shaped glyphs
295- while (t_cur_glyph < glyph_count && glyph_info[t_cur_glyph] . codepoint != 0 )
315+ // Run of glyphs in successfully shaped clusters
316+ while (t_cur_glyph < glyph_count &&
317+ cluster_is_supported (glyph_info, t_cur_glyph, glyph_count, &t_cluster_end))
296318 {
297- t_cur_glyph++ ;
319+ t_cur_glyph = t_cluster_end ;
298320 }
299-
321+
300322 if (t_start != t_cur_glyph)
301323 {
302324 MCGlyphRunMake (glyph_info, glyph_pos, x_location, t_start, t_cur_glyph, t_typeface, p_font . size, t_run);
@@ -305,37 +327,50 @@ static uindex_t shape_text_and_add_to_glyph_array(const unichar_t* p_text, uinde
305327 t_run_count++;
306328 }
307329
308- // If the first char is unsupported and we're already using the fallback
309- // font for that char, assume there is no glyph and use a replacement.
310- if (t_cur_glyph == 0 && glyph_info[t_cur_glyph] . codepoint == 0 && p_use_fallback)
330+ // If the first cluster is unsupported and we're already using the fallback
331+ // font for that cluster, assume there is no support and use a replacement.
332+ if (t_cur_glyph == 0 &&
333+ !cluster_is_supported (glyph_info, t_cur_glyph, glyph_count, &t_cluster_end)
334+ && p_use_fallback)
311335 {
312- t_cur_glyph++;
313-
314- MCGlyphRunMake (glyph_info, glyph_pos, x_location, t_start, t_cur_glyph, (SkTypeface *)p_font . fid, p_font . size, t_run);
336+ // Enforce a replacement glyph for the whole cluster by passing a 0
337+ // codepoint and only adding a single glyph to the run
338+ glyph_info[t_cur_glyph].codepoint = 0 ;
339+ MCGlyphRunMake (glyph_info, glyph_pos, x_location, t_start, t_start + 1 , (SkTypeface *)p_font . fid, p_font . size, t_run);
315340 x_runs . Push (t_run);
341+ t_cur_glyph = t_cluster_end
316342 t_start = t_cur_glyph;
317343 t_run_count++;
318344 }
319345
320- // Deal with run of unsupported characters for this font.
321- while (t_cur_glyph < glyph_count && glyph_info[t_cur_glyph] . codepoint == 0 )
346+ // Deal with run of unsupported clusters for this font.
347+ while (t_cur_glyph < glyph_count &&
348+ !cluster_is_supported (glyph_info, t_cur_glyph, glyph_count, &t_cluster_end))
322349 {
323- t_cur_glyph++ ;
350+ t_cur_glyph = t_cluster_end ;
324351 }
325352
326- // For the run of unsupported chars , shape using a fallback font.
353+ // For the run of unsupported clusters , shape using a fallback font.
327354 if (t_start != t_cur_glyph)
328355 {
356+ // Reshape from the beginning of the unsupported cluster run
357+ // to the beginning of the cluster containing t_cur_glyph.
358+ // At this point, t_cur_glyph might be equal to glyph_count,
359+ // in which case compute the reshape char count using the old char
360+ // count.
361+ uindex_t t_end_index = p_char_count;
362+ if (t_cur_glyph != glyph_count)
363+ t_end_index = glyph_info[t_cur_glyph] . cluster;
364+
329365 t_run_count += shape_text_and_add_to_glyph_array (
330366 p_text + glyph_info[t_start] . cluster,
331- glyph_info[t_cur_glyph - 1 ] . cluster - glyph_info[t_start] . cluster + 1 ,
367+ t_end_index - glyph_info[t_start] . cluster,
332368 p_rtl,
333369 p_font,
334370 true ,
335371 x_location,
336372 x_runs
337373 );
338- t_start = t_cur_glyph;
339374 }
340375 }
341376
0 commit comments