fontgoggles icon indicating copy to clipboard operation
fontgoggles copied to clipboard

Problem with certain COLRv1 glyphs in Noto-COLRv1.ttf

Open yarmola opened this issue 2 years ago • 11 comments

I am trying to paste a unicode string which contains character with codepoint above BMP (this one: 🎛). App does not like it (glyph flashes, then sample rendering disappears and text editing UI becomes unusable until app restart)

Screenshot 2022-09-21 at 13 57 06

I am experimenting with Noto Color Emoji font from here: https://github.com/googlefonts/noto-emoji

yarmola avatar Sep 21 '22 10:09 yarmola

I get the same with my totally different implementation of blackrenderer using cairo. Other glyphs are fine, but when I view this one and lots of others I get flashing or nothing.

Traceback (most recent call last): File "/Users/somebody/glyph_viewer.py", line 530, in OnPaint self.brFont.drawGlyph(self.currentGlyphName, cairoCanvas, File "/Users/somebody/somevenv/lib/python3.10/site-packages/blackrenderer/font.py", line 166, in drawGlyph self._drawGlyphCOLRv1(glyph, canvas) File "/Users/somebody/somevenv/lib/python3.10/site-packages/blackrenderer/font.py", line 191, in _drawGlyphCOLRv1 self._drawPaint(glyph.Paint, canvas) File "/Users/somebody/somevenv/lib/python3.10/site-packages/blackrenderer/font.py", line 211, in _drawPaint drawHandler(paint, canvas) File "/Users/somebody/somevenv/lib/python3.10/site-packages/blackrenderer/font.py", line 219, in _drawPaintColrLayers self._drawPaint(self.colrLayersV1.Paint[i], canvas) File "/Users/somebody/somevenv/lib/python3.10/site-packages/blackrenderer/font.py", line 211, in _drawPaint drawHandler(paint, canvas) File "/Users/somebody/somevenv/lib/python3.10/site-packages/blackrenderer/font.py", line 353, in _drawPaintComposite self._drawPaint(paint.BackdropPaint, canvas) File "/Users/somebody/somevenv/lib/python3.10/site-packages/blackrenderer/font.py", line 211, in _drawPaint drawHandler(paint, canvas) File "/Users/somebody/somevenv/lib/python3.10/site-packages/blackrenderer/font.py", line 223, in _drawPaintSolid canvas.drawPathSolid(self.currentPath, color) File "/Users/somebody/somevenv/lib/python3.10/site-packages/blackrenderer/backends/cairo.py", line 105, in drawPathSolid path.replay(self._pen) AttributeError: 'NoneType' object has no attribute 'replay'

punchcutter avatar Sep 21 '22 11:09 punchcutter

That may be the same error, I'll have a look.

justvanrossum avatar Sep 21 '22 11:09 justvanrossum

Definitely a bug in blackrenderer, though I get yet another error:

Traceback (most recent call last):
  File "/Users/just/code/git/BlackFoundry/black-renderer/venv/bin/blackrenderer", line 33, in <module>
    sys.exit(load_entry_point('blackrenderer', 'console_scripts', 'blackrenderer')())
  File "/Users/just/code/git/BlackFoundry/black-renderer/Lib/blackrenderer/__main__.py", line 43, in main
    renderText(
  File "/Users/just/code/git/BlackFoundry/black-renderer/Lib/blackrenderer/render.py", line 78, in renderText
    font.drawGlyph(glyph.name, canvas, palette=palette)
  File "/Users/just/code/git/BlackFoundry/black-renderer/Lib/blackrenderer/font.py", line 166, in drawGlyph
    self._drawGlyphCOLRv1(glyph, canvas)
  File "/Users/just/code/git/BlackFoundry/black-renderer/Lib/blackrenderer/font.py", line 191, in _drawGlyphCOLRv1
    self._drawPaint(glyph.Paint, canvas)
  File "/Users/just/code/git/BlackFoundry/black-renderer/Lib/blackrenderer/font.py", line 211, in _drawPaint
    drawHandler(paint, canvas)
  File "/Users/just/code/git/BlackFoundry/black-renderer/Lib/blackrenderer/font.py", line 219, in _drawPaintColrLayers
    self._drawPaint(self.colrLayersV1.Paint[i], canvas)
  File "/Users/just/code/git/BlackFoundry/black-renderer/Lib/blackrenderer/font.py", line 211, in _drawPaint
    drawHandler(paint, canvas)
  File "/Users/just/code/git/BlackFoundry/black-renderer/Lib/blackrenderer/font.py", line 353, in _drawPaintComposite
    self._drawPaint(paint.BackdropPaint, canvas)
  File "/Users/just/code/git/BlackFoundry/black-renderer/Lib/blackrenderer/font.py", line 211, in _drawPaint
    drawHandler(paint, canvas)
  File "/Users/just/code/git/BlackFoundry/black-renderer/Lib/blackrenderer/font.py", line 223, in _drawPaintSolid
    canvas.drawPathSolid(self.currentPath, color)
  File "/Users/just/code/git/BlackFoundry/black-renderer/Lib/blackrenderer/backends/skia.py", line 104, in drawPathSolid
    self.canvas.drawPath(path.path, paint)
AttributeError: 'NoneType' object has no attribute 'path'

justvanrossum avatar Sep 21 '22 12:09 justvanrossum

But FontGoggles should also not crash like that when it encounters a blackrenderer bug.

justvanrossum avatar Sep 21 '22 12:09 justvanrossum

Ah, but that's the same exact error, just a different backend. At the point drawPaintSolid is called the path is None in both cases. cairo tries to replay the path, skia tries to access path.path.

punchcutter avatar Sep 21 '22 12:09 punchcutter

I don't know what non-BMP has to do with it. 🎛 🎟 🎫 all fail for me, but everything else seems fine from what I can tell so far.

punchcutter avatar Sep 21 '22 12:09 punchcutter

Probably it is this particular glyph. It is built using the COLRv1 composition operator COMPOSITE_SRC_IN, but "backend" is empty. It does not look good (font-side) and I am investigating it (and will open issue in Noto Color Emoji if I find something), but I don't think renderer should crash.

yarmola avatar Sep 21 '22 13:09 yarmola

@yarmola, there'a already more discussion and analysis over at https://github.com/BlackFoundryCom/black-renderer/issues/116. The font is fine, but blackrenderer doesn't implement this case correctly.

justvanrossum avatar Sep 21 '22 14:09 justvanrossum

hey Yuri, the backround is not empy, it's simply unbounded, which is valid and spec'ed here: https://learn.microsoft.com/en-us/typography/opentype/spec/colr#metrics-and-boundedness-of-color-glyphs-using-version-1-formats

anthrotype avatar Sep 21 '22 14:09 anthrotype

Right, thanks!

Funny that in the sample above in the spec

They have unbounded gradient fill in "source" part of the composite operator while in the real font it is in the "backdrop" part (and it makes more sense).

I checked SVG origin of this glyph and it has "group" of objects with assigned transparency. Anyway, I think I should move to the black renderer repo with this, I believe the issue related to FontGoggles is clear :)

yarmola avatar Sep 21 '22 14:09 yarmola

They have unbounded gradient fill in "source" part of the composite operator while in the real font it is in the "backdrop" part (and it makes more sense).

good point, we should fix that actually. Mind filing an issue for this on the https://github.com/googlefonts/colr-gradients-spec repo?

anthrotype avatar Sep 21 '22 14:09 anthrotype

This should be fixed in FontGoggle 1.7.0: https://github.com/justvanrossum/fontgoggles/releases

justvanrossum avatar Nov 22 '22 10:11 justvanrossum

They have unbounded gradient fill in "source" part of the composite operator while in the real font it is in the "backdrop" part (and it makes more sense).

good point, we should fix that actually. Mind filing an issue for this on the https://github.com/googlefonts/colr-gradients-spec repo?

No, please open an issue on the COLR page of the OT spec. (For the figure in the spec, an SVG with feComposite was used to create the example, it in that SVG the rectangle with the alpha gradient is the destination (in2 attribute), not the source (in attribute).) If source and destination are reversed (as currently in the spec's figure), then the result would be the black alpha-gradient rectangle clipped to the circle.

PeterConstable avatar Nov 22 '22 20:11 PeterConstable

For COMPOSITE_SRC_IN, the PaintComposite is bounded if either the source or destination is bounded. That's implicit in the definition in the CSS spec. If some library is failing because the source graphic is unbounded even though the destination graphic is bounded, then that would seem to be either a bug in that library or a limitation of that library that implementations using it need to work around.

PeterConstable avatar Nov 22 '22 21:11 PeterConstable