egui/crates/epaint/src/text/font.rs

487 lines
15 KiB
Rust
Raw Normal View History

use crate::{
2022-04-15 13:18:04 +00:00
mutex::{Mutex, RwLock},
TextureAtlas,
};
use emath::{vec2, Vec2};
use std::collections::BTreeSet;
2022-04-15 13:18:04 +00:00
use std::sync::Arc;
// ----------------------------------------------------------------------------
2022-12-05 08:29:59 +00:00
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
2019-01-05 20:23:53 +00:00
pub struct UvRect {
2019-01-19 16:10:28 +00:00
/// X/Y offset for nice rendering (unit: points).
pub offset: Vec2,
New text layout (#682) This PR introduces a completely rewritten text layout engine which is simpler and more powerful. It allows mixing different text styles (heading, body, etc) and formats (color, underlining, strikethrough, …) in the same layout pass, and baked into the same `Galley`. This opens up the door to having a syntax-highlighed code editor, or a WYSIWYG markdown editor. One major change is the color is now baked in at layout time. However, many widgets changes text color on hovered. But we need to do the text layout before we know if it is hovered. Therefor the painter has an option to override the text color of a galley. ## Performance Text layout alone is about 20% slower, but a lot of that is because more tessellation is done upfront. Text tessellation is now a lot faster, but text layout + tessellation still lands at a net loss of 5-10% in performance. There are however a few tricks to speed it up (like using `smallvec`) which I am saving for later. Text layout is also cached, meaning that in most cases (when all text isn't changing each frame) text tessellation is actually more important (and that's more than 2x faster!). Sadly, the actual text cache lookup is significantly slower (300ns -> 600ns). That's because the `TextLayoutJob` is a lot bigger (it has more options, like underlining, fonts etc), so it is slower to hash and compare. I have an idea how to speed this up, but I need to do some other work before I can implement that. All in all, the performance impact on `demo_with_tesselate__realistic` is about 5-6% in the red. Not great; not terrible. The benefits are worth it, but I also think with some work I can get that down significantly, hopefully down to the old levels.
2021-09-03 16:18:00 +00:00
/// Screen size (in points) of this glyph.
/// Note that the height is different from the font height.
2019-01-19 16:10:28 +00:00
pub size: Vec2,
2019-01-04 13:14:32 +00:00
2019-01-19 16:10:28 +00:00
/// Top left corner UV in texture.
New text layout (#682) This PR introduces a completely rewritten text layout engine which is simpler and more powerful. It allows mixing different text styles (heading, body, etc) and formats (color, underlining, strikethrough, …) in the same layout pass, and baked into the same `Galley`. This opens up the door to having a syntax-highlighed code editor, or a WYSIWYG markdown editor. One major change is the color is now baked in at layout time. However, many widgets changes text color on hovered. But we need to do the text layout before we know if it is hovered. Therefor the painter has an option to override the text color of a galley. ## Performance Text layout alone is about 20% slower, but a lot of that is because more tessellation is done upfront. Text tessellation is now a lot faster, but text layout + tessellation still lands at a net loss of 5-10% in performance. There are however a few tricks to speed it up (like using `smallvec`) which I am saving for later. Text layout is also cached, meaning that in most cases (when all text isn't changing each frame) text tessellation is actually more important (and that's more than 2x faster!). Sadly, the actual text cache lookup is significantly slower (300ns -> 600ns). That's because the `TextLayoutJob` is a lot bigger (it has more options, like underlining, fonts etc), so it is slower to hash and compare. I have an idea how to speed this up, but I need to do some other work before I can implement that. All in all, the performance impact on `demo_with_tesselate__realistic` is about 5-6% in the red. Not great; not terrible. The benefits are worth it, but I also think with some work I can get that down significantly, hopefully down to the old levels.
2021-09-03 16:18:00 +00:00
pub min: [u16; 2],
2019-01-04 13:14:32 +00:00
2019-01-19 16:10:28 +00:00
/// Bottom right corner (exclusive).
New text layout (#682) This PR introduces a completely rewritten text layout engine which is simpler and more powerful. It allows mixing different text styles (heading, body, etc) and formats (color, underlining, strikethrough, …) in the same layout pass, and baked into the same `Galley`. This opens up the door to having a syntax-highlighed code editor, or a WYSIWYG markdown editor. One major change is the color is now baked in at layout time. However, many widgets changes text color on hovered. But we need to do the text layout before we know if it is hovered. Therefor the painter has an option to override the text color of a galley. ## Performance Text layout alone is about 20% slower, but a lot of that is because more tessellation is done upfront. Text tessellation is now a lot faster, but text layout + tessellation still lands at a net loss of 5-10% in performance. There are however a few tricks to speed it up (like using `smallvec`) which I am saving for later. Text layout is also cached, meaning that in most cases (when all text isn't changing each frame) text tessellation is actually more important (and that's more than 2x faster!). Sadly, the actual text cache lookup is significantly slower (300ns -> 600ns). That's because the `TextLayoutJob` is a lot bigger (it has more options, like underlining, fonts etc), so it is slower to hash and compare. I have an idea how to speed this up, but I need to do some other work before I can implement that. All in all, the performance impact on `demo_with_tesselate__realistic` is about 5-6% in the red. Not great; not terrible. The benefits are worth it, but I also think with some work I can get that down significantly, hopefully down to the old levels.
2021-09-03 16:18:00 +00:00
pub max: [u16; 2],
}
impl UvRect {
pub fn is_nothing(&self) -> bool {
self.min == self.max
}
2019-01-04 13:14:32 +00:00
}
#[derive(Clone, Copy, Debug, PartialEq)]
2019-01-05 20:23:53 +00:00
pub struct GlyphInfo {
2023-02-08 09:01:47 +00:00
/// Used for pair-kerning.
///
/// Doesn't need to be unique.
/// Use `ab_glyph::GlyphId(0)` if you just want to have an id, and don't care.
New text layout (#682) This PR introduces a completely rewritten text layout engine which is simpler and more powerful. It allows mixing different text styles (heading, body, etc) and formats (color, underlining, strikethrough, …) in the same layout pass, and baked into the same `Galley`. This opens up the door to having a syntax-highlighed code editor, or a WYSIWYG markdown editor. One major change is the color is now baked in at layout time. However, many widgets changes text color on hovered. But we need to do the text layout before we know if it is hovered. Therefor the painter has an option to override the text color of a galley. ## Performance Text layout alone is about 20% slower, but a lot of that is because more tessellation is done upfront. Text tessellation is now a lot faster, but text layout + tessellation still lands at a net loss of 5-10% in performance. There are however a few tricks to speed it up (like using `smallvec`) which I am saving for later. Text layout is also cached, meaning that in most cases (when all text isn't changing each frame) text tessellation is actually more important (and that's more than 2x faster!). Sadly, the actual text cache lookup is significantly slower (300ns -> 600ns). That's because the `TextLayoutJob` is a lot bigger (it has more options, like underlining, fonts etc), so it is slower to hash and compare. I have an idea how to speed this up, but I need to do some other work before I can implement that. All in all, the performance impact on `demo_with_tesselate__realistic` is about 5-6% in the red. Not great; not terrible. The benefits are worth it, but I also think with some work I can get that down significantly, hopefully down to the old levels.
2021-09-03 16:18:00 +00:00
pub(crate) id: ab_glyph::GlyphId,
2019-01-05 20:23:53 +00:00
2019-01-19 16:10:28 +00:00
/// Unit: points.
2019-01-05 20:23:53 +00:00
pub advance_width: f32,
/// Texture coordinates.
New text layout (#682) This PR introduces a completely rewritten text layout engine which is simpler and more powerful. It allows mixing different text styles (heading, body, etc) and formats (color, underlining, strikethrough, …) in the same layout pass, and baked into the same `Galley`. This opens up the door to having a syntax-highlighed code editor, or a WYSIWYG markdown editor. One major change is the color is now baked in at layout time. However, many widgets changes text color on hovered. But we need to do the text layout before we know if it is hovered. Therefor the painter has an option to override the text color of a galley. ## Performance Text layout alone is about 20% slower, but a lot of that is because more tessellation is done upfront. Text tessellation is now a lot faster, but text layout + tessellation still lands at a net loss of 5-10% in performance. There are however a few tricks to speed it up (like using `smallvec`) which I am saving for later. Text layout is also cached, meaning that in most cases (when all text isn't changing each frame) text tessellation is actually more important (and that's more than 2x faster!). Sadly, the actual text cache lookup is significantly slower (300ns -> 600ns). That's because the `TextLayoutJob` is a lot bigger (it has more options, like underlining, fonts etc), so it is slower to hash and compare. I have an idea how to speed this up, but I need to do some other work before I can implement that. All in all, the performance impact on `demo_with_tesselate__realistic` is about 5-6% in the red. Not great; not terrible. The benefits are worth it, but I also think with some work I can get that down significantly, hopefully down to the old levels.
2021-09-03 16:18:00 +00:00
pub uv_rect: UvRect,
2019-01-05 20:23:53 +00:00
}
impl Default for GlyphInfo {
/// Basically a zero-width space.
fn default() -> Self {
Self {
id: ab_glyph::GlyphId(0),
advance_width: 0.0,
New text layout (#682) This PR introduces a completely rewritten text layout engine which is simpler and more powerful. It allows mixing different text styles (heading, body, etc) and formats (color, underlining, strikethrough, …) in the same layout pass, and baked into the same `Galley`. This opens up the door to having a syntax-highlighed code editor, or a WYSIWYG markdown editor. One major change is the color is now baked in at layout time. However, many widgets changes text color on hovered. But we need to do the text layout before we know if it is hovered. Therefor the painter has an option to override the text color of a galley. ## Performance Text layout alone is about 20% slower, but a lot of that is because more tessellation is done upfront. Text tessellation is now a lot faster, but text layout + tessellation still lands at a net loss of 5-10% in performance. There are however a few tricks to speed it up (like using `smallvec`) which I am saving for later. Text layout is also cached, meaning that in most cases (when all text isn't changing each frame) text tessellation is actually more important (and that's more than 2x faster!). Sadly, the actual text cache lookup is significantly slower (300ns -> 600ns). That's because the `TextLayoutJob` is a lot bigger (it has more options, like underlining, fonts etc), so it is slower to hash and compare. I have an idea how to speed this up, but I need to do some other work before I can implement that. All in all, the performance impact on `demo_with_tesselate__realistic` is about 5-6% in the red. Not great; not terrible. The benefits are worth it, but I also think with some work I can get that down significantly, hopefully down to the old levels.
2021-09-03 16:18:00 +00:00
uv_rect: Default::default(),
}
}
}
// ----------------------------------------------------------------------------
/// A specific font with a size.
2019-01-19 16:10:28 +00:00
/// The interface uses points as the unit for everything.
pub struct FontImpl {
name: String,
ab_glyph_font: ab_glyph::FontArc,
2019-01-04 13:14:32 +00:00
/// Maximum character height
scale_in_pixels: u32,
height_in_points: f32,
// move each character by this much (hack)
y_offset: f32,
2019-01-19 16:10:28 +00:00
pixels_per_point: f32,
Update dependencies (#1933) * Update ahash from 0.7 to 0.8 Opt to use ahash::HashMap over ahash::AHashMap * Fix ahash compilation for web * Update ron to 0.8 * Add note about why we cannot update tiny-skia * cargo update Updating crates.io index Updating android_system_properties v0.1.2 -> v0.1.4 Updating anyhow v1.0.58 -> v1.0.62 Updating async-broadcast v0.4.0 -> v0.4.1 Updating async-channel v1.6.1 -> v1.7.1 Updating async-io v1.7.0 -> v1.8.0 Updating async-task v4.2.0 -> v4.3.0 Updating async-trait v0.1.56 -> v0.1.57 Updating backtrace v0.3.65 -> v0.3.66 Updating bit-set v0.5.2 -> v0.5.3 Updating bumpalo v3.10.0 -> v3.11.0 Updating bytemuck v1.10.0 -> v1.12.1 Updating bytemuck_derive v1.1.0 -> v1.2.1 Updating bytes v1.1.0 -> v1.2.1 Updating cast v0.2.7 -> v0.3.0 Updating chrono v0.4.19 -> v0.4.22 Updating clap v3.2.8 -> v3.2.17 Updating clipboard-win v4.4.1 -> v4.4.2 Updating combine v4.6.4 -> v4.6.6 Updating concurrent-queue v1.2.2 -> v1.2.4 Updating criterion v0.3.5 -> v0.3.6 Updating criterion-plot v0.4.4 -> v0.4.5 Updating crossbeam-channel v0.5.5 -> v0.5.6 Updating crossbeam-deque v0.8.1 -> v0.8.2 Updating crossbeam-epoch v0.9.9 -> v0.9.10 Updating crossbeam-utils v0.8.10 -> v0.8.11 Updating document-features v0.2.1 -> v0.2.3 Updating dyn-clone v1.0.6 -> v1.0.9 Removing easy-parallel v3.2.0 Updating either v1.7.0 -> v1.8.0 Updating enum-map v2.1.0 -> v2.4.1 Updating enum-map-derive v0.8.0 -> v0.10.0 Updating event-listener v2.5.2 -> v2.5.3 Updating fastrand v1.7.0 -> v1.8.0 Updating futures-core v0.3.21 -> v0.3.23 Updating futures-io v0.3.21 -> v0.3.23 Updating futures-sink v0.3.21 -> v0.3.23 Updating futures-task v0.3.21 -> v0.3.23 Updating futures-util v0.3.21 -> v0.3.23 Updating gimli v0.26.1 -> v0.26.2 Updating gpu-descriptor v0.2.2 -> v0.2.3 Removing hashbrown v0.11.2 Removing hashbrown v0.12.1 Adding hashbrown v0.12.3 Adding iana-time-zone v0.1.46 Updating image v0.24.2 -> v0.24.3 Updating inplace_it v0.3.3 -> v0.3.4 Updating itoa v1.0.2 -> v1.0.3 Updating js-sys v0.3.58 -> v0.3.59 Updating libc v0.2.126 -> v0.2.132 Updating libm v0.2.2 -> v0.2.5 Removing memmap2 v0.3.1 Removing memmap2 v0.5.4 Adding memmap2 v0.5.7 Removing num-iter v0.1.43 Updating object v0.28.4 -> v0.29.0 Updating once_cell v1.13.0 -> v1.13.1 Updating os_str_bytes v6.1.0 -> v6.3.0 Updating owned_ttf_parser v0.15.0 -> v0.15.1 Removing parking_lot v0.11.2 Removing parking_lot_core v0.8.5 Updating plotters v0.3.1 -> v0.3.3 Updating plotters-backend v0.3.2 -> v0.3.4 Updating plotters-svg v0.3.1 -> v0.3.3 Updating proc-macro-crate v1.1.3 -> v1.2.1 Updating proc-macro2 v1.0.40 -> v1.0.43 Updating quote v1.0.20 -> v1.0.21 Updating redox_syscall v0.2.13 -> v0.2.16 Updating regex v1.5.6 -> v1.6.0 Updating regex-syntax v0.6.26 -> v0.6.27 Updating rfd v0.8.0 -> v0.8.4 Removing rustc_version v0.4.0 Updating ryu v1.0.10 -> v1.0.11 Updating sctk-adwaita v0.4.1 -> v0.4.2 Removing semver v1.0.12 Updating serde v1.0.138 -> v1.0.143 Updating serde_derive v1.0.138 -> v1.0.143 Updating serde_json v1.0.82 -> v1.0.83 Updating serde_repr v0.1.8 -> v0.1.9 Updating slab v0.4.6 -> v0.4.7 Removing smithay-client-toolkit v0.15.4 Updating smithay-clipboard v0.6.5 -> v0.6.6 Updating syn v1.0.98 -> v1.0.99 Updating thiserror v1.0.31 -> v1.0.32 Updating thiserror-impl v1.0.31 -> v1.0.32 Updating time v0.3.11 -> v0.3.13 Adding tiny-skia v0.7.0 Adding tiny-skia-path v0.7.0 Updating tracing v0.1.35 -> v0.1.36 Updating tracing-core v0.1.28 -> v0.1.29 Updating tracing-subscriber v0.3.14 -> v0.3.15 Updating unicode-ident v1.0.1 -> v1.0.3 Updating unicode_names2 v0.5.0 -> v0.5.1 Updating ureq v2.4.0 -> v2.5.0 Updating wasm-bindgen-futures v0.4.31 -> v0.4.32 Updating web-sys v0.3.58 -> v0.3.59 Updating webpki-roots v0.22.3 -> v0.22.4 Updating weezl v0.1.6 -> v0.1.7 Updating wgpu-core v0.13.1 -> v0.13.2 Updating wgpu-hal v0.13.1 -> v0.13.2 Updating wgpu-types v0.13.0 -> v0.13.2 Updating windows v0.32.0 -> v0.37.0 Updating windows_aarch64_msvc v0.32.0 -> v0.37.0 Updating windows_i686_gnu v0.32.0 -> v0.37.0 Updating windows_i686_msvc v0.32.0 -> v0.37.0 Updating windows_x86_64_gnu v0.32.0 -> v0.37.0 Updating windows_x86_64_msvc v0.32.0 -> v0.37.0 Updating x11-dl v2.19.1 -> v2.20.0 Updating zbus_names v2.1.0 -> v2.2.0 Updating zvariant v3.4.1 -> v3.6.0 Updating zvariant_derive v3.4.1 -> v3.6.0 * Add "Unicode-DFS-2016" to deny.toml whitelist
2022-08-19 09:46:38 +00:00
glyph_info_cache: RwLock<ahash::HashMap<char, GlyphInfo>>, // TODO(emilk): standard Mutex
2019-01-12 23:19:53 +00:00
atlas: Arc<Mutex<TextureAtlas>>,
2019-01-04 13:14:32 +00:00
}
impl FontImpl {
2019-01-19 16:10:28 +00:00
pub fn new(
atlas: Arc<Mutex<TextureAtlas>>,
pixels_per_point: f32,
name: String,
ab_glyph_font: ab_glyph::FontArc,
scale_in_pixels: u32,
y_offset_points: f32,
) -> FontImpl {
assert!(scale_in_pixels > 0);
2020-09-09 10:14:53 +00:00
assert!(pixels_per_point > 0.0);
let height_in_points = scale_in_pixels as f32 / pixels_per_point;
// TODO(emilk): use these font metrics?
// use ab_glyph::ScaleFont as _;
// let scaled = ab_glyph_font.as_scaled(scale_in_pixels as f32);
// dbg!(scaled.ascent());
// dbg!(scaled.descent());
// dbg!(scaled.line_gap());
// Round to closest pixel:
let y_offset = (y_offset_points * pixels_per_point).round() / pixels_per_point;
Self {
name,
ab_glyph_font,
2019-01-19 16:10:28 +00:00
scale_in_pixels,
height_in_points,
y_offset,
2019-01-19 16:10:28 +00:00
pixels_per_point,
glyph_info_cache: Default::default(),
2019-01-04 13:14:32 +00:00
atlas,
}
}
/// Code points that will always be replaced by the replacement character.
///
/// See also [`invisible_char`].
fn ignore_character(&self, chr: char) -> bool {
if self.name == "emoji-icon-font" {
// HACK: https://github.com/emilk/egui/issues/1284 https://github.com/jslegers/emoji-icon-font/issues/18
// Don't show the wrong fullwidth capital letters:
if '' <= chr && chr <= '' {
return true;
}
}
matches!(
chr,
// Strip out a religious symbol with secondary nefarious interpretation:
'\u{534d}' | '\u{5350}' |
// Ignore ubuntu-specific stuff in `Ubuntu-Light.ttf`:
'\u{E0FF}' | '\u{EFFD}' | '\u{F0FF}' | '\u{F200}'
)
}
/// An un-ordered iterator over all supported characters.
fn characters(&self) -> impl Iterator<Item = char> + '_ {
use ab_glyph::Font as _;
self.ab_glyph_font
.codepoint_ids()
.map(|(_, chr)| chr)
.filter(|&chr| !self.ignore_character(chr))
}
2020-12-11 22:46:02 +00:00
/// `\n` will result in `None`
fn glyph_info(&self, c: char) -> Option<GlyphInfo> {
{
if let Some(glyph_info) = self.glyph_info_cache.read().get(&c) {
2020-12-11 22:46:02 +00:00
return Some(*glyph_info);
}
}
if self.ignore_character(c) {
return None; // these will result in the replacement character when rendering
}
if c == '\t' {
if let Some(space) = self.glyph_info(' ') {
let glyph_info = GlyphInfo {
advance_width: crate::text::TAB_SIZE as f32 * space.advance_width,
..GlyphInfo::default()
};
self.glyph_info_cache.write().insert(c, glyph_info);
return Some(glyph_info);
}
}
if c == '\u{2009}' {
// Thin space, often used as thousands deliminator: 1234567890
// https://www.compart.com/en/unicode/U+2009
// https://en.wikipedia.org/wiki/Thin_space
if let Some(space) = self.glyph_info(' ') {
let em = self.height_in_points; // TODO(emilk): is this right?
let advance_width = f32::min(em / 6.0, space.advance_width * 0.5);
let glyph_info = GlyphInfo {
advance_width,
..GlyphInfo::default()
};
self.glyph_info_cache.write().insert(c, glyph_info);
return Some(glyph_info);
}
}
if invisible_char(c) {
let glyph_info = GlyphInfo::default();
self.glyph_info_cache.write().insert(c, glyph_info);
return Some(glyph_info);
}
// Add new character:
use ab_glyph::Font as _;
let glyph_id = self.ab_glyph_font.glyph_id(c);
if glyph_id.0 == 0 {
None // unsupported character
} else {
let glyph_info = allocate_glyph(
&mut self.atlas.lock(),
&self.ab_glyph_font,
glyph_id,
self.scale_in_pixels as f32,
self.y_offset,
self.pixels_per_point,
);
self.glyph_info_cache.write().insert(c, glyph_info);
Some(glyph_info)
}
2019-01-04 13:14:32 +00:00
}
New text layout (#682) This PR introduces a completely rewritten text layout engine which is simpler and more powerful. It allows mixing different text styles (heading, body, etc) and formats (color, underlining, strikethrough, …) in the same layout pass, and baked into the same `Galley`. This opens up the door to having a syntax-highlighed code editor, or a WYSIWYG markdown editor. One major change is the color is now baked in at layout time. However, many widgets changes text color on hovered. But we need to do the text layout before we know if it is hovered. Therefor the painter has an option to override the text color of a galley. ## Performance Text layout alone is about 20% slower, but a lot of that is because more tessellation is done upfront. Text tessellation is now a lot faster, but text layout + tessellation still lands at a net loss of 5-10% in performance. There are however a few tricks to speed it up (like using `smallvec`) which I am saving for later. Text layout is also cached, meaning that in most cases (when all text isn't changing each frame) text tessellation is actually more important (and that's more than 2x faster!). Sadly, the actual text cache lookup is significantly slower (300ns -> 600ns). That's because the `TextLayoutJob` is a lot bigger (it has more options, like underlining, fonts etc), so it is slower to hash and compare. I have an idea how to speed this up, but I need to do some other work before I can implement that. All in all, the performance impact on `demo_with_tesselate__realistic` is about 5-6% in the red. Not great; not terrible. The benefits are worth it, but I also think with some work I can get that down significantly, hopefully down to the old levels.
2021-09-03 16:18:00 +00:00
#[inline]
pub fn pair_kerning(
&self,
last_glyph_id: ab_glyph::GlyphId,
glyph_id: ab_glyph::GlyphId,
) -> f32 {
use ab_glyph::{Font as _, ScaleFont};
self.ab_glyph_font
.as_scaled(self.scale_in_pixels as f32)
.kern(last_glyph_id, glyph_id)
/ self.pixels_per_point
}
/// Height of one row of text. In points
#[inline(always)]
pub fn row_height(&self) -> f32 {
self.height_in_points
}
#[inline(always)]
pub fn pixels_per_point(&self) -> f32 {
self.pixels_per_point
}
}
type FontIndex = usize;
// TODO(emilk): rename?
/// Wrapper over multiple [`FontImpl`] (e.g. a primary + fallbacks for emojis)
pub struct Font {
fonts: Vec<Arc<FontImpl>>,
/// Lazily calculated.
2022-07-11 21:08:48 +00:00
characters: Option<BTreeSet<char>>,
replacement_glyph: (FontIndex, GlyphInfo),
pixels_per_point: f32,
row_height: f32,
Update dependencies (#1933) * Update ahash from 0.7 to 0.8 Opt to use ahash::HashMap over ahash::AHashMap * Fix ahash compilation for web * Update ron to 0.8 * Add note about why we cannot update tiny-skia * cargo update Updating crates.io index Updating android_system_properties v0.1.2 -> v0.1.4 Updating anyhow v1.0.58 -> v1.0.62 Updating async-broadcast v0.4.0 -> v0.4.1 Updating async-channel v1.6.1 -> v1.7.1 Updating async-io v1.7.0 -> v1.8.0 Updating async-task v4.2.0 -> v4.3.0 Updating async-trait v0.1.56 -> v0.1.57 Updating backtrace v0.3.65 -> v0.3.66 Updating bit-set v0.5.2 -> v0.5.3 Updating bumpalo v3.10.0 -> v3.11.0 Updating bytemuck v1.10.0 -> v1.12.1 Updating bytemuck_derive v1.1.0 -> v1.2.1 Updating bytes v1.1.0 -> v1.2.1 Updating cast v0.2.7 -> v0.3.0 Updating chrono v0.4.19 -> v0.4.22 Updating clap v3.2.8 -> v3.2.17 Updating clipboard-win v4.4.1 -> v4.4.2 Updating combine v4.6.4 -> v4.6.6 Updating concurrent-queue v1.2.2 -> v1.2.4 Updating criterion v0.3.5 -> v0.3.6 Updating criterion-plot v0.4.4 -> v0.4.5 Updating crossbeam-channel v0.5.5 -> v0.5.6 Updating crossbeam-deque v0.8.1 -> v0.8.2 Updating crossbeam-epoch v0.9.9 -> v0.9.10 Updating crossbeam-utils v0.8.10 -> v0.8.11 Updating document-features v0.2.1 -> v0.2.3 Updating dyn-clone v1.0.6 -> v1.0.9 Removing easy-parallel v3.2.0 Updating either v1.7.0 -> v1.8.0 Updating enum-map v2.1.0 -> v2.4.1 Updating enum-map-derive v0.8.0 -> v0.10.0 Updating event-listener v2.5.2 -> v2.5.3 Updating fastrand v1.7.0 -> v1.8.0 Updating futures-core v0.3.21 -> v0.3.23 Updating futures-io v0.3.21 -> v0.3.23 Updating futures-sink v0.3.21 -> v0.3.23 Updating futures-task v0.3.21 -> v0.3.23 Updating futures-util v0.3.21 -> v0.3.23 Updating gimli v0.26.1 -> v0.26.2 Updating gpu-descriptor v0.2.2 -> v0.2.3 Removing hashbrown v0.11.2 Removing hashbrown v0.12.1 Adding hashbrown v0.12.3 Adding iana-time-zone v0.1.46 Updating image v0.24.2 -> v0.24.3 Updating inplace_it v0.3.3 -> v0.3.4 Updating itoa v1.0.2 -> v1.0.3 Updating js-sys v0.3.58 -> v0.3.59 Updating libc v0.2.126 -> v0.2.132 Updating libm v0.2.2 -> v0.2.5 Removing memmap2 v0.3.1 Removing memmap2 v0.5.4 Adding memmap2 v0.5.7 Removing num-iter v0.1.43 Updating object v0.28.4 -> v0.29.0 Updating once_cell v1.13.0 -> v1.13.1 Updating os_str_bytes v6.1.0 -> v6.3.0 Updating owned_ttf_parser v0.15.0 -> v0.15.1 Removing parking_lot v0.11.2 Removing parking_lot_core v0.8.5 Updating plotters v0.3.1 -> v0.3.3 Updating plotters-backend v0.3.2 -> v0.3.4 Updating plotters-svg v0.3.1 -> v0.3.3 Updating proc-macro-crate v1.1.3 -> v1.2.1 Updating proc-macro2 v1.0.40 -> v1.0.43 Updating quote v1.0.20 -> v1.0.21 Updating redox_syscall v0.2.13 -> v0.2.16 Updating regex v1.5.6 -> v1.6.0 Updating regex-syntax v0.6.26 -> v0.6.27 Updating rfd v0.8.0 -> v0.8.4 Removing rustc_version v0.4.0 Updating ryu v1.0.10 -> v1.0.11 Updating sctk-adwaita v0.4.1 -> v0.4.2 Removing semver v1.0.12 Updating serde v1.0.138 -> v1.0.143 Updating serde_derive v1.0.138 -> v1.0.143 Updating serde_json v1.0.82 -> v1.0.83 Updating serde_repr v0.1.8 -> v0.1.9 Updating slab v0.4.6 -> v0.4.7 Removing smithay-client-toolkit v0.15.4 Updating smithay-clipboard v0.6.5 -> v0.6.6 Updating syn v1.0.98 -> v1.0.99 Updating thiserror v1.0.31 -> v1.0.32 Updating thiserror-impl v1.0.31 -> v1.0.32 Updating time v0.3.11 -> v0.3.13 Adding tiny-skia v0.7.0 Adding tiny-skia-path v0.7.0 Updating tracing v0.1.35 -> v0.1.36 Updating tracing-core v0.1.28 -> v0.1.29 Updating tracing-subscriber v0.3.14 -> v0.3.15 Updating unicode-ident v1.0.1 -> v1.0.3 Updating unicode_names2 v0.5.0 -> v0.5.1 Updating ureq v2.4.0 -> v2.5.0 Updating wasm-bindgen-futures v0.4.31 -> v0.4.32 Updating web-sys v0.3.58 -> v0.3.59 Updating webpki-roots v0.22.3 -> v0.22.4 Updating weezl v0.1.6 -> v0.1.7 Updating wgpu-core v0.13.1 -> v0.13.2 Updating wgpu-hal v0.13.1 -> v0.13.2 Updating wgpu-types v0.13.0 -> v0.13.2 Updating windows v0.32.0 -> v0.37.0 Updating windows_aarch64_msvc v0.32.0 -> v0.37.0 Updating windows_i686_gnu v0.32.0 -> v0.37.0 Updating windows_i686_msvc v0.32.0 -> v0.37.0 Updating windows_x86_64_gnu v0.32.0 -> v0.37.0 Updating windows_x86_64_msvc v0.32.0 -> v0.37.0 Updating x11-dl v2.19.1 -> v2.20.0 Updating zbus_names v2.1.0 -> v2.2.0 Updating zvariant v3.4.1 -> v3.6.0 Updating zvariant_derive v3.4.1 -> v3.6.0 * Add "Unicode-DFS-2016" to deny.toml whitelist
2022-08-19 09:46:38 +00:00
glyph_info_cache: ahash::HashMap<char, (FontIndex, GlyphInfo)>,
}
impl Font {
pub fn new(fonts: Vec<Arc<FontImpl>>) -> Self {
if fonts.is_empty() {
return Self {
fonts,
characters: None,
replacement_glyph: Default::default(),
pixels_per_point: 1.0,
row_height: 0.0,
glyph_info_cache: Default::default(),
};
}
let pixels_per_point = fonts[0].pixels_per_point();
let row_height = fonts[0].row_height();
let mut slf = Self {
fonts,
characters: None,
replacement_glyph: Default::default(),
pixels_per_point,
row_height,
glyph_info_cache: Default::default(),
};
const PRIMARY_REPLACEMENT_CHAR: char = '◻'; // white medium square
const FALLBACK_REPLACEMENT_CHAR: char = '?'; // fallback for the fallback
let replacement_glyph = slf
.glyph_info_no_cache_or_fallback(PRIMARY_REPLACEMENT_CHAR)
.or_else(|| slf.glyph_info_no_cache_or_fallback(FALLBACK_REPLACEMENT_CHAR))
.unwrap_or_else(|| {
panic!(
"Failed to find replacement characters {:?} or {:?}",
PRIMARY_REPLACEMENT_CHAR, FALLBACK_REPLACEMENT_CHAR
)
});
slf.replacement_glyph = replacement_glyph;
slf
}
pub fn preload_characters(&mut self, s: &str) {
for c in s.chars() {
self.glyph_info(c);
}
}
pub fn preload_common_characters(&mut self) {
// Preload the printable ASCII characters [32, 126] (which excludes control codes):
const FIRST_ASCII: usize = 32; // 32 == space
const LAST_ASCII: usize = 126;
for c in (FIRST_ASCII..=LAST_ASCII).map(|c| c as u8 as char) {
self.glyph_info(c);
}
self.glyph_info('°');
self.glyph_info(crate::text::PASSWORD_REPLACEMENT_CHAR);
}
/// All supported characters.
pub fn characters(&mut self) -> &BTreeSet<char> {
self.characters.get_or_insert_with(|| {
let mut characters = BTreeSet::new();
for font in &self.fonts {
characters.extend(font.characters());
}
characters
})
}
#[inline(always)]
pub fn round_to_pixel(&self, point: f32) -> f32 {
(point * self.pixels_per_point).round() / self.pixels_per_point
}
/// Height of one row of text. In points
#[inline(always)]
pub fn row_height(&self) -> f32 {
self.row_height
}
New text layout (#682) This PR introduces a completely rewritten text layout engine which is simpler and more powerful. It allows mixing different text styles (heading, body, etc) and formats (color, underlining, strikethrough, …) in the same layout pass, and baked into the same `Galley`. This opens up the door to having a syntax-highlighed code editor, or a WYSIWYG markdown editor. One major change is the color is now baked in at layout time. However, many widgets changes text color on hovered. But we need to do the text layout before we know if it is hovered. Therefor the painter has an option to override the text color of a galley. ## Performance Text layout alone is about 20% slower, but a lot of that is because more tessellation is done upfront. Text tessellation is now a lot faster, but text layout + tessellation still lands at a net loss of 5-10% in performance. There are however a few tricks to speed it up (like using `smallvec`) which I am saving for later. Text layout is also cached, meaning that in most cases (when all text isn't changing each frame) text tessellation is actually more important (and that's more than 2x faster!). Sadly, the actual text cache lookup is significantly slower (300ns -> 600ns). That's because the `TextLayoutJob` is a lot bigger (it has more options, like underlining, fonts etc), so it is slower to hash and compare. I have an idea how to speed this up, but I need to do some other work before I can implement that. All in all, the performance impact on `demo_with_tesselate__realistic` is about 5-6% in the red. Not great; not terrible. The benefits are worth it, but I also think with some work I can get that down significantly, hopefully down to the old levels.
2021-09-03 16:18:00 +00:00
pub fn uv_rect(&self, c: char) -> UvRect {
self.glyph_info_cache
.get(&c)
New text layout (#682) This PR introduces a completely rewritten text layout engine which is simpler and more powerful. It allows mixing different text styles (heading, body, etc) and formats (color, underlining, strikethrough, …) in the same layout pass, and baked into the same `Galley`. This opens up the door to having a syntax-highlighed code editor, or a WYSIWYG markdown editor. One major change is the color is now baked in at layout time. However, many widgets changes text color on hovered. But we need to do the text layout before we know if it is hovered. Therefor the painter has an option to override the text color of a galley. ## Performance Text layout alone is about 20% slower, but a lot of that is because more tessellation is done upfront. Text tessellation is now a lot faster, but text layout + tessellation still lands at a net loss of 5-10% in performance. There are however a few tricks to speed it up (like using `smallvec`) which I am saving for later. Text layout is also cached, meaning that in most cases (when all text isn't changing each frame) text tessellation is actually more important (and that's more than 2x faster!). Sadly, the actual text cache lookup is significantly slower (300ns -> 600ns). That's because the `TextLayoutJob` is a lot bigger (it has more options, like underlining, fonts etc), so it is slower to hash and compare. I have an idea how to speed this up, but I need to do some other work before I can implement that. All in all, the performance impact on `demo_with_tesselate__realistic` is about 5-6% in the red. Not great; not terrible. The benefits are worth it, but I also think with some work I can get that down significantly, hopefully down to the old levels.
2021-09-03 16:18:00 +00:00
.map(|gi| gi.1.uv_rect)
.unwrap_or_default()
}
/// Width of this character in points.
pub fn glyph_width(&mut self, c: char) -> f32 {
self.glyph_info(c).1.advance_width
}
/// Can we display this glyph?
pub fn has_glyph(&mut self, c: char) -> bool {
self.glyph_info(c) != self.replacement_glyph // TODO(emilk): this is a false negative if the user asks about the replacement character itself 🤦‍♂️
}
/// Can we display all the glyphs in this text?
pub fn has_glyphs(&mut self, s: &str) -> bool {
s.chars().all(|c| self.has_glyph(c))
}
/// `\n` will (intentionally) show up as the replacement character.
fn glyph_info(&mut self, c: char) -> (FontIndex, GlyphInfo) {
if let Some(font_index_glyph_info) = self.glyph_info_cache.get(&c) {
return *font_index_glyph_info;
}
let font_index_glyph_info = self.glyph_info_no_cache_or_fallback(c);
let font_index_glyph_info = font_index_glyph_info.unwrap_or(self.replacement_glyph);
self.glyph_info_cache.insert(c, font_index_glyph_info);
font_index_glyph_info
}
New text layout (#682) This PR introduces a completely rewritten text layout engine which is simpler and more powerful. It allows mixing different text styles (heading, body, etc) and formats (color, underlining, strikethrough, …) in the same layout pass, and baked into the same `Galley`. This opens up the door to having a syntax-highlighed code editor, or a WYSIWYG markdown editor. One major change is the color is now baked in at layout time. However, many widgets changes text color on hovered. But we need to do the text layout before we know if it is hovered. Therefor the painter has an option to override the text color of a galley. ## Performance Text layout alone is about 20% slower, but a lot of that is because more tessellation is done upfront. Text tessellation is now a lot faster, but text layout + tessellation still lands at a net loss of 5-10% in performance. There are however a few tricks to speed it up (like using `smallvec`) which I am saving for later. Text layout is also cached, meaning that in most cases (when all text isn't changing each frame) text tessellation is actually more important (and that's more than 2x faster!). Sadly, the actual text cache lookup is significantly slower (300ns -> 600ns). That's because the `TextLayoutJob` is a lot bigger (it has more options, like underlining, fonts etc), so it is slower to hash and compare. I have an idea how to speed this up, but I need to do some other work before I can implement that. All in all, the performance impact on `demo_with_tesselate__realistic` is about 5-6% in the red. Not great; not terrible. The benefits are worth it, but I also think with some work I can get that down significantly, hopefully down to the old levels.
2021-09-03 16:18:00 +00:00
#[inline]
pub(crate) fn glyph_info_and_font_impl(&mut self, c: char) -> (Option<&FontImpl>, GlyphInfo) {
if self.fonts.is_empty() {
return (None, self.replacement_glyph.1);
}
New text layout (#682) This PR introduces a completely rewritten text layout engine which is simpler and more powerful. It allows mixing different text styles (heading, body, etc) and formats (color, underlining, strikethrough, …) in the same layout pass, and baked into the same `Galley`. This opens up the door to having a syntax-highlighed code editor, or a WYSIWYG markdown editor. One major change is the color is now baked in at layout time. However, many widgets changes text color on hovered. But we need to do the text layout before we know if it is hovered. Therefor the painter has an option to override the text color of a galley. ## Performance Text layout alone is about 20% slower, but a lot of that is because more tessellation is done upfront. Text tessellation is now a lot faster, but text layout + tessellation still lands at a net loss of 5-10% in performance. There are however a few tricks to speed it up (like using `smallvec`) which I am saving for later. Text layout is also cached, meaning that in most cases (when all text isn't changing each frame) text tessellation is actually more important (and that's more than 2x faster!). Sadly, the actual text cache lookup is significantly slower (300ns -> 600ns). That's because the `TextLayoutJob` is a lot bigger (it has more options, like underlining, fonts etc), so it is slower to hash and compare. I have an idea how to speed this up, but I need to do some other work before I can implement that. All in all, the performance impact on `demo_with_tesselate__realistic` is about 5-6% in the red. Not great; not terrible. The benefits are worth it, but I also think with some work I can get that down significantly, hopefully down to the old levels.
2021-09-03 16:18:00 +00:00
let (font_index, glyph_info) = self.glyph_info(c);
let font_impl = &self.fonts[font_index];
(Some(font_impl), glyph_info)
New text layout (#682) This PR introduces a completely rewritten text layout engine which is simpler and more powerful. It allows mixing different text styles (heading, body, etc) and formats (color, underlining, strikethrough, …) in the same layout pass, and baked into the same `Galley`. This opens up the door to having a syntax-highlighed code editor, or a WYSIWYG markdown editor. One major change is the color is now baked in at layout time. However, many widgets changes text color on hovered. But we need to do the text layout before we know if it is hovered. Therefor the painter has an option to override the text color of a galley. ## Performance Text layout alone is about 20% slower, but a lot of that is because more tessellation is done upfront. Text tessellation is now a lot faster, but text layout + tessellation still lands at a net loss of 5-10% in performance. There are however a few tricks to speed it up (like using `smallvec`) which I am saving for later. Text layout is also cached, meaning that in most cases (when all text isn't changing each frame) text tessellation is actually more important (and that's more than 2x faster!). Sadly, the actual text cache lookup is significantly slower (300ns -> 600ns). That's because the `TextLayoutJob` is a lot bigger (it has more options, like underlining, fonts etc), so it is slower to hash and compare. I have an idea how to speed this up, but I need to do some other work before I can implement that. All in all, the performance impact on `demo_with_tesselate__realistic` is about 5-6% in the red. Not great; not terrible. The benefits are worth it, but I also think with some work I can get that down significantly, hopefully down to the old levels.
2021-09-03 16:18:00 +00:00
}
fn glyph_info_no_cache_or_fallback(&mut self, c: char) -> Option<(FontIndex, GlyphInfo)> {
for (font_index, font_impl) in self.fonts.iter().enumerate() {
if let Some(glyph_info) = font_impl.glyph_info(c) {
self.glyph_info_cache.insert(c, (font_index, glyph_info));
return Some((font_index, glyph_info));
}
}
None
}
}
/// Code points that will always be invisible (zero width).
///
/// See also [`FontImpl::ignore_character`].
#[inline]
fn invisible_char(c: char) -> bool {
if c == '\r' {
// A character most vile and pernicious. Don't display it.
return true;
}
// See https://github.com/emilk/egui/issues/336
// From https://www.fileformat.info/info/unicode/category/Cf/list.htm
// TODO(emilk): heed bidi characters
matches!(
c,
'\u{200B}' // ZERO WIDTH SPACE
| '\u{200C}' // ZERO WIDTH NON-JOINER
| '\u{200D}' // ZERO WIDTH JOINER
| '\u{200E}' // LEFT-TO-RIGHT MARK
| '\u{200F}' // RIGHT-TO-LEFT MARK
| '\u{202A}' // LEFT-TO-RIGHT EMBEDDING
| '\u{202B}' // RIGHT-TO-LEFT EMBEDDING
| '\u{202C}' // POP DIRECTIONAL FORMATTING
| '\u{202D}' // LEFT-TO-RIGHT OVERRIDE
| '\u{202E}' // RIGHT-TO-LEFT OVERRIDE
| '\u{2060}' // WORD JOINER
| '\u{2061}' // FUNCTION APPLICATION
| '\u{2062}' // INVISIBLE TIMES
| '\u{2063}' // INVISIBLE SEPARATOR
| '\u{2064}' // INVISIBLE PLUS
| '\u{2066}' // LEFT-TO-RIGHT ISOLATE
| '\u{2067}' // RIGHT-TO-LEFT ISOLATE
| '\u{2068}' // FIRST STRONG ISOLATE
| '\u{2069}' // POP DIRECTIONAL ISOLATE
| '\u{206A}' // INHIBIT SYMMETRIC SWAPPING
| '\u{206B}' // ACTIVATE SYMMETRIC SWAPPING
| '\u{206C}' // INHIBIT ARABIC FORM SHAPING
| '\u{206D}' // ACTIVATE ARABIC FORM SHAPING
| '\u{206E}' // NATIONAL DIGIT SHAPES
| '\u{206F}' // NOMINAL DIGIT SHAPES
| '\u{FEFF}' // ZERO WIDTH NO-BREAK SPACE
)
}
fn allocate_glyph(
atlas: &mut TextureAtlas,
font: &ab_glyph::FontArc,
glyph_id: ab_glyph::GlyphId,
scale_in_pixels: f32,
y_offset: f32,
pixels_per_point: f32,
) -> GlyphInfo {
assert!(glyph_id.0 != 0);
use ab_glyph::{Font as _, ScaleFont};
let glyph =
glyph_id.with_scale_and_position(scale_in_pixels, ab_glyph::Point { x: 0.0, y: 0.0 });
New text layout (#682) This PR introduces a completely rewritten text layout engine which is simpler and more powerful. It allows mixing different text styles (heading, body, etc) and formats (color, underlining, strikethrough, …) in the same layout pass, and baked into the same `Galley`. This opens up the door to having a syntax-highlighed code editor, or a WYSIWYG markdown editor. One major change is the color is now baked in at layout time. However, many widgets changes text color on hovered. But we need to do the text layout before we know if it is hovered. Therefor the painter has an option to override the text color of a galley. ## Performance Text layout alone is about 20% slower, but a lot of that is because more tessellation is done upfront. Text tessellation is now a lot faster, but text layout + tessellation still lands at a net loss of 5-10% in performance. There are however a few tricks to speed it up (like using `smallvec`) which I am saving for later. Text layout is also cached, meaning that in most cases (when all text isn't changing each frame) text tessellation is actually more important (and that's more than 2x faster!). Sadly, the actual text cache lookup is significantly slower (300ns -> 600ns). That's because the `TextLayoutJob` is a lot bigger (it has more options, like underlining, fonts etc), so it is slower to hash and compare. I have an idea how to speed this up, but I need to do some other work before I can implement that. All in all, the performance impact on `demo_with_tesselate__realistic` is about 5-6% in the red. Not great; not terrible. The benefits are worth it, but I also think with some work I can get that down significantly, hopefully down to the old levels.
2021-09-03 16:18:00 +00:00
let uv_rect = font.outline_glyph(glyph).map(|glyph| {
let bb = glyph.px_bounds();
let glyph_width = bb.width() as usize;
let glyph_height = bb.height() as usize;
if glyph_width == 0 || glyph_height == 0 {
New text layout (#682) This PR introduces a completely rewritten text layout engine which is simpler and more powerful. It allows mixing different text styles (heading, body, etc) and formats (color, underlining, strikethrough, …) in the same layout pass, and baked into the same `Galley`. This opens up the door to having a syntax-highlighed code editor, or a WYSIWYG markdown editor. One major change is the color is now baked in at layout time. However, many widgets changes text color on hovered. But we need to do the text layout before we know if it is hovered. Therefor the painter has an option to override the text color of a galley. ## Performance Text layout alone is about 20% slower, but a lot of that is because more tessellation is done upfront. Text tessellation is now a lot faster, but text layout + tessellation still lands at a net loss of 5-10% in performance. There are however a few tricks to speed it up (like using `smallvec`) which I am saving for later. Text layout is also cached, meaning that in most cases (when all text isn't changing each frame) text tessellation is actually more important (and that's more than 2x faster!). Sadly, the actual text cache lookup is significantly slower (300ns -> 600ns). That's because the `TextLayoutJob` is a lot bigger (it has more options, like underlining, fonts etc), so it is slower to hash and compare. I have an idea how to speed this up, but I need to do some other work before I can implement that. All in all, the performance impact on `demo_with_tesselate__realistic` is about 5-6% in the red. Not great; not terrible. The benefits are worth it, but I also think with some work I can get that down significantly, hopefully down to the old levels.
2021-09-03 16:18:00 +00:00
UvRect::default()
} else {
2022-01-22 10:23:12 +00:00
let (glyph_pos, image) = atlas.allocate((glyph_width, glyph_height));
glyph.draw(|x, y, v| {
if v > 0.0 {
let px = glyph_pos.0 + x as usize;
let py = glyph_pos.1 + y as usize;
image[(px, py)] = v;
}
});
2022-07-11 21:08:48 +00:00
let offset_in_pixels = vec2(bb.min.x, scale_in_pixels + bb.min.y);
let offset = offset_in_pixels / pixels_per_point + y_offset * Vec2::Y;
New text layout (#682) This PR introduces a completely rewritten text layout engine which is simpler and more powerful. It allows mixing different text styles (heading, body, etc) and formats (color, underlining, strikethrough, …) in the same layout pass, and baked into the same `Galley`. This opens up the door to having a syntax-highlighed code editor, or a WYSIWYG markdown editor. One major change is the color is now baked in at layout time. However, many widgets changes text color on hovered. But we need to do the text layout before we know if it is hovered. Therefor the painter has an option to override the text color of a galley. ## Performance Text layout alone is about 20% slower, but a lot of that is because more tessellation is done upfront. Text tessellation is now a lot faster, but text layout + tessellation still lands at a net loss of 5-10% in performance. There are however a few tricks to speed it up (like using `smallvec`) which I am saving for later. Text layout is also cached, meaning that in most cases (when all text isn't changing each frame) text tessellation is actually more important (and that's more than 2x faster!). Sadly, the actual text cache lookup is significantly slower (300ns -> 600ns). That's because the `TextLayoutJob` is a lot bigger (it has more options, like underlining, fonts etc), so it is slower to hash and compare. I have an idea how to speed this up, but I need to do some other work before I can implement that. All in all, the performance impact on `demo_with_tesselate__realistic` is about 5-6% in the red. Not great; not terrible. The benefits are worth it, but I also think with some work I can get that down significantly, hopefully down to the old levels.
2021-09-03 16:18:00 +00:00
UvRect {
offset,
size: vec2(glyph_width as f32, glyph_height as f32) / pixels_per_point,
New text layout (#682) This PR introduces a completely rewritten text layout engine which is simpler and more powerful. It allows mixing different text styles (heading, body, etc) and formats (color, underlining, strikethrough, …) in the same layout pass, and baked into the same `Galley`. This opens up the door to having a syntax-highlighed code editor, or a WYSIWYG markdown editor. One major change is the color is now baked in at layout time. However, many widgets changes text color on hovered. But we need to do the text layout before we know if it is hovered. Therefor the painter has an option to override the text color of a galley. ## Performance Text layout alone is about 20% slower, but a lot of that is because more tessellation is done upfront. Text tessellation is now a lot faster, but text layout + tessellation still lands at a net loss of 5-10% in performance. There are however a few tricks to speed it up (like using `smallvec`) which I am saving for later. Text layout is also cached, meaning that in most cases (when all text isn't changing each frame) text tessellation is actually more important (and that's more than 2x faster!). Sadly, the actual text cache lookup is significantly slower (300ns -> 600ns). That's because the `TextLayoutJob` is a lot bigger (it has more options, like underlining, fonts etc), so it is slower to hash and compare. I have an idea how to speed this up, but I need to do some other work before I can implement that. All in all, the performance impact on `demo_with_tesselate__realistic` is about 5-6% in the red. Not great; not terrible. The benefits are worth it, but I also think with some work I can get that down significantly, hopefully down to the old levels.
2021-09-03 16:18:00 +00:00
min: [glyph_pos.0 as u16, glyph_pos.1 as u16],
max: [
(glyph_pos.0 + glyph_width) as u16,
(glyph_pos.1 + glyph_height) as u16,
New text layout (#682) This PR introduces a completely rewritten text layout engine which is simpler and more powerful. It allows mixing different text styles (heading, body, etc) and formats (color, underlining, strikethrough, …) in the same layout pass, and baked into the same `Galley`. This opens up the door to having a syntax-highlighed code editor, or a WYSIWYG markdown editor. One major change is the color is now baked in at layout time. However, many widgets changes text color on hovered. But we need to do the text layout before we know if it is hovered. Therefor the painter has an option to override the text color of a galley. ## Performance Text layout alone is about 20% slower, but a lot of that is because more tessellation is done upfront. Text tessellation is now a lot faster, but text layout + tessellation still lands at a net loss of 5-10% in performance. There are however a few tricks to speed it up (like using `smallvec`) which I am saving for later. Text layout is also cached, meaning that in most cases (when all text isn't changing each frame) text tessellation is actually more important (and that's more than 2x faster!). Sadly, the actual text cache lookup is significantly slower (300ns -> 600ns). That's because the `TextLayoutJob` is a lot bigger (it has more options, like underlining, fonts etc), so it is slower to hash and compare. I have an idea how to speed this up, but I need to do some other work before I can implement that. All in all, the performance impact on `demo_with_tesselate__realistic` is about 5-6% in the red. Not great; not terrible. The benefits are worth it, but I also think with some work I can get that down significantly, hopefully down to the old levels.
2021-09-03 16:18:00 +00:00
],
}
}
});
New text layout (#682) This PR introduces a completely rewritten text layout engine which is simpler and more powerful. It allows mixing different text styles (heading, body, etc) and formats (color, underlining, strikethrough, …) in the same layout pass, and baked into the same `Galley`. This opens up the door to having a syntax-highlighed code editor, or a WYSIWYG markdown editor. One major change is the color is now baked in at layout time. However, many widgets changes text color on hovered. But we need to do the text layout before we know if it is hovered. Therefor the painter has an option to override the text color of a galley. ## Performance Text layout alone is about 20% slower, but a lot of that is because more tessellation is done upfront. Text tessellation is now a lot faster, but text layout + tessellation still lands at a net loss of 5-10% in performance. There are however a few tricks to speed it up (like using `smallvec`) which I am saving for later. Text layout is also cached, meaning that in most cases (when all text isn't changing each frame) text tessellation is actually more important (and that's more than 2x faster!). Sadly, the actual text cache lookup is significantly slower (300ns -> 600ns). That's because the `TextLayoutJob` is a lot bigger (it has more options, like underlining, fonts etc), so it is slower to hash and compare. I have an idea how to speed this up, but I need to do some other work before I can implement that. All in all, the performance impact on `demo_with_tesselate__realistic` is about 5-6% in the red. Not great; not terrible. The benefits are worth it, but I also think with some work I can get that down significantly, hopefully down to the old levels.
2021-09-03 16:18:00 +00:00
let uv_rect = uv_rect.unwrap_or_default();
let advance_width_in_points =
font.as_scaled(scale_in_pixels).h_advance(glyph_id) / pixels_per_point;
GlyphInfo {
id: glyph_id,
advance_width: advance_width_in_points,
uv_rect,
}
}