@@ -27,6 +27,8 @@ along with LiveCode. If not see <http://www.gnu.org/licenses/>. */
2727#include < SkTypeface.h>
2828#include < SkPoint.h>
2929#include < SkTypes.h>
30+ #include < SkFontMgr.h>
31+ #include < SkUtils.h>
3032
3133#include " foundation-unicode.h"
3234#include < unicode/uscript.h>
@@ -65,10 +67,10 @@ struct MCGlyphRun
6567 sk_sp<SkTypeface> typeface;
6668};
6769
68- void MCGlyphRunMake (hb_glyph_info_t *p_infos, hb_glyph_position_t *p_positions, MCGPoint* x_location, uindex_t p_start, uindex_t p_end, const MCGFont &p_font , MCGlyphRun& r_run)
70+ void MCGlyphRunMake (hb_glyph_info_t *p_infos, hb_glyph_position_t *p_positions, MCGPoint* x_location, uindex_t p_start, uindex_t p_end, SkTypeface* p_typeface, uint16_t p_size , MCGlyphRun& r_run)
6971{
7072 // Skia APIs expect typefaces to be passed as shared pointers
71- sk_sp<SkTypeface> t_typeface ((SkTypeface*)p_font. fid );
73+ sk_sp<SkTypeface> t_typeface (p_typeface );
7274 t_typeface->ref ();
7375
7476 uindex_t t_count = p_end - p_start;
@@ -99,7 +101,7 @@ void MCGlyphRunMake(hb_glyph_info_t *p_infos, hb_glyph_position_t *p_positions,
99101 else
100102 {
101103 uindex_t advance;
102- skia_get_replacement_glyph (p_font . size , t_typeface, r_run . glyphs[run_index], advance);
104+ skia_get_replacement_glyph (p_size , t_typeface, r_run . glyphs[run_index], advance);
103105 advance_x += advance;
104106 }
105107
@@ -234,31 +236,37 @@ MCHarfbuzzSkiaFace *MCHarfbuzzGetFaceForSkiaTypeface(SkTypeface *p_typeface, uin
234236 return nil;
235237}
236238
237- void shape (const unichar_t * p_text, uindex_t p_char_count, MCGPoint p_location, bool p_rtl, const MCGFont &p_font, MCGlyphRun*& r_runs, uindex_t & r_run_count )
239+ static 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 )
238240{
239- MCAutoArray<MCGlyphRun> t_runs;
240-
241- if (p_font . fid == nil)
242- {
243- MCLog (" %s: Found null font!" , __FUNCTION__);
244- r_run_count = 0 ;
245- r_runs = nil;
246- return ;
247- }
248-
249- SkTypeface *t_typeface = (SkTypeface *)p_font . fid;
250-
251- // MCLog("typeface name %d", t_typeface -> uniqueID());
241+ if (p_font . fid == nil)
242+ return 0 ;
243+
244+ SkTypeface *t_typeface = nil;
245+ if (p_use_fallback)
246+ {
247+ // If we're to use a fallback font, use Skia's font manager to find a
248+ // font that has glyphs for the first char in the string.
249+ const unichar_t * t_text = p_text;
250+ SkUnichar t_uni_char = SkUTF16_NextUnichar (&t_text);
251+ sk_sp<SkFontMgr> t_fnt_mgr (SkFontMgr::RefDefault ());
252+ t_typeface = t_fnt_mgr -> matchFamilyStyleCharacter (nil, ((SkTypeface *)p_font . fid) -> fontStyle (), nil, 0 , t_uni_char);
253+
254+ // If there is no fallback font for the char, use the replacement glyph
255+ // in the original font.
256+ if (t_typeface == nil)
257+ t_typeface = (SkTypeface *)p_font . fid;
258+ }
259+ else
260+ t_typeface = (SkTypeface *)p_font . fid;
261+
262+ if (t_typeface == nil)
263+ return 0 ;
252264
253265 MCHarfbuzzSkiaFace *t_hb_sk_face;
254266 t_hb_sk_face = MCHarfbuzzGetFaceForSkiaTypeface (t_typeface, p_font . size);
255267
256268 if (t_hb_sk_face == nil)
257- {
258- r_run_count = 0 ;
259- r_runs = nil;
260- return ;
261- }
269+ return 0 ;
262270
263271 // Set up the HarfBuzz buffer
264272 hb_buffer_t *buffer = hb_buffer_create ();
@@ -271,59 +279,85 @@ void shape(const unichar_t* p_text, uindex_t p_char_count, MCGPoint p_location,
271279
272280 hb_shape (HBSkiaFaceToHBFont (t_hb_sk_face), buffer, NULL , 0 );
273281
274- int glyph_count = hb_buffer_get_length (buffer);
282+ uindex_t glyph_count = hb_buffer_get_length (buffer);
275283 hb_glyph_info_t *glyph_info = hb_buffer_get_glyph_infos (buffer, 0 );
276284 hb_glyph_position_t *glyph_pos = hb_buffer_get_glyph_positions (buffer, 0 );
277285
278- uindex_t t_cur_glyph = 0 ;
279- uindex_t t_start, t_end;
280- uindex_t t_char_index = 0 ;
281-
286+ uindex_t t_cur_glyph = 0 , t_start = 0 , t_run_count = 0 ;
287+
282288 // deal with runs of supported and unsupported glyphs
283289 while (t_cur_glyph < glyph_count)
284290 {
285291 MCGlyphRun t_run;
286- t_start = t_end = t_cur_glyph;
292+ t_start = t_cur_glyph;
287293
288294 // Run of successfully shaped glyphs
289295 while (t_cur_glyph < glyph_count && glyph_info[t_cur_glyph] . codepoint != 0 )
290296 {
291- t_char_index++;
292- t_end++;
293297 t_cur_glyph++;
294298 }
295299
296- if (t_start != t_end )
300+ if (t_start != t_cur_glyph )
297301 {
298- MCGlyphRunMake (glyph_info, glyph_pos, &p_location , t_start, t_end, p_font, t_run);
299- t_runs . Push (t_run);
302+ MCGlyphRunMake (glyph_info, glyph_pos, x_location , t_start, t_cur_glyph, t_typeface, p_font . size , t_run);
303+ x_runs . Push (t_run);
300304 t_start = t_cur_glyph;
301- t_end = t_cur_glyph;
305+ t_run_count++;
306+ }
307+
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)
311+ {
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);
315+ x_runs . Push (t_run);
316+ t_start = t_cur_glyph;
317+ t_run_count++;
302318 }
303319
304320 // Deal with run of unsupported characters for this font.
305321 while (t_cur_glyph < glyph_count && glyph_info[t_cur_glyph] . codepoint == 0 )
306322 {
307- t_end++;
308323 t_cur_glyph++;
309324 }
310325
311- if (t_start != t_end)
326+ // For the run of unsupported chars, shape using a fallback font.
327+ if (t_start != t_cur_glyph)
312328 {
313- // Need to get a fallback font here.
314- // For now, just fail to display the glyphs. Should display 'missing character' glyph.
315- MCGlyphRunMake (glyph_info, glyph_pos, &p_location, t_start, t_end, p_font, t_run);
316- t_runs . Push (t_run);
317-
329+ t_run_count += shape_text_and_add_to_glyph_array (
330+ p_text + glyph_info[t_start] . cluster,
331+ glyph_info[t_cur_glyph - 1 ] . cluster - glyph_info[t_start] . cluster + 1 ,
332+ p_rtl,
333+ p_font,
334+ true ,
335+ x_location,
336+ x_runs
337+ );
318338 t_start = t_cur_glyph;
319- t_end = t_cur_glyph;
320339 }
321-
322- t_char_index += (t_end - t_start);
323340 }
324341
325342 hb_buffer_destroy (buffer);
326- t_runs . Take (r_runs, r_run_count);
343+ return t_run_count;
344+ }
345+
346+ void shape (const unichar_t * p_text, uindex_t p_char_count, MCGPoint p_location, bool p_rtl, const MCGFont &p_font, MCGlyphRun*& r_runs, uindex_t & r_run_count)
347+ {
348+ MCAutoArray<MCGlyphRun> t_runs;
349+ uindex_t t_run_count = shape_text_and_add_to_glyph_array (p_text, p_char_count, p_rtl, p_font, false , &p_location, t_runs);
350+
351+ if (t_run_count == 0 )
352+ {
353+ r_run_count = 0 ;
354+ r_runs = nil;
355+ }
356+ else
357+ {
358+ r_run_count = t_run_count;
359+ t_runs . Take (r_runs, r_run_count);
360+ }
327361}
328362
329363// //////////////////////////////////////////////////////////////////////////////
0 commit comments