Created attachment 134165 [details] [review] [PATCH] Hacky hack: Use color glyph alpha as mask Context: After upgrading to cairo 1.15.8, i3 suddenly cleared its surfaces before drawing color glyphs, because it uses the SOURCE operator for text drawing: https://github.com/i3/i3/pull/2908 My patch to use OVER instead was reverted as another user uses a fork with alpha source to "punch holes": https://github.com/i3/i3/pull/2925 Looking for an alternative solution, the attached (very hacky) patch alters cairo's handling of color glyphs: - When loading a color glyph, separate the alpha channel and save it as the non-color surface. - Use the non-color surface as the mask when compositing color glyphs. - Plug a leak of patterns in composite_one_color_glyph => Drawing glyphs with CAIRO_OPERATOR_SOURCE no longer clears dest. In general the handling of color glyphs should match the handling of normal glyphs now, except for the source color. => Possible extension: Let the user deactivate color glyph handling (in the context? in the pattern?) in order to draw with the chosen source instead, for things like text shadows. Since the normal surface is the alpha mask now, this handles color glyphs nicely. To do that, just have it override the check of _cairo_scaled_font_has_color_glyphs to be false. My ignorance of cairo and pixman internals means this is probably terrible code.
Fixed: https://cgit.freedesktop.org/cairo/commit/?id=99427c3f4f6ce7ce3c95c4caa4d2b8ff7c0093d9
I think using alpha as the mask but leaving it in the source would do weird things to the destination alpha, as it becomes src * src + dst * (1 - src), i.e. you have a quadratic curve.
(In reply to Jan Alexander Steffens (heftig) from comment #2) > I think using alpha as the mask but leaving it in the source would do weird > things to the destination alpha, as it becomes src * src + dst * (1 - src), > i.e. you have a quadratic curve. Yeah I agree we are double-multiplying...
Reopening to discuss double-multiplying. I'm willing to let it go though. Note that the proposed hacky hack patch that separate alpha and rgb suffers from the same problem IMO.
Does it? My patch turns the color surface into RGB24 format, so the alpha is dropped.
(In reply to Jan Alexander Steffens (heftig) from comment #5) > Does it? My patch turns the color surface into RGB24 format, so the alpha is > dropped. Yes, but RGB that get in there are premultiplied...
Ah, I missed that detail. And the colors coming out of FreeType are already premultiplied. Well, there goes the easy solution. I now agree this is probably not worth worrying about.
(In reply to Jan Alexander Steffens (heftig) from comment #7) > Ah, I missed that detail. And the colors coming out of FreeType are already > premultiplied. Well, there goes the easy solution. Exactly. The PNG is NOT premultiplied, but we premultiply in FreeType before returning... > I now agree this is probably not worth worrying about.
Ahh. I wish I knew about premultiplication and objected as much as I could. Now we are about to release layered fonts with the premultiplication... Screw everyone who cares about gamma correction too! At least Direct2D offers a choice https://docs.microsoft.com/en-us/windows/desktop/api/dcommon/ne-dcommon-d2d1_alpha_mode
Cairo was designed to act like the letters were the *mask*. No pixels outside the letters should be changed no matter what the compositing operation is or what character is drawn. Users expect that by default (which means the compositing op is OVER) the emoji are filled in with their colors. It is also useful to be able to fill the shapes of the emoji with solid colors, for effects such as drop shadows. This cannot be done in one step right now. My recommendation: * If the op is OVER, then it does what it is doing now. * If the op is not OVER, then the color of the emoji is ignored. Instead the alpha of each of them is merged into the mask with the rest of the glyphs, and then font rendering continues as normal. In particular this allows SOURCE to be used to fill with a solid color or image. A different recommendation. This is more consistent, but much harder to implement, and may be less useful. To draw an emoji produce exactly the same result as if you did this: * Intersect the mask with the alpha of the emoji * Set the source to an opaque *unpremultiplied* version of the emoji's color * Fill a rectangle that is bigger than the mask. This produces the same result for OVER as it does now. SOURCE also produces the same result.
-- GitLab Migration Automatic Message -- This bug has been migrated to freedesktop.org's GitLab instance and has been closed from further activity. You can subscribe and participate further through the new bug through this link to our GitLab instance: https://gitlab.freedesktop.org/cairo/cairo/issues/296.
Use of freedesktop.org services, including Bugzilla, is subject to our Code of Conduct. How we collect and use information is described in our Privacy Policy.