use std::{borrow::Cow, sync::Arc}; use ::util::ResultExt;use anyhow::{anyhow, Result};use collections::HashMap;use itertools::Itertools;use parking_lot::{RwLock, RwLockUpgradableReadGuard};use smallvec::SmallVec;use windows::{ core::*, Win32::{ Foundation::*, Globalization::GetUserDefaultLocaleName, Graphics::{ Direct2D::{Common::*, *}, DirectWrite::*, Dxgi::Common::*, Gdi::LOGFONTW, Imaging::*, }, System::SystemServices::LOCALE_NAME_MAX_LENGTH, UI::WindowsAndMessaging::*, },}; use crate::*; #[derive(Debug)]struct FontInfo { font_family: String, font_face: IDWriteFontFace3, features: IDWriteTypography, fallbacks: Option<IDWriteFontFallback>, is_system_font: bool, is_emoji: bool,} pub(crate) struct DirectWriteTextSystem(RwLock<DirectWriteState>); struct DirectWriteComponent { locale: String, factory: IDWriteFactory5, bitmap_factory: AgileReference<IWICImagingFactory>, d2d1_factory: ID2D1Factory, in_memory_loader: IDWriteInMemoryFontFileLoader, builder: IDWriteFontSetBuilder1, text_renderer: Arc<TextRendererWrapper>, render_context: GlyphRenderContext,} struct GlyphRenderContext { params: IDWriteRenderingParams3, dc_target: ID2D1DeviceContext4,} struct DirectWriteState { components: DirectWriteComponent, system_ui_font_name: SharedString, system_font_collection: IDWriteFontCollection1, custom_font_collection: IDWriteFontCollection1, fonts: Vec<FontInfo>, font_selections: HashMap<Font, FontId>, font_id_by_identifier: HashMap<FontIdentifier, FontId>,} #[derive(Debug, Clone, Hash, PartialEq, Eq)]struct FontIdentifier { postscript_name: String, weight: i32, style: i32,} impl DirectWriteComponent { pub fn new(bitmap_factory: &IWICImagingFactory) -> Result<Self> { unsafe { let factory: IDWriteFactory5 = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED)?; let bitmap_factory = AgileReference::new(bitmap_factory)?; let d2d1_factory: ID2D1Factory = D2D1CreateFactory(D2D1_FACTORY_TYPE_MULTI_THREADED, None)?; // The `IDWriteInMemoryFontFileLoader` here is supported starting from // Windows 10 Creators Update, which consequently requires the entire // `DirectWriteTextSystem` to run on `win10 1703`+. let in_memory_loader = factory.CreateInMemoryFontFileLoader()?; factory.RegisterFontFileLoader(&in_memory_loader)?; let builder = factory.CreateFontSetBuilder()?; let mut locale_vec = vec![0u16; LOCALE_NAME_MAX_LENGTH as usize]; GetUserDefaultLocaleName(&mut locale_vec); let locale = String::from_utf16_lossy(&locale_vec); let text_renderer = Arc::new(TextRendererWrapper::new(&locale)); let render_context = GlyphRenderContext::new(&factory, &d2d1_factory)?; Ok(DirectWriteComponent { locale, factory, bitmap_factory, d2d1_factory, in_memory_loader, builder, text_renderer, render_context, }) } }} impl GlyphRenderContext { pub fn new(factory: &IDWriteFactory5, d2d1_factory: &ID2D1Factory) -> Result<Self> { unsafe { let default_params: IDWriteRenderingParams3 = factory.CreateRenderingParams()?.cast()?; let gamma = default_params.GetGamma(); let enhanced_contrast = default_params.GetEnhancedContrast(); let gray_contrast = default_params.GetGrayscaleEnhancedContrast(); let cleartype_level = default_params.GetClearTypeLevel(); let grid_fit_mode = default_params.GetGridFitMode(); let params = factory.CreateCustomRenderingParams( gamma, enhanced_contrast, gray_contrast, cleartype_level, DWRITE_PIXEL_GEOMETRY_RGB, DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC, grid_fit_mode, )?; let dc_target = { let target = d2d1_factory.CreateDCRenderTarget(&get_render_target_property( DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED, ))?; let target = target.cast::<ID2D1DeviceContext4>()?; target.SetTextRenderingParams(¶ms); target }; Ok(Self { params, dc_target }) } }} impl DirectWriteTextSystem { pub(crate) fn new(bitmap_factory: &IWICImagingFactory) -> Result<Self> { let components = DirectWriteComponent::new(bitmap_factory)?; let system_font_collection = unsafe { let mut result = std::mem::zeroed(); components .factory .GetSystemFontCollection(false, &mut result, true)?; result.unwrap() }; let custom_font_set = unsafe { components.builder.CreateFontSet()? }; let custom_font_collection = unsafe { components .factory .CreateFontCollectionFromFontSet(&custom_font_set)? }; let system_ui_font_name = get_system_ui_font_name(); Ok(Self(RwLock::new(DirectWriteState { components, system_ui_font_name, system_font_collection, custom_font_collection, fonts: Vec::new(), font_selections: HashMap::default(), font_id_by_identifier: HashMap::default(), }))) }} impl PlatformTextSystem for DirectWriteTextSystem { fn add_fonts(&self, fonts: Vec<Cow<'static, [u8]>>) -> Result<()> { self.0.write().add_fonts(fonts) } fn all_font_names(&self) -> Vec<String> { self.0.read().all_font_names() } fn font_id(&self, font: &Font) -> Result<FontId> { let lock = self.0.upgradable_read(); if let Some(font_id) = lock.font_selections.get(font) { Ok(*font_id) } else { let mut lock = RwLockUpgradableReadGuard::upgrade(lock); let font_id = lock.select_font(font); lock.font_selections.insert(font.clone(), font_id); Ok(font_id) } } fn font_metrics(&self, font_id: FontId) -> FontMetrics { self.0.read().font_metrics(font_id) } fn typographic_bounds(&self, font_id: FontId, glyph_id: GlyphId) -> Result<Bounds<f32>> { self.0.read().get_typographic_bounds(font_id, glyph_id) } fn advance(&self, font_id: FontId, glyph_id: GlyphId) -> anyhow::Result<Size<f32>> { self.0.read().get_advance(font_id, glyph_id) } fn glyph_for_char(&self, font_id: FontId, ch: char) -> Option<GlyphId> { self.0.read().glyph_for_char(font_id, ch) } fn glyph_raster_bounds( &self, params: &RenderGlyphParams, ) -> anyhow::Result<Bounds<DevicePixels>> { self.0.read().raster_bounds(params) } fn rasterize_glyph( &self, params: &RenderGlyphParams, raster_bounds: Bounds<DevicePixels>, ) -> anyhow::Result<(Size<DevicePixels>, Vec<u8>)> { self.0.read().rasterize_glyph(params, raster_bounds) } fn layout_line(&self, text: &str, font_size: Pixels, runs: &[FontRun]) -> LineLayout { self.0 .write() .layout_line(text, font_size, runs) .log_err() .unwrap_or(LineLayout { font_size, ..Default::default() }) }} impl DirectWriteState { fn add_fonts(&mut self, fonts: Vec<Cow<'static, [u8]>>) -> Result<()> { for font_data in fonts { match font_data { Cow::Borrowed(data) => unsafe { let font_file = self .components .in_memory_loader .CreateInMemoryFontFileReference( &self.components.factory, data.as_ptr() as _, data.len() as _, None, )?; self.components.builder.AddFontFile(&font_file)?; }, Cow::Owned(data) => unsafe { let font_file = self .components .in_memory_loader .CreateInMemoryFontFileReference( &self.components.factory, data.as_ptr() as _, data.len() as _, None, )?; self.components.builder.AddFontFile(&font_file)?; }, } } let set = unsafe { self.components.builder.CreateFontSet()? }; let collection = unsafe { self.components .factory .CreateFontCollectionFromFontSet(&set)? }; self.custom_font_collection = collection; Ok(()) } fn generate_font_fallbacks( &self, fallbacks: &FontFallbacks, ) -> Result<Option<IDWriteFontFallback>> { if fallbacks.fallback_list().is_empty() { return Ok(None); } unsafe { let builder = self.components.factory.CreateFontFallbackBuilder()?; let font_set = &self.system_font_collection.GetFontSet()?; for family_name in fallbacks.fallback_list() { let Some(fonts) = font_set .GetMatchingFonts( &HSTRING::from(family_name), DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, ) .log_err() else { continue; }; if fonts.GetFontCount() == 0 { log::error!("No matching font found for {}", family_name); continue; } let font = fonts.GetFontFaceReference(0)?.CreateFontFace()?; let mut count = 0; font.GetUnicodeRanges(None, &mut count).ok(); if count == 0 { continue; } let mut unicode_ranges = vec![DWRITE_UNICODE_RANGE::default(); count as usize]; let Some(_) = font .GetUnicodeRanges(Some(&mut unicode_ranges), &mut count) .log_err() else { continue; }; let target_family_name = HSTRING::from(family_name); builder.AddMapping( &unicode_ranges, &[target_family_name.as_ptr()], None, None, None, 1.0, )?; } let system_fallbacks = self.components.factory.GetSystemFontFallback()?; builder.AddMappings(&system_fallbacks)?; Ok(Some(builder.CreateFontFallback()?)) } } unsafe fn generate_font_features( &self, font_features: &FontFeatures, ) -> Result<IDWriteTypography> { let direct_write_features = self.components.factory.CreateTypography()?; apply_font_features(&direct_write_features, font_features)?; Ok(direct_write_features) } unsafe fn get_font_id_from_font_collection( &mut self, family_name: &str, font_weight: FontWeight, font_style: FontStyle, font_features: &FontFeatures, font_fallbacks: Option<&FontFallbacks>, is_system_font: bool, ) -> Option<FontId> { let collection = if is_system_font { &self.system_font_collection } else { &self.custom_font_collection }; let fontset = collection.GetFontSet().log_err()?; let font = fontset .GetMatchingFonts( &HSTRING::from(family_name), font_weight.into(), DWRITE_FONT_STRETCH_NORMAL, font_style.into(), ) .log_err()?; let total_number = font.GetFontCount(); for index in 0..total_number { let Some(font_face_ref) = font.GetFontFaceReference(index).log_err() else { continue; }; let Some(font_face) = font_face_ref.CreateFontFace().log_err() else { continue; }; let Some(identifier) = get_font_identifier(&font_face, &self.components.locale) else { continue; }; let is_emoji = font_face.IsColorFont().as_bool(); let Some(direct_write_features) = self.generate_font_features(font_features).log_err() else { continue; }; let fallbacks = font_fallbacks .and_then(|fallbacks| self.generate_font_fallbacks(fallbacks).log_err().flatten()); let font_info = FontInfo { font_family: family_name.to_owned(), font_face, features: direct_write_features, fallbacks, is_system_font, is_emoji, }; let font_id = FontId(self.fonts.len()); self.fonts.push(font_info); self.font_id_by_identifier.insert(identifier, font_id); return Some(font_id); } None } unsafe fn update_system_font_collection(&mut self) { let mut collection = std::mem::zeroed(); if self .components .factory .GetSystemFontCollection(false, &mut collection, true) .log_err() .is_some() { self.system_font_collection = collection.unwrap(); } } fn select_font(&mut self, target_font: &Font) -> FontId { unsafe { if target_font.family == ".SystemUIFont" { let family = self.system_ui_font_name.clone(); self.find_font_id( family.as_ref(), target_font.weight, target_font.style, &target_font.features, target_font.fallbacks.as_ref(), ) .unwrap() } else { self.find_font_id( target_font.family.as_ref(), target_font.weight, target_font.style, &target_font.features, target_font.fallbacks.as_ref(), ) .unwrap_or_else(|| { #[cfg(any(test, feature = "test-support"))] { panic!("ERROR: {} font not found!", target_font.family); } #[cfg(not(any(test, feature = "test-support")))] { let family = self.system_ui_font_name.clone(); log::error!("{} not found, use {} instead.", target_font.family, family); self.get_font_id_from_font_collection( family.as_ref(), target_font.weight, target_font.style, &target_font.features, target_font.fallbacks.as_ref(), true, ) .unwrap() } }) } } } unsafe fn find_font_id( &mut self, family_name: &str, weight: FontWeight, style: FontStyle, features: &FontFeatures, fallbacks: Option<&FontFallbacks>, ) -> Option<FontId> { // try to find target font in custom font collection first self.get_font_id_from_font_collection( family_name, weight, style, features, fallbacks, false, ) .or_else(|| { self.get_font_id_from_font_collection( family_name, weight, style, features, fallbacks, true, ) }) .or_else(|| { self.update_system_font_collection(); self.get_font_id_from_font_collection( family_name, weight, style, features, fallbacks, true, ) }) } fn layout_line( &mut self, text: &str, font_size: Pixels, font_runs: &[FontRun], ) -> Result<LineLayout> { if font_runs.is_empty() {Lines 1–500 of 1502. Load more
use std::{borrow::Cow, sync::Arc}; use ::util::ResultExt; use anyhow::{anyhow, Result}; use collections::HashMap; use itertools::Itertools; use parking_lot::{RwLock, RwLockUpgradableReadGuard}; use smallvec::SmallVec; use windows::{ core::*, Win32::{ Foundation::*, Globalization::GetUserDefaultLocaleName, Graphics::{ Direct2D::{Common::*, *}, DirectWrite::*, Dxgi::Common::*, Gdi::LOGFONTW, Imaging::*, }, System::SystemServices::LOCALE_NAME_MAX_LENGTH, UI::WindowsAndMessaging::*, }, }; use crate::*; #[derive(Debug)] struct FontInfo { font_family: String, font_face: IDWriteFontFace3, features: IDWriteTypography, fallbacks: Option<IDWriteFontFallback>, is_system_font: bool, is_emoji: bool, } pub(crate) struct DirectWriteTextSystem(RwLock<DirectWriteState>); struct DirectWriteComponent { locale: String, factory: IDWriteFactory5, bitmap_factory: AgileReference<IWICImagingFactory>, d2d1_factory: ID2D1Factory, in_memory_loader: IDWriteInMemoryFontFileLoader, builder: IDWriteFontSetBuilder1, text_renderer: Arc<TextRendererWrapper>, render_context: GlyphRenderContext, } struct GlyphRenderContext { params: IDWriteRenderingParams3, dc_target: ID2D1DeviceContext4, } struct DirectWriteState { components: DirectWriteComponent, system_ui_font_name: SharedString, system_font_collection: IDWriteFontCollection1, custom_font_collection: IDWriteFontCollection1, fonts: Vec<FontInfo>, font_selections: HashMap<Font, FontId>, font_id_by_identifier: HashMap<FontIdentifier, FontId>, } #[derive(Debug, Clone, Hash, PartialEq, Eq)] struct FontIdentifier { postscript_name: String, weight: i32, style: i32, } impl DirectWriteComponent { pub fn new(bitmap_factory: &IWICImagingFactory) -> Result<Self> { unsafe { let factory: IDWriteFactory5 = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED)?; let bitmap_factory = AgileReference::new(bitmap_factory)?; let d2d1_factory: ID2D1Factory = D2D1CreateFactory(D2D1_FACTORY_TYPE_MULTI_THREADED, None)?; // The `IDWriteInMemoryFontFileLoader` here is supported starting from // Windows 10 Creators Update, which consequently requires the entire // `DirectWriteTextSystem` to run on `win10 1703`+. let in_memory_loader = factory.CreateInMemoryFontFileLoader()?; factory.RegisterFontFileLoader(&in_memory_loader)?; let builder = factory.CreateFontSetBuilder()?; let mut locale_vec = vec![0u16; LOCALE_NAME_MAX_LENGTH as usize]; GetUserDefaultLocaleName(&mut locale_vec); let locale = String::from_utf16_lossy(&locale_vec); let text_renderer = Arc::new(TextRendererWrapper::new(&locale)); let render_context = GlyphRenderContext::new(&factory, &d2d1_factory)?; Ok(DirectWriteComponent { locale, factory, bitmap_factory, d2d1_factory, in_memory_loader, builder, text_renderer, render_context, }) } } } impl GlyphRenderContext { pub fn new(factory: &IDWriteFactory5, d2d1_factory: &ID2D1Factory) -> Result<Self> { unsafe { let default_params: IDWriteRenderingParams3 = factory.CreateRenderingParams()?.cast()?; let gamma = default_params.GetGamma(); let enhanced_contrast = default_params.GetEnhancedContrast(); let gray_contrast = default_params.GetGrayscaleEnhancedContrast(); let cleartype_level = default_params.GetClearTypeLevel(); let grid_fit_mode = default_params.GetGridFitMode(); let params = factory.CreateCustomRenderingParams( gamma, enhanced_contrast, gray_contrast, cleartype_level, DWRITE_PIXEL_GEOMETRY_RGB, DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC, grid_fit_mode, )?; let dc_target = { let target = d2d1_factory.CreateDCRenderTarget(&get_render_target_property( DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED, ))?; let target = target.cast::<ID2D1DeviceContext4>()?; target.SetTextRenderingParams(¶ms); target }; Ok(Self { params, dc_target }) } } } impl DirectWriteTextSystem { pub(crate) fn new(bitmap_factory: &IWICImagingFactory) -> Result<Self> { let components = DirectWriteComponent::new(bitmap_factory)?; let system_font_collection = unsafe { let mut result = std::mem::zeroed(); components .factory .GetSystemFontCollection(false, &mut result, true)?; result.unwrap() }; let custom_font_set = unsafe { components.builder.CreateFontSet()? }; let custom_font_collection = unsafe { components .factory .CreateFontCollectionFromFontSet(&custom_font_set)? }; let system_ui_font_name = get_system_ui_font_name(); Ok(Self(RwLock::new(DirectWriteState { components, system_ui_font_name, system_font_collection, custom_font_collection, fonts: Vec::new(), font_selections: HashMap::default(), font_id_by_identifier: HashMap::default(), }))) } } impl PlatformTextSystem for DirectWriteTextSystem { fn add_fonts(&self, fonts: Vec<Cow<'static, [u8]>>) -> Result<()> { self.0.write().add_fonts(fonts) } fn all_font_names(&self) -> Vec<String> { self.0.read().all_font_names() } fn font_id(&self, font: &Font) -> Result<FontId> { let lock = self.0.upgradable_read(); if let Some(font_id) = lock.font_selections.get(font) { Ok(*font_id) } else { let mut lock = RwLockUpgradableReadGuard::upgrade(lock); let font_id = lock.select_font(font); lock.font_selections.insert(font.clone(), font_id); Ok(font_id) } } fn font_metrics(&self, font_id: FontId) -> FontMetrics { self.0.read().font_metrics(font_id) } fn typographic_bounds(&self, font_id: FontId, glyph_id: GlyphId) -> Result<Bounds<f32>> { self.0.read().get_typographic_bounds(font_id, glyph_id) } fn advance(&self, font_id: FontId, glyph_id: GlyphId) -> anyhow::Result<Size<f32>> { self.0.read().get_advance(font_id, glyph_id) } fn glyph_for_char(&self, font_id: FontId, ch: char) -> Option<GlyphId> { self.0.read().glyph_for_char(font_id, ch) } fn glyph_raster_bounds( &self, params: &RenderGlyphParams, ) -> anyhow::Result<Bounds<DevicePixels>> { self.0.read().raster_bounds(params) } fn rasterize_glyph( &self, params: &RenderGlyphParams, raster_bounds: Bounds<DevicePixels>, ) -> anyhow::Result<(Size<DevicePixels>, Vec<u8>)> { self.0.read().rasterize_glyph(params, raster_bounds) } fn layout_line(&self, text: &str, font_size: Pixels, runs: &[FontRun]) -> LineLayout { self.0 .write() .layout_line(text, font_size, runs) .log_err() .unwrap_or(LineLayout { font_size, ..Default::default() }) } } impl DirectWriteState { fn add_fonts(&mut self, fonts: Vec<Cow<'static, [u8]>>) -> Result<()> { for font_data in fonts { match font_data { Cow::Borrowed(data) => unsafe { let font_file = self .components .in_memory_loader .CreateInMemoryFontFileReference( &self.components.factory, data.as_ptr() as _, data.len() as _, None, )?; self.components.builder.AddFontFile(&font_file)?; }, Cow::Owned(data) => unsafe { let font_file = self .components .in_memory_loader .CreateInMemoryFontFileReference( &self.components.factory, data.as_ptr() as _, data.len() as _, None, )?; self.components.builder.AddFontFile(&font_file)?; }, } } let set = unsafe { self.components.builder.CreateFontSet()? }; let collection = unsafe { self.components .factory .CreateFontCollectionFromFontSet(&set)? }; self.custom_font_collection = collection; Ok(()) } fn generate_font_fallbacks( &self, fallbacks: &FontFallbacks, ) -> Result<Option<IDWriteFontFallback>> { if fallbacks.fallback_list().is_empty() { return Ok(None); } unsafe { let builder = self.components.factory.CreateFontFallbackBuilder()?; let font_set = &self.system_font_collection.GetFontSet()?; for family_name in fallbacks.fallback_list() { let Some(fonts) = font_set .GetMatchingFonts( &HSTRING::from(family_name), DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, ) .log_err() else { continue; }; if fonts.GetFontCount() == 0 { log::error!("No matching font found for {}", family_name); continue; } let font = fonts.GetFontFaceReference(0)?.CreateFontFace()?; let mut count = 0; font.GetUnicodeRanges(None, &mut count).ok(); if count == 0 { continue; } let mut unicode_ranges = vec![DWRITE_UNICODE_RANGE::default(); count as usize]; let Some(_) = font .GetUnicodeRanges(Some(&mut unicode_ranges), &mut count) .log_err() else { continue; }; let target_family_name = HSTRING::from(family_name); builder.AddMapping( &unicode_ranges, &[target_family_name.as_ptr()], None, None, None, 1.0, )?; } let system_fallbacks = self.components.factory.GetSystemFontFallback()?; builder.AddMappings(&system_fallbacks)?; Ok(Some(builder.CreateFontFallback()?)) } } unsafe fn generate_font_features( &self, font_features: &FontFeatures, ) -> Result<IDWriteTypography> { let direct_write_features = self.components.factory.CreateTypography()?; apply_font_features(&direct_write_features, font_features)?; Ok(direct_write_features) } unsafe fn get_font_id_from_font_collection( &mut self, family_name: &str, font_weight: FontWeight, font_style: FontStyle, font_features: &FontFeatures, font_fallbacks: Option<&FontFallbacks>, is_system_font: bool, ) -> Option<FontId> { let collection = if is_system_font { &self.system_font_collection } else { &self.custom_font_collection }; let fontset = collection.GetFontSet().log_err()?; let font = fontset .GetMatchingFonts( &HSTRING::from(family_name), font_weight.into(), DWRITE_FONT_STRETCH_NORMAL, font_style.into(), ) .log_err()?; let total_number = font.GetFontCount(); for index in 0..total_number { let Some(font_face_ref) = font.GetFontFaceReference(index).log_err() else { continue; }; let Some(font_face) = font_face_ref.CreateFontFace().log_err() else { continue; }; let Some(identifier) = get_font_identifier(&font_face, &self.components.locale) else { continue; }; let is_emoji = font_face.IsColorFont().as_bool(); let Some(direct_write_features) = self.generate_font_features(font_features).log_err() else { continue; }; let fallbacks = font_fallbacks .and_then(|fallbacks| self.generate_font_fallbacks(fallbacks).log_err().flatten()); let font_info = FontInfo { font_family: family_name.to_owned(), font_face, features: direct_write_features, fallbacks, is_system_font, is_emoji, }; let font_id = FontId(self.fonts.len()); self.fonts.push(font_info); self.font_id_by_identifier.insert(identifier, font_id); return Some(font_id); } None } unsafe fn update_system_font_collection(&mut self) { let mut collection = std::mem::zeroed(); if self .components .factory .GetSystemFontCollection(false, &mut collection, true) .log_err() .is_some() { self.system_font_collection = collection.unwrap(); } } fn select_font(&mut self, target_font: &Font) -> FontId { unsafe { if target_font.family == ".SystemUIFont" { let family = self.system_ui_font_name.clone(); self.find_font_id( family.as_ref(), target_font.weight, target_font.style, &target_font.features, target_font.fallbacks.as_ref(), ) .unwrap() } else { self.find_font_id( target_font.family.as_ref(), target_font.weight, target_font.style, &target_font.features, target_font.fallbacks.as_ref(), ) .unwrap_or_else(|| { #[cfg(any(test, feature = "test-support"))] { panic!("ERROR: {} font not found!", target_font.family); } #[cfg(not(any(test, feature = "test-support")))] { let family = self.system_ui_font_name.clone(); log::error!("{} not found, use {} instead.", target_font.family, family); self.get_font_id_from_font_collection( family.as_ref(), target_font.weight, target_font.style, &target_font.features, target_font.fallbacks.as_ref(), true, ) .unwrap() } }) } } } unsafe fn find_font_id( &mut self, family_name: &str, weight: FontWeight, style: FontStyle, features: &FontFeatures, fallbacks: Option<&FontFallbacks>, ) -> Option<FontId> { // try to find target font in custom font collection first self.get_font_id_from_font_collection( family_name, weight, style, features, fallbacks, false, ) .or_else(|| { self.get_font_id_from_font_collection( family_name, weight, style, features, fallbacks, true, ) }) .or_else(|| { self.update_system_font_collection(); self.get_font_id_from_font_collection( family_name, weight, style, features, fallbacks, true, ) }) } fn layout_line( &mut self, text: &str, font_size: Pixels, font_runs: &[FontRun], ) -> Result<LineLayout> { if font_runs.is_empty() {