1
0
mirror of https://github.com/emilk/egui.git synced 2026-06-26 22:53:14 -04:00

Remove more Arc<Mutex<...>> from font code

By making `Font` a view type and indexing by font ID, we can avoid
wrapping `FontImpl` and `TextureAtlas` in an `Arc<Mutex<...>>`.
This commit is contained in:
valadaptive
2025-07-04 00:03:57 -04:00
parent 02d45d70bc
commit 837fc7fef7
5 changed files with 208 additions and 156 deletions

View File

@@ -1588,7 +1588,7 @@ impl Context {
let font_id = TextStyle::Body.resolve(&self.style());
self.fonts_mut(|f| {
let font = f.fonts.font(&font_id.family);
let mut font = f.fonts.font(&font_id.family);
font.has_glyphs(alt)
&& font.has_glyphs(ctrl)
&& font.has_glyphs(shift)
@@ -2466,14 +2466,15 @@ impl ContextImpl {
self.memory.end_pass(&viewport.this_pass.used_ids);
if let Some(fonts) = self.fonts.get(&pixels_per_point.into()) {
let num_font_envs = self.fonts.len();
if let Some(fonts) = self.fonts.get_mut(&pixels_per_point.into()) {
let tex_mngr = &mut self.tex_manager.0.write();
if let Some(font_image_delta) = fonts.font_image_delta() {
// A partial font atlas update, e.g. a new glyph has been entered.
tex_mngr.set(TextureId::default(), font_image_delta);
}
if 1 < self.fonts.len() {
if 1 < num_font_envs {
// We have multiple different `pixels_per_point`,
// e.g. because we have many viewports spread across
// monitors with different DPI scaling.
@@ -2693,10 +2694,6 @@ impl Context {
.1
.texture_atlas()
};
let (font_tex_size, prepared_discs) = {
let atlas = texture_atlas.lock();
(atlas.size(), atlas.prepared_discs())
};
let paint_stats = PaintStats::from_shapes(&shapes);
let clipped_primitives = {
@@ -2704,8 +2701,8 @@ impl Context {
tessellator::Tessellator::new(
pixels_per_point,
tessellation_options,
font_tex_size,
prepared_discs,
texture_atlas.size(),
texture_atlas.prepared_discs(),
)
.tessellate_shapes(shapes)
};

View File

@@ -227,7 +227,7 @@ pub fn criterion_benchmark(c: &mut Criterion) {
let galley = fonts.layout(LOREM_IPSUM_LONG.to_owned(), font_id, text_color, wrap_width);
let font_image_size = fonts.font_image_size();
let prepared_discs = fonts.texture_atlas().lock().prepared_discs();
let prepared_discs = fonts.texture_atlas().prepared_discs();
let mut tessellator = egui::epaint::Tessellator::new(
1.0,
Default::default(),

View File

@@ -1,13 +1,14 @@
use std::collections::BTreeMap;
use std::sync::Arc;
use ab_glyph::{Font as _, PxScaleFont, ScaleFont as _};
use emath::{GuiRounding as _, OrderedFloat, Vec2, vec2};
use crate::{
TextureAtlas,
mutex::{Mutex, RwLock},
text::FontTweak,
text::{
FontTweak,
fonts::{CachedFamily, FontFaceKey},
},
};
// ----------------------------------------------------------------------------
@@ -84,9 +85,8 @@ pub struct FontImpl {
name: String,
ab_glyph_font: ab_glyph::FontArc,
tweak: FontTweak,
glyph_info_cache: RwLock<ahash::HashMap<char, GlyphInfo>>, // TODO(emilk): standard Mutex
glyph_alloc_cache: RwLock<ahash::HashMap<(GlyphInfo, OrderedFloat<f32>), GlyphAllocation>>, // TODO(emilk): standard Mutex
atlas: Arc<Mutex<TextureAtlas>>,
glyph_info_cache: ahash::HashMap<char, GlyphInfo>,
glyph_alloc_cache: ahash::HashMap<(GlyphInfo, OrderedFloat<f32>), GlyphAllocation>,
}
trait FontExt {
@@ -116,19 +116,13 @@ where
}
impl FontImpl {
pub fn new(
atlas: Arc<Mutex<TextureAtlas>>,
name: String,
ab_glyph_font: ab_glyph::FontArc,
tweak: FontTweak,
) -> Self {
pub fn new(name: String, ab_glyph_font: ab_glyph::FontArc, tweak: FontTweak) -> Self {
Self {
name,
ab_glyph_font,
tweak,
glyph_info_cache: Default::default(),
glyph_alloc_cache: Default::default(),
atlas,
}
}
@@ -161,9 +155,9 @@ impl FontImpl {
}
/// `\n` will result in `None`
fn glyph_info(&self, c: char) -> Option<GlyphInfo> {
fn glyph_info(&mut self, c: char) -> Option<GlyphInfo> {
{
if let Some(glyph_info) = self.glyph_info_cache.read().get(&c) {
if let Some(glyph_info) = self.glyph_info_cache.get(&c) {
return Some(*glyph_info);
}
}
@@ -180,7 +174,7 @@ impl FontImpl {
.into(),
..space
};
self.glyph_info_cache.write().insert(c, glyph_info);
self.glyph_info_cache.insert(c, glyph_info);
return Some(glyph_info);
}
}
@@ -197,14 +191,14 @@ impl FontImpl {
advance_width_unscaled: advance_width.into(),
..space
};
self.glyph_info_cache.write().insert(c, glyph_info);
self.glyph_info_cache.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);
self.glyph_info_cache.insert(c, glyph_info);
return Some(glyph_info);
}
@@ -219,7 +213,7 @@ impl FontImpl {
advance_width_unscaled: self.ab_glyph_font.h_advance_unscaled(glyph_id).into(),
visible: true,
};
self.glyph_info_cache.write().insert(c, glyph_info);
self.glyph_info_cache.insert(c, glyph_info);
Some(glyph_info)
}
}
@@ -259,8 +253,9 @@ impl FontImpl {
}
pub fn allocate_glyph(
&self,
&mut self,
glyph_info: GlyphInfo,
atlas: &mut TextureAtlas,
font_size: f32,
pixels_per_point: f32,
) -> GlyphAllocation {
@@ -273,8 +268,7 @@ impl FontImpl {
.ab_glyph_font
.pt_scale_factor(font_size * self.tweak.scale * pixels_per_point)
.round();
let mut cache = self.glyph_alloc_cache.write();
let entry = match cache.entry((glyph_info, scale.into())) {
let entry = match self.glyph_alloc_cache.entry((glyph_info, scale.into())) {
std::collections::hash_map::Entry::Occupied(glyph_alloc) => {
return *glyph_alloc.get();
}
@@ -312,7 +306,6 @@ impl FontImpl {
UvRect::default()
} else {
let glyph_pos = {
let atlas = &mut self.atlas.lock();
let text_alpha_from_coverage = atlas.text_alpha_from_coverage;
let (glyph_pos, image) = atlas.allocate((glyph_width, glyph_height));
glyph.draw(|x, y, v| {
@@ -352,56 +345,15 @@ impl FontImpl {
}
}
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.
characters: Option<BTreeMap<char, Vec<String>>>,
replacement_glyph: (FontIndex, GlyphInfo),
glyph_info_cache: ahash::HashMap<char, (FontIndex, GlyphInfo)>,
pub struct Font<'a> {
pub(super) fonts_by_id: &'a mut nohash_hasher::IntMap<FontFaceKey, FontImpl>,
pub(super) cached_family: &'a mut CachedFamily,
pub(super) atlas: &'a mut TextureAtlas,
}
impl Font {
pub fn new(fonts: Vec<Arc<FontImpl>>) -> Self {
if fonts.is_empty() {
return Self {
fonts,
characters: None,
replacement_glyph: Default::default(),
glyph_info_cache: Default::default(),
};
}
let mut slf = Self {
fonts,
characters: None,
replacement_glyph: Default::default(),
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(|| {
#[cfg(feature = "log")]
log::warn!(
"Failed to find replacement characters {PRIMARY_REPLACEMENT_CHAR:?} or {FALLBACK_REPLACEMENT_CHAR:?}. Will use empty glyph."
);
(0, GlyphInfo::default())
});
slf.replacement_glyph = replacement_glyph;
slf
}
impl Font<'_> {
pub fn preload_characters(&mut self, s: &str) {
for c in s.chars() {
self.glyph_info(c);
@@ -421,9 +373,10 @@ impl Font {
/// All supported characters, and in which font they are available in.
pub fn characters(&mut self) -> &BTreeMap<char, Vec<String>> {
self.characters.get_or_insert_with(|| {
self.cached_family.characters.get_or_insert_with(|| {
let mut characters: BTreeMap<char, Vec<String>> = Default::default();
for font in &self.fonts {
for font_id in &self.cached_family.fonts {
let font = self.fonts_by_id.get(font_id).expect("Nonexistent font ID");
for chr in font.characters() {
characters.entry(chr).or_default().push(font.name.clone());
}
@@ -437,20 +390,27 @@ impl Font {
/// Returns a value rounded to [`emath::GUI_ROUNDING`].
#[inline(always)]
pub fn row_height(&self, font_size: f32) -> f32 {
self.fonts[0].row_height(font_size)
let Some(first_font) = self.fonts_by_id.get(&self.cached_family.fonts[0]) else {
return 0.0;
};
first_font.row_height(font_size)
}
/// Width of this character in points.
pub fn glyph_width(&mut self, c: char, font_size: f32) -> f32 {
let (font_index, glyph_info) = self.glyph_info(c);
let font = &self.fonts[font_index].ab_glyph_font;
let (key, glyph_info) = self.glyph_info(c);
let font = &self
.fonts_by_id
.get(&key)
.expect("Nonexistent font ID")
.ab_glyph_font;
glyph_info.advance_width_unscaled.0 * font.pt_scale_factor(font_size)
/ font.height_unscaled()
}
/// 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 🤦‍♂️
self.glyph_info(c) != self.cached_family.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?
@@ -459,24 +419,30 @@ impl Font {
}
/// `\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) {
fn glyph_info(&mut self, c: char) -> (FontFaceKey, GlyphInfo) {
if let Some(font_index_glyph_info) = self.cached_family.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);
let font_index_glyph_info =
font_index_glyph_info.unwrap_or(self.cached_family.replacement_glyph);
self.cached_family
.glyph_info_cache
.insert(c, font_index_glyph_info);
font_index_glyph_info
}
#[inline]
pub(crate) fn font_impl_and_glyph_info(&mut self, c: char) -> (Option<&FontImpl>, GlyphInfo) {
if self.fonts.is_empty() {
return (None, self.replacement_glyph.1);
pub(crate) fn font_impl_and_glyph_info(
&mut self,
c: char,
) -> (Option<&mut FontImpl>, GlyphInfo) {
if self.cached_family.fonts.is_empty() {
return (None, self.cached_family.replacement_glyph.1);
}
let (font_index, glyph_info) = self.glyph_info(c);
let font_impl = &self.fonts[font_index];
let (key, glyph_info) = self.glyph_info(c);
let font_impl = self.fonts_by_id.get_mut(&key).expect("Nonexistent font ID");
(Some(font_impl), glyph_info)
}
@@ -487,28 +453,39 @@ impl Font {
font_size: f32,
pixels_per_point: f32,
) -> (Option<&FontImpl>, GlyphAllocation) {
if self.fonts.is_empty() {
if self.cached_family.fonts.is_empty() {
return (None, Default::default());
}
let (font_index, glyph_info) = self.glyph_info(c);
let font_impl = &self.fonts[font_index];
let allocated_glyph = font_impl.allocate_glyph(glyph_info, font_size, pixels_per_point);
let (key, glyph_info) = self.glyph_info(c);
let font_impl = self.fonts_by_id.get_mut(&key).expect("Nonexistent font ID");
let allocated_glyph =
font_impl.allocate_glyph(glyph_info, self.atlas, font_size, pixels_per_point);
(Some(font_impl), allocated_glyph)
}
pub(crate) fn ascent(&self, font_size: f32) -> f32 {
if let Some(first) = self.fonts.first() {
if let Some(first) = self.cached_family.fonts.first() {
let first = self.fonts_by_id.get(first).expect("Nonexistent font ID");
first.ascent(font_size)
} else {
self.row_height(font_size)
}
}
fn glyph_info_no_cache_or_fallback(&mut self, c: char) -> Option<(FontIndex, GlyphInfo)> {
for (font_index, font_impl) in self.fonts.iter().enumerate() {
pub(crate) fn glyph_info_no_cache_or_fallback(
&mut self,
c: char,
) -> Option<(FontFaceKey, GlyphInfo)> {
for font_key in &self.cached_family.fonts {
let font_impl = self
.fonts_by_id
.get_mut(font_key)
.expect("Nonexistent font ID");
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));
self.cached_family
.glyph_info_cache
.insert(c, (*font_key, glyph_info));
return Some((*font_key, glyph_info));
}
}
None

View File

@@ -1,11 +1,16 @@
use std::{collections::BTreeMap, sync::Arc};
use std::{
collections::BTreeMap,
sync::{
Arc,
atomic::{AtomicU64, Ordering},
},
};
use crate::{
AlphaFromCoverage, TextureAtlas,
mutex::Mutex,
text::{
Galley, LayoutJob, LayoutSection,
font::{Font, FontImpl},
font::{Font, FontImpl, GlyphInfo},
},
};
use emath::NumExt as _;
@@ -399,6 +404,79 @@ impl FontDefinitions {
}
}
/// Unique ID for looking up a single font face/file.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Default)]
pub(crate) struct FontFaceKey(pub u64);
static KEY_COUNTER: AtomicU64 = AtomicU64::new(1);
impl FontFaceKey {
fn new() -> Self {
Self(KEY_COUNTER.fetch_add(1, Ordering::Relaxed))
}
}
impl nohash_hasher::IsEnabled for FontFaceKey {}
/// Cached data for working with a font family (e.g. doing character lookups).
#[derive(Debug)]
pub(super) struct CachedFamily {
pub fonts: Vec<FontFaceKey>,
/// Lazily calculated.
pub characters: Option<BTreeMap<char, Vec<String>>>,
pub replacement_glyph: (FontFaceKey, GlyphInfo),
pub glyph_info_cache: ahash::HashMap<char, (FontFaceKey, GlyphInfo)>,
}
impl CachedFamily {
fn new(
fonts: Vec<FontFaceKey>,
fonts_by_id: &mut nohash_hasher::IntMap<FontFaceKey, FontImpl>,
atlas: &mut TextureAtlas,
) -> Self {
if fonts.is_empty() {
return Self {
fonts,
characters: None,
replacement_glyph: Default::default(),
glyph_info_cache: Default::default(),
};
}
let mut slf = Self {
fonts,
characters: None,
replacement_glyph: Default::default(),
glyph_info_cache: Default::default(),
};
const PRIMARY_REPLACEMENT_CHAR: char = '◻'; // white medium square
const FALLBACK_REPLACEMENT_CHAR: char = '?'; // fallback for the fallback
let mut font = Font {
fonts_by_id,
cached_family: &mut slf,
atlas,
};
let replacement_glyph = font
.glyph_info_no_cache_or_fallback(PRIMARY_REPLACEMENT_CHAR)
.or_else(|| font.glyph_info_no_cache_or_fallback(FALLBACK_REPLACEMENT_CHAR))
.unwrap_or_else(|| {
#[cfg(feature = "log")]
log::warn!(
"Failed to find replacement characters {PRIMARY_REPLACEMENT_CHAR:?} or {FALLBACK_REPLACEMENT_CHAR:?}. Will use empty glyph."
);
(FontFaceKey::default(), GlyphInfo::default())
});
slf.replacement_glyph = replacement_glyph;
slf
}
}
// ----------------------------------------------------------------------------
/// The collection of fonts used by `epaint`.
@@ -454,8 +532,8 @@ impl Fonts {
let pixels_per_point_changed = self.fonts.pixels_per_point != pixels_per_point;
let max_texture_side_changed = self.fonts.max_texture_side != max_texture_side;
let text_alpha_from_coverage_changed =
self.fonts.atlas.lock().text_alpha_from_coverage != text_alpha_from_coverage;
let font_atlas_almost_full = self.fonts.atlas.lock().fill_ratio() > 0.8;
self.fonts.atlas.text_alpha_from_coverage != text_alpha_from_coverage;
let font_atlas_almost_full = self.fonts.atlas.fill_ratio() > 0.8;
let needs_recreate = pixels_per_point_changed
|| max_texture_side_changed
|| text_alpha_from_coverage_changed
@@ -479,8 +557,8 @@ impl Fonts {
}
/// Call at the end of each frame (before painting) to get the change to the font texture since last call.
pub fn font_image_delta(&self) -> Option<crate::ImageDelta> {
self.fonts.atlas.lock().take_delta()
pub fn font_image_delta(&mut self) -> Option<crate::ImageDelta> {
self.fonts.atlas.take_delta()
}
#[inline]
@@ -495,20 +573,20 @@ impl Fonts {
/// The font atlas.
/// Pass this to [`crate::Tessellator`].
pub fn texture_atlas(&self) -> Arc<Mutex<TextureAtlas>> {
self.fonts.atlas.clone()
pub fn texture_atlas(&self) -> &TextureAtlas {
&self.fonts.atlas
}
/// The full font atlas image.
#[inline]
pub fn image(&self) -> crate::ColorImage {
self.fonts.atlas.lock().image().clone()
self.fonts.atlas.image().clone()
}
/// Current size of the font image.
/// Pass this to [`crate::Tessellator`].
pub fn font_image_size(&self) -> [usize; 2] {
self.fonts.atlas.lock().size()
self.fonts.atlas.size()
}
/// Width of this character in points.
@@ -564,7 +642,7 @@ impl Fonts {
/// This increases as new fonts and/or glyphs are used,
/// but can also decrease in a call to [`Self::begin_pass`].
pub fn font_atlas_fill_ratio(&self) -> f32 {
self.fonts.atlas.lock().fill_ratio()
self.fonts.atlas.fill_ratio()
}
/// Will wrap text at the given width and line break at `\n`.
@@ -618,10 +696,10 @@ pub struct FontsImpl {
pixels_per_point: f32,
max_texture_side: usize,
definitions: FontDefinitions,
atlas: Arc<Mutex<TextureAtlas>>,
//font_impl_cache: FontImplCache,
font_impls: ahash::HashMap<String, Arc<FontImpl>>,
family_cache: ahash::HashMap<FontFamily, Font>,
atlas: TextureAtlas,
fonts_by_id: nohash_hasher::IntMap<FontFaceKey, FontImpl>,
font_impls: ahash::HashMap<String, FontFaceKey>,
family_cache: ahash::HashMap<FontFamily, CachedFamily>,
}
impl FontsImpl {
@@ -642,24 +720,23 @@ impl FontsImpl {
let initial_height = 32; // Keep initial font atlas small, so it is fast to upload to GPU. This will expand as needed anyways.
let atlas = TextureAtlas::new([texture_width, initial_height], text_alpha_from_coverage);
let atlas = Arc::new(Mutex::new(atlas));
let font_impls = definitions
.font_data
.iter()
.map(|(name, font_data)| {
let tweak = font_data.tweak;
let ab_glyph = ab_glyph_font_from_font_data(name, font_data);
let font_impl = FontImpl::new(atlas.clone(), name.clone(), ab_glyph, tweak);
(name.clone(), Arc::new(font_impl))
})
.collect();
let mut fonts_by_id: nohash_hasher::IntMap<FontFaceKey, FontImpl> = Default::default();
let mut font_impls: ahash::HashMap<String, FontFaceKey> = Default::default();
for (name, font_data) in &definitions.font_data {
let tweak = font_data.tweak;
let ab_glyph = ab_glyph_font_from_font_data(name, font_data);
let font_impl = FontImpl::new(name.clone(), ab_glyph, tweak);
let key = FontFaceKey::new();
fonts_by_id.insert(key, font_impl);
font_impls.insert(name.clone(), key);
}
Self {
pixels_per_point,
max_texture_side,
definitions,
atlas,
fonts_by_id,
font_impls,
family_cache: Default::default(),
}
@@ -676,24 +753,29 @@ impl FontsImpl {
}
/// Get the right font implementation from [`FontFamily`].
pub fn font(&mut self, family: &FontFamily) -> &mut Font {
self.family_cache.entry(family.clone()).or_insert_with(|| {
pub fn font(&mut self, family: &FontFamily) -> Font<'_> {
let cached_family = self.family_cache.entry(family.clone()).or_insert_with(|| {
let fonts = &self.definitions.families.get(family);
let fonts =
fonts.unwrap_or_else(|| panic!("FontFamily::{family:?} is not bound to any fonts"));
let fonts: Vec<Arc<FontImpl>> = fonts
let fonts: Vec<FontFaceKey> = fonts
.iter()
.map(|font_name| {
self.font_impls
*self
.font_impls
.get(font_name)
.unwrap_or_else(|| panic!("No font data found for {font_name:?}"))
.clone()
})
.collect();
Font::new(fonts)
})
CachedFamily::new(fonts, &mut self.fonts_by_id, &mut self.atlas)
});
Font {
fonts_by_id: &mut self.fonts_by_id,
cached_family,
atlas: &mut self.atlas,
}
}
/// Width of this character in points.

View File

@@ -144,7 +144,7 @@ fn layout_section(
format,
} = section;
let pixels_per_point = fonts.pixels_per_point();
let font = fonts.font(&format.font_id.family);
let mut font = fonts.font(&format.font_id.family);
let font_size = format.font_id.size;
let line_height = section
.format
@@ -416,7 +416,7 @@ fn replace_last_glyph_with_overflow_character(
}
}
fn row_height(section: &LayoutSection, font: &Font, font_size: f32) -> f32 {
fn row_height(section: &LayoutSection, font: &Font<'_>, font_size: f32) -> f32 {
section
.format
.line_height
@@ -433,9 +433,9 @@ fn replace_last_glyph_with_overflow_character(
if let Some(last_glyph) = row.glyphs.last() {
let section_index = last_glyph.section_index;
let section = &job.sections[section_index as usize];
let font = fonts.font(&section.format.font_id.family);
let mut font = fonts.font(&section.format.font_id.family);
let font_size = section.format.font_id.size;
let line_height = row_height(section, font, font_size);
let line_height = row_height(section, &font, font_size);
let (_, last_glyph_info) = font.font_impl_and_glyph_info(last_glyph.chr);
@@ -470,29 +470,25 @@ fn replace_last_glyph_with_overflow_character(
} else {
let section_index = row.section_index_at_start;
let section = &job.sections[section_index as usize];
let font = fonts.font(&section.format.font_id.family);
let mut font = fonts.font(&section.format.font_id.family);
let font_size = section.format.font_id.size;
let line_height = row_height(section, font, font_size);
let line_height = row_height(section, &font, font_size);
let x = 0.0; // TODO(emilk): heed paragraph leading_space 😬
let (font_impl, replacement_glyph_info) = font.font_impl_and_glyph_info(overflow_character);
let glyph_alloc = if let Some(font_impl) = font_impl {
font_impl.allocate_glyph(replacement_glyph_info, font_size, pixels_per_point)
} else {
Default::default()
};
let (mut font_impl, replacement_glyph_alloc) =
font.font_impl_and_glyph_alloc(overflow_character, font_size, pixels_per_point);
row.glyphs.push(Glyph {
chr: overflow_character,
pos: pos2(x, f32::NAN),
advance_width: glyph_alloc.advance_width,
advance_width: replacement_glyph_alloc.advance_width,
line_height,
font_impl_height: font_impl.map_or(0.0, |f| f.row_height(font_size)),
font_impl_ascent: font_impl.map_or(0.0, |f| f.ascent(font_size)),
font_impl_height: font_impl.as_mut().map_or(0.0, |f| f.row_height(font_size)),
font_impl_ascent: font_impl.as_mut().map_or(0.0, |f| f.ascent(font_size)),
font_height: font.row_height(font_size),
font_ascent: font.ascent(font_size),
uv_rect: glyph_alloc.uv_rect,
uv_rect: replacement_glyph_alloc.uv_rect,
section_index,
});
}
@@ -519,7 +515,7 @@ fn replace_last_glyph_with_overflow_character(
let section = &job.sections[last_glyph.section_index as usize];
let extra_letter_spacing = section.format.extra_letter_spacing;
let pixels_per_point = fonts.pixels_per_point();
let font = fonts.font(&section.format.font_id.family);
let mut font = fonts.font(&section.format.font_id.family);
let font_size = section.format.font_id.size;
if let Some(prev_glyph) = prev_glyph {
@@ -573,7 +569,7 @@ fn replace_last_glyph_with_overflow_character(
return;
};
let pixels_per_point = fonts.pixels_per_point();
let font = fonts.font(&section.format.font_id.family);
let mut font = fonts.font(&section.format.font_id.family);
let font_size = section.format.font_id.size;
// Just replace and be done with it.
last_glyph.chr = overflow_character;