Bug 48844 - (SkiaSharp) SKCanvas.DrawText does not render Unicode characters
Summary: (SkiaSharp) SKCanvas.DrawText does not render Unicode characters
Alias: None
Product: Android
Classification: Xamarin
Component: General ()
Version: 4.0
Hardware: PC Windows
: --- normal
Target Milestone: ---
Assignee: Jonathan Pryor
Depends on:
Reported: 2016-12-02 21:19 UTC by Brian Fallon
Modified: 2017-02-06 17:48 UTC (History)
2 users (show)

Is this bug a regression?: ---
Last known good build:

VS2015 Xamarin Android (Native) project referencing SkiaSharp 1.55.1 (13.30 KB, application/x-zip-compressed)
2016-12-02 21:19 UTC, Brian Fallon

Notice (2018-05-24): bugzilla.xamarin.com is now in read-only mode.

Please join us on Visual Studio Developer Community and in the Xamarin and Mono organizations on GitHub to continue tracking issues. Bugzilla will remain available for reference in read-only mode. We will continue to work on open Bugzilla bugs, copy them to the new locations as needed for follow-up, and add the new items under Related Links.

Our sincere thanks to everyone who has contributed on this bug tracker over the years. Thanks also for your understanding as we make these adjustments and improvements for the future.

Please create a new report on Developer Community or GitHub with your current version information, steps to reproduce, and relevant error messages or log files if you are hitting an issue that looks similar to this resolved bug and you do not yet see a matching new report.

Related Links:

Description Brian Fallon 2016-12-02 21:19:19 UTC
Created attachment 18759 [details]
VS2015 Xamarin Android (Native) project referencing SkiaSharp 1.55.1

1. Open attached project. Nuget for SkiaSharp is omitted to save space so go into 'Manage NuGet Packages' and add a reference to any version of SkiSharp. I tried with 1.49.1 and 1.55.1. Note that because of a breaking change in the SKColorType enumeration, you will have to change the 'Rgba999' constant to 'Rgba_888' to compile in 1.49.1.

2. Run the project in an emulator or device (I used a Google Nexus 7 (Android 4.4 - API 19)). The sample uses SKCanvas.DrawText to draw a string, "Unicode: [ 年 月 ]" to a View.

  The Japanese characters (年, 月) are missing, and the string that appears is "Unicode: [    ]".

  The Japanese characters should appear inline along with the rest of the string.

I tried various different typefaces, and even set the language on the device to 'ja-JP', to no avail.
The Japanese characters are not garbled, or wrong, or wacky looking, they just plain aren't there.
Comment 1 Matthew Leibowitz 2017-02-04 17:02:17 UTC
This issue is being tracked here: https://github.com/mono/SkiaSharp/issues/232

Commit: https://github.com/mono/SkiaSharp/commit/485ef83acda0bb309efafedf1d4a357a5d451dee

The real issue is that Skia does not support character fallbacks. If the typeface does not contain the character, it will print a block. The GitHub issue has more information.
Comment 2 Brian Fallon 2017-02-06 15:47:06 UTC
Thanks for looking into this. If I understood the resolution correctly, the caller has to arbitrarily choose some character to pass to the MatchCharacter method in order to obtain a typeface that supports it.

This isn't really a viable solution. In my case, I was trying to localize an application, so I have a culture name (say 'ja-JP'), and at the time I decide what typeface to use, I might not have any characters available. Now, I could defer selecting a typeface until I have an actual string, but then what - do I have to analyze every character in that string to determine what typeface is appropriate? The obvious workaround there is to just use some hardcoded character that I *think* will yield a typeface appropriate for the given culture, but that would imply that I have to construct some kind of table that cross-references each culture I want to support with some character that is guaranteed to yield the most ideal typeface for that culture. This sounds extremely hacky.

Did I miss something here?
Comment 3 Matthew Leibowitz 2017-02-06 17:34:45 UTC
I'll admit it does appear quite weird why Google chose to do it this way. 

They wrote this: https://groups.google.com/forum/#!topic/skia-discuss/O4ClH4ziwVo

  This is more likely to do with font fallback. In previous versions of Skia 
  font fallback (font chaining) was implicit. Basically, every font was 
  'extended' with all of the characters/glyphs in all of the fallback fonts. 
  This became unsupportable (as the number of glyphs became too large and 
  meant that fallback could not be controlled in a app locale dependent 
  manner). As a result, you'll need to use 
  SkTypeface::matchFamilyStyleCharacter to discover a font to use with 
  glyphs which cannot be mapped.

I am not quite sure how they would expect one to support a typeface for multiple cultures. But, since you already know what culture are working with, you can select the appropriate typeface - when 'ja-JP', then use font X, and if 'en', then use font Y.

But, probably the best thing would be to ask on that forum topic, and maybe present your use case. They made a decision, and they didn't really provide a way to properly draw text. I'll be watching that post, and if they point out any members that you should use, I'll make sure that they are bound.
Comment 4 Brian Fallon 2017-02-06 17:48:08 UTC
I think you're right, the simplest and cleanest solution is to explicitly set a typeface based on the culture. I guess I was thinking about this with my Windows hat on; Windows resolves the ambient font based on the current culture, but that functionality doesn't seem to be quite as intrinsic on other platforms, hence this seemingly missing functionality.

Thanks again for looking into this.