-
Notifications
You must be signed in to change notification settings - Fork 2.9k
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
Rework fontconfig fallback to use fallback list computed from font_sort #3163
Conversation
9cc6e9c
to
b3f653d
Compare
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.
Just some ramblings that jumped to my mind when having a quick glance at things.
Generally most of this makes sense to me, so we just need to nail down the exact implementation, but the approach seems good.
font/src/ft/mod.rs
Outdated
let fallback_list = self.fallback_lists.remove(&font_key).unwrap_or_default(); | ||
|
||
for font in fallback_list { | ||
let font_path = font.file(0).unwrap(); |
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 don't think any of the old code unwraps on font.file(0)
. Is this safe to do? Also mind explaining to me what the importance of the 0
is? Are there potentially multiple files available?
If this isn't just because this is a WIP, but it's still safe, we should probably expect
.
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 unwrap could be if let Some()
, but I just I'd like to keep it like that for now, since I don't get it, how your pattern couldn't have a path after you query the thing. I'll come back to it later, since I don't really like to unwrap things.
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.
Makes sense, yeah. I could see how file(0).unwrap() might be safe, but file(1).unwrap() might not be or something like that.
font/src/ft/mod.rs
Outdated
// Reuse the original fontkey if you're reloading the font | ||
let key = if let Some(key) = key { | ||
key | ||
} else { | ||
FontKey::next() | ||
}; |
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.
Why do we bother with reusing the fontkey if possible here? Is that related to possible duplications between different fonts (like bold/italic/normal/...).
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.
Imagine you're a downstream crate, and you request 2 fonts, A
, B
, where A
== B
. So I'm loading font A
and getting FontKey 1
, then I'm trying to load font B
which is the same as A
, so if I don't reuse FontKey, you'll invalidate a FontKey for A
and generate a new one for B
, so next time your downstream will query the font by FontKey
,which it got for A
it wont get the right one (I was fixing this issue during implementation). So you don't want your internal caches affect your public API. Technically this should also applies to fallback fonts, but since alacritty is the only one downstream right now, and wiping the cache I thought that it's fine for now.
font/src/ft/mod.rs
Outdated
// This code will be hit, only if you don't have glyph at all or didn't | ||
// loaded font, so not that hot for a normal scenario and all costly parts | ||
// are inside the if |
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.
If I understand this correctly, this code will load the font once, if it hasn't been loaded yet?
Why don't we do this when the fallback list is loaded initially for all fonts in that list? Is it to minimize the number of fonts we have to load, so on a system with 150 fallback fonts we don't load 150 fonts but instead just load the first few (assuming those cover most characters)?
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.
Yes, it'll load once when you're facing a font that hasn't been loaded in your fallback list and the char you're requesting is presented in this font. This code is fast and there's no desire to build all faces for all fonts during load_font. I don't want to load 150 faces for fonts that we wont use. Like I can work only with ASCII most of time, why should I load all the things, it's just pointless.
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, makes a lot of sense. Though it is a bit messy. Might be good to at least put that in another function with a descriptive name, so the initialization of a font isn't just sitting in some random match statement somewhere.
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.
There are still some things I want to try on this branch "path", so I'll leave it here as it is for now, and come back later.
b3f653d
to
b586616
Compare
The main problem I see with the current FontKey + cache updates is that I didn't have much time to look into how we should approach our internal structure. Right now you can't have multiple fonts, but with different font sizes for e.g. So you can't have But there's nothing wrong in invalidating FontKeys for fallbacks tbh(without solving fist issue), because you can't load the same font twice, but with different sizes, so your fallbacks should also update their sizes -> we can safely invalidate them for now. |
That makes sense, yeah. Maybe it makes sense to think about our API a bit and how we would want both Alacritty and others to use it. |
51b3aa4
to
f77f502
Compare
a9f608d
to
0499f4f
Compare
0499f4f
to
7cb289c
Compare
font/src/ft/fc/pattern.rs
Outdated
pub fn get_charset(&self) -> &CharSetRef { | ||
unsafe { | ||
let mut charset: *mut _ = ptr::null_mut(); | ||
// We should likely check the result |
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.
If we should, we should probably do it now?
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 can't find any docs on what it can return or fail with. Like I can check, but I don't know what to check...
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.
These are convenience functions that call FcPatternGet and verify that the returned data is of the expected type. They return FcResultTypeMismatch if this is not the case.
font/src/ft/mod.rs
Outdated
let fallback_list = self.fallback_lists.remove(&font_key).unwrap_or_default(); | ||
|
||
for font_pattern in &fallback_list.list { | ||
|
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.
font/src/ft/mod.rs
Outdated
fn face_from_pattern(&mut self, pattern: &fc::Pattern) -> Result<Option<FontKey>, Error> { | ||
fn face_from_pattern( | ||
&mut self, | ||
pattern: &fc::PatternRef, |
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.
pattern: &fc::PatternRef, | |
pattern: &PatternRef, |
I think PatternRef
can probably safely be imported directly, right?
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 think we can.
font/src/ft/mod.rs
Outdated
// Recreate a pattern | ||
let mut pattern = fc::Pattern::new(); | ||
pattern.add_pixelsize(self.pixel_size as f64); | ||
// Unwrap should be safe in general, however let's play safe here |
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 don't think there's much value in this comment. If it's 100% safe and we decide to go for it, we should just unwrap. If we have doubts, then we should fallback. But stating that it's 100% safe while doing the opposite will just lead to confusion.
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 guess I've forgot to remove this comment or something like that.
font/src/ft/mod.rs
Outdated
let config = fc::Config::get_current(); | ||
|
||
// Recreate a pattern | ||
let mut pattern = fc::Pattern::new(); |
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.
Why do we have to create a new pattern here, instead of using the pattern
we cloned from font_pattern
and then just setting the pixelsize on 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.
This is a specific thing to docs... You should use your "original pattern" (the one you've used to font_sort) and use a thing from font_sort(the font_pattern) + render_pattern to get a valid thing.
font/src/ft/mod.rs
Outdated
pattern.add_family( | ||
font_pattern.family().next().unwrap_or_else(|| "monospace"), | ||
); | ||
// We should render pattern, otherwise most of its properties wont work |
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 should render pattern, otherwise most of its properties wont work | |
// Render pattern, otherwise most of its properties wont work |
font/src/ft/mod.rs
Outdated
// We should render pattern, otherwise most of its properties wont work | ||
let pattern = pattern.render_prepare(config, font_pattern); | ||
|
||
let key = self.face_from_pattern(&pattern, None)?.unwrap(); |
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.
Unwrapping on this seems strange? How do we know it will always be Some
?
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.
You can get None
if your pattern doesn't have path, but you're already matching by path in this loop, so you know that pattern has path, that means that check can't fail.
font/src/ft/mod.rs
Outdated
// Theoretically you shouldn't reach this point, but let's just keep it and don't try to be | ||
// smart and assert here | ||
Ok(glyph.font_key) |
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.
Similar to the unwrap comment, I don't think this comment is great. It also indicates that maybe our code structure isn't ideal. Having this here at the end 'just to be safe' with a half-hearted comment does not give me much confidence in this function.
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 don't want to wrap everything in a giant if-else or something like that, suggestion are welcome here.
Fixes alacritty#3134. Fixes alacritty#2657. Fixes alacritty#1560. Fixes alacritty#965. Fixes Linux/BSD parts of alacritty#511.
7cb289c
to
35faa8d
Compare
c780141
to
43e7d47
Compare
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 think this is good to go as far as I'm concerned.
Attempt to improve fontconfig fallback mechanism to be faster and more predictive for users. The idea is to use a fallback list from font_sort.
Probably should fix:
#3134
#2657
#1560
#2935
#965
Some fallback problems there #153
Concerns there #2706
Improve Linux/BSD parts of #511?
cc @nixpulvis
P.s. I've just published some initial attempt to solve mentioned issues, so feedback and testing is welcome.
TODO:
2micro seconds, should be innot true, and using a different thing doesn't change anything...nano
!Out of scope: