Skip to content
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

Vectorial text for Canvas #1610

Merged
merged 5 commits into from
Jan 2, 2023
Merged

Conversation

hecrj
Copy link
Member

@hecrj hecrj commented Dec 20, 2022

This PR implements vectorial text support for the Canvas widget by leveraging cosmic-text 🎉

This means that text now is no different than any other kind of geometry in a Canvas and, as a result, it can be transformed (translated, rotated, and scaled) and composed (layering!) freely.

Also, cosmic-text implements both text shaping and font fallback, so a Canvas should now be able to support different scripts as well.

2022-12-20.11-05-30.mp4

The bitmap font support is wonky (and very inefficient), as you can see in the example above. This is just the start of a series of PRs that will improve our text handling and rendering. Further improvements are coming!

@hecrj hecrj force-pushed the feature/canvas-vectorial-text branch from 1326cdd to f150e2d Compare December 20, 2022 10:53
`fill_rectangle` can only be used with axis-aligned rectangles.
Comment on lines +306 to +312
let attrs = match text.font {
Font::Default => cosmic_text::Attrs::new(),
Font::External { name, .. } => cosmic_text::Attrs {
family: cosmic_text::Family::Name(name),
..cosmic_text::Attrs::new()
},
};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Has there been thoughts around how to align iced::Font w/ use of cosmic-text? Does cosmic-text support loading fonts from bytes? I'm sure this is already a known regression, but just want to point it out & start a conversation around it:

  • Font::Default / Attrs::new will use the default sans serif font registered w/ the cosmic_text::FontSystem... Fira Sans. If not found, uses a system found fallback.
  • Font::External / cosmic_text::Family::Name(..) won't use the included font bytes at all, but will see if there is a matching font family for the provided name on the users system, otherwise uses a system found fallback.

I don't see any way currently to load font bytes w/ cosmic-text or set a default font.

Copy link
Member Author

@hecrj hecrj Dec 21, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mentioned some ideas in the Discord, but basically we will change the way iced deals with fonts.

cosmic-text should be able to add support for loading fonts from bytes by leveraging Database::load_font_data.

Comment on lines +306 to +307
let attrs = match text.font {
Font::Default => cosmic_text::Attrs::new(),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Attrs allows us to specify style & weight, would be cool to see these added to Text so user can control those attributes as well. I'd imagine Text is going to need to change in order to support these and other changes, together w/ Font

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Eventually! Currently just focused on improving the text foundations. API should be accommodated later.

Comment on lines +403 to +408
// TODO: Raster image support for `Canvas`
let [r, g, b, a] = text.color.into_rgba8();

swash_cache.with_pixels(
glyph.cache_key,
cosmic_text::Color::rgba(r, g, b, a),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did some profiling and the bitmap pixels -> lyon tessellation is a huge performance killer. Even on release mode, I'm getting primitive generation times for size 80 text in the 8ms range. This drops to ~400μs when removing the emoji.

Maybe we add a disclaimer to the fill_text docs until there is better support for rastered images w/ transformations.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I ported the new example to master, but it's near impossible compare performance differences between the old / new fill_text since previously this was GPU rendered text and now it's tessellated by CPU. New changes are exposed in primitive generation numbers, but previously the impact would be hidden in render. Both maintain 60fps in release mode.

Obviously the canvas will most likely sit behind a canvas::Cache and in most workflows, the text is fairly static outside applying transformations.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, as I mentioned it's pretty inefficient!

The bitmap support is just a nice to have. For vectorial text, you'll want to deal with fonts that have outline information, so I don't think it's a big deal.

That said, we can probably skip the generic tessellation algorithm and hardcode the triangles ourselves.

Copy link
Member Author

@hecrj hecrj Dec 21, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, important to note that, once we remove glyph-brush, we will be able to compose primitives much more efficiently (a new draw call vs a new render pass). We may be able to use the GPU glyph atlas approach for text that isn't transformed for better readability and performance (with proper layering and caching!).

Lots of doors will open once we get that bottleneck out of the way.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense!

That said, we can probably skip the generic tessellation algorithm and hardcode the triangles ourselves.

That would be nice. Even though tessellating rectangles should be very cheap, I'd imagine there's still some overhead with lyon that we can get around building the mesh ourselves.

Copy link
Member Author

@hecrj hecrj Dec 21, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe it's as cheap as any other path of 4 points, since we are using the generic path algorithm and not fill_rectangle (which only works with axis-aligned rectangles).

@hecrj hecrj changed the base branch from master to advanced-text January 2, 2023 18:58
@hecrj hecrj merged commit d8102c5 into advanced-text Jan 2, 2023
@hecrj hecrj deleted the feature/canvas-vectorial-text branch January 2, 2023 18:58
@hecrj hecrj mentioned this pull request Jan 17, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants