googlefonts / nanoemoji

A wee tool to build color fonts.
Apache License 2.0
239 stars 21 forks source link

SVG+COLRv1+CBDT font renders CBDT on Chrome Canary, COLRv1 only shows when no CBDT #406

Closed twardoch closed 2 years ago

twardoch commented 2 years ago

The BlakaInk-Regular.ttf font includes three color flavors: SVG (the SVG table), COLRv1 (the COLR and CPAL tables) and CBDT (the CBDT and CBLC tables).

The BlakaInk-Regular-color-multiflavor.zip contains the same font (as SVG-COLRv1-CBDT), and also a SVG-COLRv1 font where I removed the CBDT flavor with sfntedit -d CBDT,CBLC BlakaInk-Regular-SVG-COLRv1.ttf.

On my macOS 12.3.1:

Firefox 100.0b3

Firefox renders the SVG flavor for both fonts:

scr- 2022-04-12 at 12 53 22

Safari

Safari Technology Preview Release 143 (Safari 15.4, WebKit 17614.1.7.7), and Safari Version 15.4 (17613.1.17.1.13) render the SVG flavor for both fonts:

scr- 2022-04-12 at 12 53 27

Chrome Canary

Chrome Canary Version 102.0.4999.0 (Official Build) canary (x86_64) renders the low-res bitmap version (the CBDT flavor) for the SVG-COLRv1-CBDT font — that’s NOT GOOD:

scr- 2022-04-12 at 12 53 17

It only renders the vector COLRv1 flavor for the SVG-COLRv1 font, which does not contain the CBDT and CBLC tables:

scr- 2022-04-12 at 12 56 59

So Chrome needs to be fixed — it should give preference to COLRv1 flavor even if the CBDT flavor exists in the font.

I guess this is an issue that should be filed into the Chrome project, but I’m not sure how to do it. (Or perhaps this is already filed, but feel free to add a link to this very report there).

anthrotype commented 2 years ago

Thanks, yes, this is a known issue, I think we mention also in the README https://github.com/googlefonts/nanoemoji#adding-color-tables-to-existing-fonts

cc @drott

anthrotype commented 2 years ago

note maximum_color only adds a CBDT table if --bitmaps flag is passed, so one can omit that when building the hybrid font if not desired. The Fonts API will subset and keep only one table depending on the user agent.

drott commented 2 years ago

See https://bugs.chromium.org/p/skia/issues/detail?id=12945

twardoch commented 2 years ago

OK, good!

I never quite liked the hacking that went on regarding the relationship between CBDT and outline formats. The original monochrome spec for EBDT had the EBSC table, where you could describe (only within the uint8 range of ppms) if some other ppms should use another ppm range. But this table didn’t allow for specifying ranges, so a fully-compatible CBSC wouldn’t be practical. Which I guess why Google never suggested it.

But then FreeType originally had this behavior that if CBDT existed together with glyf, then FreeType would only show the color bitmaps at the specified ppm, and use glyf for all other ppms. This was, I guess, because that’s how the monochrome counterpart (EBDT) behaved, and rightly so. But EBDT was a "fine-tuned" variant of the glyf outlines while CBDT provided, well, something else. AFAIR, FreeType showed the CBDT in all ppms only if the font had no glyf table.

Then Microsoft’s support for CBDT was different than Android’s, I guess.

And now we’re facing this again. Prioritizing COLR over CBDT is sensible, and not too-many hybrid color fonts have been built in the past. I did experiment with hybrid color fonts some 6-7 years ago, putting practically all formats into one file, but I never proceeded with it — because there was no native SVG support on Apple (just sbix), and without COLRv1, any reasonable expressive font would have to pack SVG+sbix (ideally in high res)+CBDT, but that made the fonts so huge that it surely wasn’t sensible.

But now, with sbix practically out of the picture, CBDT relegated to a somewhat temporary backwards polyfill a la kern table, we’re kind of entering the "max_color" time with at least two flavors (COLRv1 and SVG) being feasibly present in one SFNT resource. Obviously, the GF API is going to serve the right flavor only, but I’d like to see a less-hacky solution for the co-existence of the two outline flavors.

OK, in the immediate situation, some engines only do COLRv1 and some engines only do SVG. But what if someone (say Mozilla) implements both? What would be the criteria of choosing COLRv1 over SVG or the other way around, if a hybrid font is shown?

Keep in mind that it’s no easy answer. COLRv1 may be faster, and has variable capabilities, so some may think "OK, that's the better format, and SVG is just a polyfill". But on the other hand, SVG has the richer capabilities. It may combine vectors and bitmaps, so for example an SVG glyph might use a bitmap drop shadow or some intricate bitmap detail, which then the COLRv1 could simulate with simpler means.

There is a fair number of OpenType+SVG fonts already released (for example on Creative Market) which utilize SVG as a container for essentially bitmaps glyphs.

Something like Greg Nicholls’ Take Charge is actually something I hoped would emerge with color fonts, and in the end it did (I’ve used it on the BitFonter website, although as a pre-rendered image).

This type of font is a good candidate for an SVG+CBDT hybrid, but there may be others where the COLRv1 version is "80% of the intended design" and SVG is "100%" (because it adds some bitmap stuff vector content.

From the point of view of the spec and the renderers, it would be good if a font could somehow include some indicators on the preferred usage. We have the meta table which can differentiate between "design" and "supported" languages. This rightly realizes that in some fonts, some glyphs may be done really well, and some may be stubs or generics.

Perhaps the meta table would be the right place to specify the order of preference of implementations present in the font — it could give preference to COLR vs. SVG (or vice versa), and even to morx vs. GSUB.

twardoch commented 2 years ago

But maybe it’s dumb and overcomplicated to introduce this kind of selection mechanism. In the end, we get more and more towards dynamic asset serving via the web, and even for offline use, vendors can always provide single-flavor versions. :)

rsheeter commented 2 years ago

It's plausible to add a PaintBitmap to allow a bitmap to be pulled into a COLR graph (https://github.com/googlefonts/colr-gradients-spec/issues/272) but we don't really have any data to help drive the decision. I don't know how many actively used ot-svg fonts exist, and of those how many are completely bitmap, completely vector, or vector/bitmap hybrids.

Optimistic hat on, perhaps a vendor with access to a lot of ot-svg fonts (is Adobe the only one?) might be willing to let us poke through them to better understand how ot-svg is actually used.

yanone commented 2 years ago

I was going to continue onboarding Blaka Ink to Google Fonts, running maximum_color on it to add the tables as per @rsheeter’s suggestion in the email thread, only to find that the font already exists.

What’s more surprising tho is that I can't reproduce the SVG version in the same way as the one that Adam linked at the top. I used nanoemoji from both PyPi as well as Github directly. This is how my SVG version renders in Safari (and other macOS environments such as the Finder preview):

Bildschirmfoto 2022-05-05 um 16 16 03

Rod also said that running it through maximum_color is optional, I suppose because he can maximize the color fonts properly and I can continue onboarding the simple COLRv1 font, but I wanted to alert everyone here of the fact that the conversion isn't reliable. Happy to try out anything on my end to get it to work.

rsheeter commented 2 years ago

Thanks for the report, sounds like a bug in maximum_color. I filed a separate issue for that.

rsheeter commented 2 years ago

Rod also said that running it through maximum_color is optional

Maybe I should nuance that more. Try max color, if it fails or does something dumb file a bug and proceed. In time we'll want to take a harder line but for now that tool is barely past experimental so I don't want anyones workflow to be blocked when it fails.

rsheeter commented 2 years ago

In re-reading this I believe there is nothing to do for this issue in this repo, the work will be done on https://bugs.chromium.org/p/skia/issues/detail?id=12945. Closing, please reopen if you believe there is something to be done in nanoemoji wrt Chrome preference for CBDT over COLR.