mirror of
https://github.com/wez/wezterm.git
synced 2024-11-24 07:46:59 +03:00
fonts: FontConfiguration::resolve_font
Can now create a LoadedFont that ties together the new abstractions. It's not yet sufficient to use in wezterm though.
This commit is contained in:
parent
cd07a31d84
commit
c91345cbd6
@ -1,4 +1,4 @@
|
||||
use failure::{bail, format_err, Error};
|
||||
use failure::{bail, format_err, Error, Fallible};
|
||||
use log::{debug, error};
|
||||
use serde_derive::*;
|
||||
mod ftfont;
|
||||
@ -35,13 +35,15 @@ pub mod fontloader_and_freetype;
|
||||
pub mod fontkit;
|
||||
|
||||
use crate::font::loader::{FontLocator, FontLocatorSelection};
|
||||
use crate::font::rasterizer::{FontRasterizer, FontRasterizerSelection};
|
||||
use crate::font::shaper::{FontShaper, FontShaperSelection};
|
||||
|
||||
use super::config::{configuration, ConfigHandle, TextStyle};
|
||||
use term::CellAttributes;
|
||||
|
||||
pub struct LoadedFont {
|
||||
rasterizer: Box<dyn rasterizer::FontRasterizer>,
|
||||
shaper: Box<dyn shaper::FontShaper>,
|
||||
rasterizers: Vec<Box<dyn FontRasterizer>>,
|
||||
shaper: Box<dyn FontShaper>,
|
||||
}
|
||||
|
||||
type FontPtr = Rc<RefCell<Box<dyn NamedFont>>>;
|
||||
@ -176,6 +178,30 @@ impl FontConfiguration {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn resolve_font(&self, style: &TextStyle) -> Fallible<Rc<LoadedFont>> {
|
||||
let mut fonts = self.new_fonts.borrow_mut();
|
||||
if let Some(entry) = fonts.get(style) {
|
||||
return Ok(Rc::clone(entry));
|
||||
}
|
||||
|
||||
let attributes = style.font_with_fallback();
|
||||
let handles = self.loader.load_fonts(&attributes)?;
|
||||
let mut rasterizers = vec![];
|
||||
for handle in &handles {
|
||||
rasterizers.push(FontRasterizerSelection::get_default().new_rasterizer(&handle)?);
|
||||
}
|
||||
let shaper = FontShaperSelection::get_default().new_shaper(&handles)?;
|
||||
|
||||
let loaded = Rc::new(LoadedFont {
|
||||
rasterizers,
|
||||
shaper,
|
||||
});
|
||||
|
||||
fonts.insert(style.clone(), Rc::clone(&loaded));
|
||||
|
||||
Ok(loaded)
|
||||
}
|
||||
|
||||
/// Given a text style, load (with caching) the font that best
|
||||
/// matches according to the fontconfig pattern.
|
||||
pub fn cached_font(&self, style: &TextStyle) -> Result<Rc<RefCell<Box<dyn NamedFont>>>, Error> {
|
||||
|
@ -1,3 +1,4 @@
|
||||
use crate::font::loader::FontDataHandle;
|
||||
use crate::font::rasterizer::FontRasterizer;
|
||||
use crate::font::{ftwrap, RasterizedGlyph};
|
||||
use ::freetype::FT_GlyphSlotRec_;
|
||||
@ -8,6 +9,7 @@ use std::slice;
|
||||
|
||||
pub struct FreeTypeRasterizer {
|
||||
face: RefCell<ftwrap::Face>,
|
||||
lib: ftwrap::Library,
|
||||
has_color: bool,
|
||||
}
|
||||
|
||||
@ -263,12 +265,14 @@ impl FreeTypeRasterizer {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_face(face: ftwrap::Face) -> Fallible<Self> {
|
||||
pub fn from_locator(handle: &FontDataHandle) -> Fallible<Self> {
|
||||
let lib = ftwrap::Library::new()?;
|
||||
let face = lib.face_from_locator(handle)?;
|
||||
let has_color = unsafe {
|
||||
(((*face.face).face_flags as u32) & (ftwrap::FT_FACE_FLAG_COLOR as u32)) != 0
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
lib,
|
||||
face: RefCell::new(face),
|
||||
has_color,
|
||||
})
|
||||
|
@ -1,5 +1,8 @@
|
||||
use crate::font::loader::FontDataHandle;
|
||||
use crate::font::system::RasterizedGlyph;
|
||||
use failure::Fallible;
|
||||
use failure::{bail, format_err, Error, Fallible};
|
||||
use serde_derive::*;
|
||||
use std::sync::Mutex;
|
||||
|
||||
pub mod freetype;
|
||||
|
||||
@ -8,3 +11,59 @@ pub mod freetype;
|
||||
pub trait FontRasterizer {
|
||||
fn rasterize_glyph(&self, glyph_pos: u32, size: f64, dpi: u32) -> Fallible<RasterizedGlyph>;
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Clone, Copy)]
|
||||
pub enum FontRasterizerSelection {
|
||||
FreeType,
|
||||
FontKit,
|
||||
}
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
static ref DEFAULT_RASTER: Mutex<FontRasterizerSelection> = Mutex::new(Default::default());
|
||||
}
|
||||
|
||||
impl Default for FontRasterizerSelection {
|
||||
fn default() -> Self {
|
||||
FontRasterizerSelection::FreeType
|
||||
}
|
||||
}
|
||||
|
||||
impl FontRasterizerSelection {
|
||||
pub fn set_default(self) {
|
||||
let mut def = DEFAULT_RASTER.lock().unwrap();
|
||||
*def = self;
|
||||
}
|
||||
|
||||
pub fn get_default() -> Self {
|
||||
let def = DEFAULT_RASTER.lock().unwrap();
|
||||
*def
|
||||
}
|
||||
|
||||
pub fn variants() -> Vec<&'static str> {
|
||||
vec!["FreeType", "FontKit"]
|
||||
}
|
||||
|
||||
pub fn new_rasterizer(self, handle: &FontDataHandle) -> Fallible<Box<dyn FontRasterizer>> {
|
||||
match self {
|
||||
Self::FreeType => Ok(Box::new(freetype::FreeTypeRasterizer::from_locator(
|
||||
handle,
|
||||
)?)),
|
||||
Self::FontKit => bail!("FontKit rasterizer not implemented yet"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::str::FromStr for FontRasterizerSelection {
|
||||
type Err = Error;
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s.to_lowercase().as_ref() {
|
||||
"freetype" => Ok(Self::FreeType),
|
||||
"fontkit" => Ok(Self::FontKit),
|
||||
_ => Err(format_err!(
|
||||
"{} is not a valid FontRasterizerSelection variant, possible values are {:?}",
|
||||
s,
|
||||
Self::variants()
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,8 @@
|
||||
use crate::font::loader::FontDataHandle;
|
||||
use crate::font::system::GlyphInfo;
|
||||
use failure::Fallible;
|
||||
use failure::{format_err, Error, Fallible};
|
||||
use serde_derive::*;
|
||||
use std::sync::Mutex;
|
||||
|
||||
pub mod harfbuzz;
|
||||
|
||||
@ -7,3 +10,54 @@ pub trait FontShaper {
|
||||
/// Shape text and return a vector of GlyphInfo
|
||||
fn shape(&self, text: &str, size: f64, dpi: u32) -> Fallible<Vec<GlyphInfo>>;
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Clone, Copy)]
|
||||
pub enum FontShaperSelection {
|
||||
Harfbuzz,
|
||||
}
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
static ref DEFAULT_SHAPER: Mutex<FontShaperSelection> = Mutex::new(Default::default());
|
||||
}
|
||||
|
||||
impl Default for FontShaperSelection {
|
||||
fn default() -> Self {
|
||||
FontShaperSelection::Harfbuzz
|
||||
}
|
||||
}
|
||||
|
||||
impl FontShaperSelection {
|
||||
pub fn set_default(self) {
|
||||
let mut def = DEFAULT_SHAPER.lock().unwrap();
|
||||
*def = self;
|
||||
}
|
||||
|
||||
pub fn get_default() -> Self {
|
||||
let def = DEFAULT_SHAPER.lock().unwrap();
|
||||
*def
|
||||
}
|
||||
|
||||
pub fn variants() -> Vec<&'static str> {
|
||||
vec!["Harfbuzz"]
|
||||
}
|
||||
|
||||
pub fn new_shaper(self, handles: &[FontDataHandle]) -> Fallible<Box<dyn FontShaper>> {
|
||||
match self {
|
||||
Self::Harfbuzz => Ok(Box::new(harfbuzz::HarfbuzzShaper::new(handles)?)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::str::FromStr for FontShaperSelection {
|
||||
type Err = Error;
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s.to_lowercase().as_ref() {
|
||||
"harfbuzz" => Ok(Self::Harfbuzz),
|
||||
_ => Err(format_err!(
|
||||
"{} is not a valid FontShaperSelection variant, possible values are {:?}",
|
||||
s,
|
||||
Self::variants()
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user