Fixes #114. COLRv1 color glyphs are now rendered instead of rejected. As laid out in the issue and the upstream WIP colrv1 branch, FreeType parses the paint graph, and the paint operations are implemented with pixman (look ma, no harfbuzz!).
Full disclosure up front, most of this is LLM-written. I've read all the code and don't see anything too out there (it's mostly a canvas model like Skia or HarfBuzz, mapping FreeType stuff to pixman ops, mundane to the point of tedium), but I am very willing to refactor things (e.g. if you think the colrv1 stuff should move to a separate file like the OT-SVG renderer shim).
Compositing uses color_glyphs.format, blending in gamma space when color_glyphs.srgb_decode=false and linear light when color_glyphs.srgb_decode=true (read: honoring foot's gamma-correct-blending). All COLRv1 paint formats are handled: solid, linear/radial/sweep gradients across extend modes, colr-layers, glyph, colr-glyph, translate/transform/scale/rotate/skew, composite, and clip boxes. All but sweep/rotate/skew and colr-glyph are exercised by the COLRv1 version of Noto Color Emoji, and validated both visually and by diffing rendered glyphs against a bitmap version of Noto Color Emoji. Clankers love their tests, though, so nevertheless all these formats have also been tested through "a tiny, self-contained COLRv1 test font (test-fonts/, generated by gen-colr-test-font.py)", an approach insane enough that I have not included it in this PR (I can of course add it if you want). IME, the real test is printing some emoji in foot.
The one quirk I'm aware of is our (pixman's) gradient stops are interpolated straight where the CPAL spec wants premultiplied. These only differ when a gradient stop changes color and alpha together. I did at one point implement this more exact gradient rendering, in a hacky way, and could not notice a visual difference in any emoji in any font I tested. So it seems there are very few such gradients, and when they exist, they are between near-identical colors. Given this I don't think the pedantry is worth giving up pixman's gradient rendering and rolling our own, but that is theoretically something one could do.
Fixes #114. COLRv1 color glyphs are now rendered instead of rejected. As laid out in the issue and the upstream WIP colrv1 branch, FreeType parses the paint graph, and the paint operations are implemented with pixman (look ma, no harfbuzz!).
**Full disclosure up front, most of this is LLM-written.** I've read all the code and don't see anything too out there (it's mostly a canvas model like Skia or HarfBuzz, mapping FreeType stuff to pixman ops, mundane to the point of tedium), but I am very willing to refactor things (e.g. if you think the colrv1 stuff should move to a separate file like the OT-SVG renderer shim).
Compositing uses color_glyphs.format, blending in gamma space when color_glyphs.srgb_decode=false and linear light when color_glyphs.srgb_decode=true (read: honoring foot's gamma-correct-blending). All COLRv1 paint formats are handled: solid, linear/radial/sweep gradients across extend modes, colr-layers, glyph, colr-glyph, translate/transform/scale/rotate/skew, composite, and clip boxes. All but sweep/rotate/skew and colr-glyph are exercised by the COLRv1 version of Noto Color Emoji, and validated both visually and by diffing rendered glyphs against a bitmap version of Noto Color Emoji. Clankers love their tests, though, so nevertheless all these formats have *also* been tested through ["a tiny, self-contained COLRv1 test font (`test-fonts/`, generated by `gen-colr-test-font.py`)"](https://codeberg.org/twilligon/fcft/commit/f8cd18af232bb85e55d763e27ac320f06586b20d), an approach insane enough that I have not included it in this PR (I can of course add it if you want). IME, the real test is printing some emoji in foot.
The one quirk I'm aware of is our (pixman's) gradient stops are interpolated straight where the CPAL spec wants premultiplied. These only differ when a gradient stop changes color and alpha together. I did at one point implement this more exact gradient rendering, in a hacky way, and could not notice a visual difference in any emoji in any font I tested. So it seems there are very few such gradients, and when they exist, they are between near-identical colors. Given this I don't think the pedantry is worth giving up pixman's gradient rendering and rolling our own, but that is theoretically something one could do.