-
-
Notifications
You must be signed in to change notification settings - Fork 55
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for SVG icons #102
Conversation
On second thought I think the helper struct to load SVGs is unnecessary, so I removed it. |
Thanks @BillyDM, this is really cool! I need to think about how we should expose this a bit, because people may want to bring their own SVG/vector crate but still be able to share the glyphon internals in some way. One option is to expose some way to send glow a custom glyph to be used at a specific position. This way we could accept any kind of image instead of tying it to resvg. What would you think about that option? I'd also like to make this design compatible with eventually being able to have inline boxes in cosmic-text (pop-os/cosmic-text#80), so custom icons could be added inline with text. |
Ah yeah, it would be much better if there was a way to inline the custom icons with regular text (and possibly render icons directly in As for the user being able to use any crate to render custom icons, perhaps we can just have the user pass in a closure that takes an icon ID and a size as input and raw pixel data as output? |
Actually, I just got an idea how to make this work. I'll go ahead and do that (and also rebase to the latest commits). |
Figured out how to properly rebase in VSCode this time :) |
Alright, I reworked the API. Now there is no |
Actually, thinking about it, if cosmic-text gets inline boxes, they would be part of the text buffer. So I simplified things a bit. Now you just pass in a vec of |
Thanks for working through the design a bit! I'd like to avoid putting any of the SVG-related logic in glyphon to keep it flexible. It seems like the API should allow the rasterized output + coordinates to be passed to glyphon instead of glyphon having optional dependencies. |
Alright, I removed the SVG-related logic. |
I realized I forgot to account for scale factor, so I added a quick fix for that. |
a5d86e9
to
19a86ac
Compare
Are you happy with this API, or do you want to workshop this some more? |
@BillyDM Thanks! I'll try to take another detailed look soon. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had some time to go through this in detail and it looks great so far. I had some ideas that might improve this a bit - please let me know if anything isn't clear.
It seems like it would be compatible with the ideas about inline boxes on the cosmic-text side, so that's really cool.
src/text_render.rs
Outdated
#[cfg(feature = "custom-glyphs")] | ||
let custom_glyph_font_id = cosmic_text::fontdb::ID::dummy(); | ||
#[cfg(feature = "custom-glyphs")] | ||
// This is a bit of a hacky way to reserve a slot for icons in the text |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure about relying on dummy()
and the CacheKeyFlags
representation. Maybe we could add an enum with something like enum CacheKey { Text(CacheKey), Custom(CustomGlyphCacheKey) }
? The overhead might be 1 byte or so per entry, but that seems ok based on typical cache sizes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, that seems cleaner and more flexible. I'll do that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I also realized while doing this that I'm not currently getting the rasterized custom glyph data in InnerAtlas::grow()
and this line will panic. https://github.com/grovesNL/glyphon/blob/main/src/text_atlas.rs#L160
I suppose I need to store the rasterized custom glyphs in a hash map.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or wait, actually it seems like you are using SwashCache.get_image_uncached()
.
Does that mean that all glyphs should be re-rasterized whenever the atlas grows?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just went ahead and did what glyphon does for text and re-rasterize the glyphs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok great. Yeah we don't want to keep two versions around in memory but also don't want to try to pull existing images back out of the atlas during grow, so this is probably about as good as we could do it right now.
src/text_render.rs
Outdated
/// The scaling factor applied to the text area. | ||
pub scale: f32, | ||
/// Binning of fractional X offset | ||
pub x_bin: cosmic_text::SubpixelBin, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could probably pass the original position down and let the rasterizer decide how they want to do binning. This way they could still apply cosmic-text's SubpixelBin
if they want, but I'd guess a lot of the time for images they'd skip the binning and just snap to the nearest left/top pixel anyway
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This won't work because you would need to have the position as part of the cache key, which would potentially lead to a whole lot of atlas entries being created.
I think the better solution is to add a flag to CustomGlyph
saying whether or not you want to snap the glyph to the nearest whole pixel.
src/text_render.rs
Outdated
#[cfg(feature = "custom-glyphs")] | ||
#[derive(Debug, Clone, Copy, PartialEq)] | ||
/// The input data to render a custom glyph | ||
pub struct CustomGlyphInput { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: CustomGlyphRasterizationRequest
or something
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about just RasterizationRequest
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, I'd just like to distinguish between rasterization requests for regular glyphs vs. custom glyphs somehow
Alright, I finished making improvements. |
Alright this seems ready now, thank you! |
What is the rationale for It seems a bit strange to introduce the ability to draw absolutely positioned bitmaps through a text rendering crate. I believe complexity would be greatly reduced if the library dropped this feature and instead exposed more parts of the |
@hecrj my thought was that we’ll eventually have support for inline boxes in cosmic-text which would pair really nicely with this (automatic positions instead of the absolute coordinates). I’d also be up for exposing the atlas and other pieces to do this externally, and/or provide helpers. Maybe there could be a nice hybrid that still allows for the inline boxes to be used with custom glyphs easily. If we had those parts exposed then we could probably change the API that we added for custom glyphs here. What would you think about something like that? |
@grovesNL I was just thinking that was problably the motivation. However, I think for inline boxes I'd expect I think this is the only reasonable approach for GUI toolkits like |
Yeah that makes sense too. I think I’d like to support both approaches – it seems common enough to want to insert a bitmap inline that it’s probably worthwhile to make it easier in glyphon instead of passing the position through. I’m not tied to any particular shape for the API though. |
Fair enough! It blurs the boundaries of the library a bit. Up until now it was all glyph rendering; and thanks to that choosing In any case, I'll think about a potential shared atlas API. We use a couple atlases for raster and vector images in |
I was really struggling to figure out how to create a custom icon font for my GUI library that actually worked with
cosmic-text
, so I just went ahead and implemented a feature to render SVG icons in glyphon as mentioned in #100.I've managed to reuse the same text atlas, pipeline, and shader that the text renderer uses. All that was added is an
IconRenderer
and anIconSystem
struct that behaves analogous to theTextRenderer
andFontSystem
structs.I've also added a helper struct to simplify loading and parsing SVG icons.