googlefonts / fontations

Reading and writing font files
Apache License 2.0
394 stars 24 forks source link

[skrifa] CBDT/CBLC and SBIX bitmap color font access interfaces #593

Open drott opened 1 year ago

drott commented 1 year ago

For bitmap color font support in the Fontations SkTypeface backend, interfaces in Skrifa or read-fonts are needed to access the bitmap strikes of CBDT/CBLC and SBIX fonts. (In principle EBDT/EBLC might be needed but in practice I don't think we encounter such fonts so much, except for some Windows Chinese system fonts which are not high priority).

I have not analyzed FreeType's support or interfaces or what SkTypeface does with them yet, but I suspect we might want some control over retrieving what strike sizes are available and selecting them. And/or and automatic mode might be useful where the next higher strike size or the highest available strike size is selected according to configured scaled font size.

.2 cents considerations regarding priority, I wonder if this make sense to do even before hinting and autohinting support. It depends on how much work this is. If it's a smaller amount of work, this might unblock me from starting the work on the Skia side so that work could start in parallel while hinting and autohinting is being worked on.

drott commented 9 months ago

As a basis for discussion and invitation for feedback, here's my current thinking on how to hook up bitmap glyphs.

Alternative 1: New type of ColorGlyphCollection

Option a)

Instantiate SBIX for example, add format for SBIX to ColorGlyphFormat, then support calling paint() on it. Problem: paint() operates in font units, so it's ambiguous which strike size should be chosen. This could be solved by adding a getter to ColorPainter, for example bitmap_output_ppem_size() or strike_size() or similar. This would make the ColorPainter aware of what output strike size is expected. It could then find the nearest bigger or the max strike size bitmap, send a push_transform() with a scale to bridge between font unit space and 1:1 bitmap output space, and combine that neutralizing transform with a small scale transform if needed to go from the strike size found in the font to the requested output strike size.

Add methods to ColorPainter for paint_png... and paint_jpg... or paint_a8_bitmap_buf... or some such.

Other advantages:

Disadvantage:

Option b)

Provide a different paint_bitmap(scaled_to_size : f32) method with a preferred output size argument scaled_to_size that. (Fail when the color vector method paint()is called.) This method paint_bitmap() would then not work in font units but in pixel size, as requested. This paint_bitmap method could still accept the same ColorPainter object, but would then not operate in font units but in pixel space.

Option c)

Like above, i.e. represent bitmap fonts as a ColorGlyphCollection (even EBDT/EBLC monochromatic ones 🫣) and don't support paint(), i.e. return a PaintError for these, and only add simpler accessor methods to just retrieve a bitmap with a strike size, don't drive any callback-based painting.

Requires more work on the client / Skia side. Leaves glyph placement relative to em box outside the library and makes that the client's responsibility.

Alternative 2: No API in Skrifa

Leave all of it to FFI code in Skia, just based on read-fonts.

drott commented 9 months ago

My assumption at the moment is that we won't need to support all the monochromatic encodings in Chromium and mostly go with CBDT/CBLX PNG image data and sbix PNG image data. I might restrict the implementation to that and thus not feel like I want to invest in designing a full general purpose (monochromatic and color) bitmap API in Skrifa. So currently I am working based on the Alternative 2.