use std::{ borrow::Cow, ffi::{c_uint, c_void}, sync::Arc,}; use ::util::ResultExt;use anyhow::{Context, Result};use collections::HashMap;use itertools::Itertools;use parking_lot::{RwLock, RwLockUpgradableReadGuard};use windows::{ Win32::{ Foundation::*, Globalization::GetUserDefaultLocaleName, Graphics::{ Direct3D::D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP, Direct3D11::*, DirectWrite::*, Dxgi::Common::*, Gdi::LOGFONTW, }, System::SystemServices::LOCALE_NAME_MAX_LENGTH, UI::WindowsAndMessaging::*, }, core::*,};use windows_numerics::Vector2; use crate::*; #[derive(Debug)]struct FontInfo { font_family: String, font_face: IDWriteFontFace3, features: IDWriteTypography, fallbacks: Option<IDWriteFontFallback>, is_system_font: bool,} pub(crate) struct DirectWriteTextSystem(RwLock<DirectWriteState>); struct DirectWriteComponent { locale: String, factory: IDWriteFactory5, in_memory_loader: IDWriteInMemoryFontFileLoader, builder: IDWriteFontSetBuilder1, text_renderer: Arc<TextRendererWrapper>, gpu_state: GPUState,} struct GPUState { device: ID3D11Device, device_context: ID3D11DeviceContext, sampler: [Option<ID3D11SamplerState>; 1], blend_state: ID3D11BlendState, vertex_shader: ID3D11VertexShader, pixel_shader: ID3D11PixelShader,} 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>, system_subpixel_rendering: bool,} #[derive(Debug, Clone, Hash, PartialEq, Eq)]struct FontIdentifier { postscript_name: String, weight: i32, style: i32,} impl DirectWriteComponent { pub fn new(directx_devices: &DirectXDevices) -> Result<Self> { // todo: ideally this would not be a large unsafe block but smaller isolated ones for easier auditing unsafe { let factory: IDWriteFactory5 = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED)?; // 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 gpu_state = GPUState::new(directx_devices)?; Ok(DirectWriteComponent { locale, factory, in_memory_loader, builder, text_renderer, gpu_state, }) } }} impl GPUState { fn new(directx_devices: &DirectXDevices) -> Result<Self> { let device = directx_devices.device.clone(); let device_context = directx_devices.device_context.clone(); let blend_state = { let mut blend_state = None; let desc = D3D11_BLEND_DESC { AlphaToCoverageEnable: false.into(), IndependentBlendEnable: false.into(), RenderTarget: [ D3D11_RENDER_TARGET_BLEND_DESC { BlendEnable: true.into(), SrcBlend: D3D11_BLEND_ONE, DestBlend: D3D11_BLEND_INV_SRC_ALPHA, BlendOp: D3D11_BLEND_OP_ADD, SrcBlendAlpha: D3D11_BLEND_ONE, DestBlendAlpha: D3D11_BLEND_INV_SRC_ALPHA, BlendOpAlpha: D3D11_BLEND_OP_ADD, RenderTargetWriteMask: D3D11_COLOR_WRITE_ENABLE_ALL.0 as u8, }, Default::default(), Default::default(), Default::default(), Default::default(), Default::default(), Default::default(), Default::default(), ], }; unsafe { device.CreateBlendState(&desc, Some(&mut blend_state)) }?; blend_state.unwrap() }; let sampler = { let mut sampler = None; let desc = D3D11_SAMPLER_DESC { Filter: D3D11_FILTER_MIN_MAG_MIP_POINT, AddressU: D3D11_TEXTURE_ADDRESS_BORDER, AddressV: D3D11_TEXTURE_ADDRESS_BORDER, AddressW: D3D11_TEXTURE_ADDRESS_BORDER, MipLODBias: 0.0, MaxAnisotropy: 1, ComparisonFunc: D3D11_COMPARISON_ALWAYS, BorderColor: [0.0, 0.0, 0.0, 0.0], MinLOD: 0.0, MaxLOD: 0.0, }; unsafe { device.CreateSamplerState(&desc, Some(&mut sampler)) }?; [sampler] }; let vertex_shader = { let source = shader_resources::RawShaderBytes::new( shader_resources::ShaderModule::EmojiRasterization, shader_resources::ShaderTarget::Vertex, )?; let mut shader = None; unsafe { device.CreateVertexShader(source.as_bytes(), None, Some(&mut shader)) }?; shader.unwrap() }; let pixel_shader = { let source = shader_resources::RawShaderBytes::new( shader_resources::ShaderModule::EmojiRasterization, shader_resources::ShaderTarget::Fragment, )?; let mut shader = None; unsafe { device.CreatePixelShader(source.as_bytes(), None, Some(&mut shader)) }?; shader.unwrap() }; Ok(Self { device, device_context, sampler, blend_state, vertex_shader, pixel_shader, }) }} impl DirectWriteTextSystem { pub(crate) fn new(directx_devices: &DirectXDevices) -> Result<Self> { let components = DirectWriteComponent::new(directx_devices)?; 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(); let system_subpixel_rendering = get_system_subpixel_rendering(); 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(), system_subpixel_rendering, }))) } pub(crate) fn handle_gpu_lost(&self, directx_devices: &DirectXDevices) -> Result<()> { self.0.write().handle_gpu_lost(directx_devices) }} 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) .with_context(|| format!("Failed to 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() }) } fn recommended_rendering_mode( &self, _font_id: FontId, _font_size: Pixels, ) -> TextRenderingMode { if self.0.read().system_subpixel_rendering { TextRenderingMode::Subpixel } else { TextRenderingMode::Grayscale } }} 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 = unsafe { 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 = unsafe { collection.GetFontSet().log_err()? }; let font = unsafe { fontset .GetMatchingFonts( &HSTRING::from(family_name), font_weight.into(), DWRITE_FONT_STRETCH_NORMAL, font_style.into(), ) .log_err()? }; let total_number = unsafe { font.GetFontCount() }; for index in 0..total_number { let Some(font_face_ref) = (unsafe { font.GetFontFaceReference(index).log_err() }) else { continue; }; let Some(font_face) = (unsafe { font_face_ref.CreateFontFace().log_err() }) else { continue; }; let Some(identifier) = get_font_identifier(&font_face, &self.components.locale) else { continue; }; let Some(direct_write_features) = (unsafe { 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, }; 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 = unsafe { std::mem::zeroed() }; if unsafe { 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) -> Option<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(), ) } else { let family = self.system_ui_font_name.clone(); self.find_font_id( font_name_with_fallbacks(target_font.family.as_ref(), family.as_ref()), target_font.weight, target_font.style, &target_font.features, target_font.fallbacks.as_ref(), )Lines 1–500 of 2017. Load more
use std::{ borrow::Cow, ffi::{c_uint, c_void}, sync::Arc, }; use ::util::ResultExt; use anyhow::{Context, Result}; use collections::HashMap; use itertools::Itertools; use parking_lot::{RwLock, RwLockUpgradableReadGuard}; use windows::{ Win32::{ Foundation::*, Globalization::GetUserDefaultLocaleName, Graphics::{ Direct3D::D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP, Direct3D11::*, DirectWrite::*, Dxgi::Common::*, Gdi::LOGFONTW, }, System::SystemServices::LOCALE_NAME_MAX_LENGTH, UI::WindowsAndMessaging::*, }, core::*, }; use windows_numerics::Vector2; use crate::*; #[derive(Debug)] struct FontInfo { font_family: String, font_face: IDWriteFontFace3, features: IDWriteTypography, fallbacks: Option<IDWriteFontFallback>, is_system_font: bool, } pub(crate) struct DirectWriteTextSystem(RwLock<DirectWriteState>); struct DirectWriteComponent { locale: String, factory: IDWriteFactory5, in_memory_loader: IDWriteInMemoryFontFileLoader, builder: IDWriteFontSetBuilder1, text_renderer: Arc<TextRendererWrapper>, gpu_state: GPUState, } struct GPUState { device: ID3D11Device, device_context: ID3D11DeviceContext, sampler: [Option<ID3D11SamplerState>; 1], blend_state: ID3D11BlendState, vertex_shader: ID3D11VertexShader, pixel_shader: ID3D11PixelShader, } 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>, system_subpixel_rendering: bool, } #[derive(Debug, Clone, Hash, PartialEq, Eq)] struct FontIdentifier { postscript_name: String, weight: i32, style: i32, } impl DirectWriteComponent { pub fn new(directx_devices: &DirectXDevices) -> Result<Self> { // todo: ideally this would not be a large unsafe block but smaller isolated ones for easier auditing unsafe { let factory: IDWriteFactory5 = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED)?; // 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 gpu_state = GPUState::new(directx_devices)?; Ok(DirectWriteComponent { locale, factory, in_memory_loader, builder, text_renderer, gpu_state, }) } } } impl GPUState { fn new(directx_devices: &DirectXDevices) -> Result<Self> { let device = directx_devices.device.clone(); let device_context = directx_devices.device_context.clone(); let blend_state = { let mut blend_state = None; let desc = D3D11_BLEND_DESC { AlphaToCoverageEnable: false.into(), IndependentBlendEnable: false.into(), RenderTarget: [ D3D11_RENDER_TARGET_BLEND_DESC { BlendEnable: true.into(), SrcBlend: D3D11_BLEND_ONE, DestBlend: D3D11_BLEND_INV_SRC_ALPHA, BlendOp: D3D11_BLEND_OP_ADD, SrcBlendAlpha: D3D11_BLEND_ONE, DestBlendAlpha: D3D11_BLEND_INV_SRC_ALPHA, BlendOpAlpha: D3D11_BLEND_OP_ADD, RenderTargetWriteMask: D3D11_COLOR_WRITE_ENABLE_ALL.0 as u8, }, Default::default(), Default::default(), Default::default(), Default::default(), Default::default(), Default::default(), Default::default(), ], }; unsafe { device.CreateBlendState(&desc, Some(&mut blend_state)) }?; blend_state.unwrap() }; let sampler = { let mut sampler = None; let desc = D3D11_SAMPLER_DESC { Filter: D3D11_FILTER_MIN_MAG_MIP_POINT, AddressU: D3D11_TEXTURE_ADDRESS_BORDER, AddressV: D3D11_TEXTURE_ADDRESS_BORDER, AddressW: D3D11_TEXTURE_ADDRESS_BORDER, MipLODBias: 0.0, MaxAnisotropy: 1, ComparisonFunc: D3D11_COMPARISON_ALWAYS, BorderColor: [0.0, 0.0, 0.0, 0.0], MinLOD: 0.0, MaxLOD: 0.0, }; unsafe { device.CreateSamplerState(&desc, Some(&mut sampler)) }?; [sampler] }; let vertex_shader = { let source = shader_resources::RawShaderBytes::new( shader_resources::ShaderModule::EmojiRasterization, shader_resources::ShaderTarget::Vertex, )?; let mut shader = None; unsafe { device.CreateVertexShader(source.as_bytes(), None, Some(&mut shader)) }?; shader.unwrap() }; let pixel_shader = { let source = shader_resources::RawShaderBytes::new( shader_resources::ShaderModule::EmojiRasterization, shader_resources::ShaderTarget::Fragment, )?; let mut shader = None; unsafe { device.CreatePixelShader(source.as_bytes(), None, Some(&mut shader)) }?; shader.unwrap() }; Ok(Self { device, device_context, sampler, blend_state, vertex_shader, pixel_shader, }) } } impl DirectWriteTextSystem { pub(crate) fn new(directx_devices: &DirectXDevices) -> Result<Self> { let components = DirectWriteComponent::new(directx_devices)?; 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(); let system_subpixel_rendering = get_system_subpixel_rendering(); 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(), system_subpixel_rendering, }))) } pub(crate) fn handle_gpu_lost(&self, directx_devices: &DirectXDevices) -> Result<()> { self.0.write().handle_gpu_lost(directx_devices) } } 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) .with_context(|| format!("Failed to 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() }) } fn recommended_rendering_mode( &self, _font_id: FontId, _font_size: Pixels, ) -> TextRenderingMode { if self.0.read().system_subpixel_rendering { TextRenderingMode::Subpixel } else { TextRenderingMode::Grayscale } } } 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 = unsafe { 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 = unsafe { collection.GetFontSet().log_err()? }; let font = unsafe { fontset .GetMatchingFonts( &HSTRING::from(family_name), font_weight.into(), DWRITE_FONT_STRETCH_NORMAL, font_style.into(), ) .log_err()? }; let total_number = unsafe { font.GetFontCount() }; for index in 0..total_number { let Some(font_face_ref) = (unsafe { font.GetFontFaceReference(index).log_err() }) else { continue; }; let Some(font_face) = (unsafe { font_face_ref.CreateFontFace().log_err() }) else { continue; }; let Some(identifier) = get_font_identifier(&font_face, &self.components.locale) else { continue; }; let Some(direct_write_features) = (unsafe { 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, }; 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 = unsafe { std::mem::zeroed() }; if unsafe { 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) -> Option<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(), ) } else { let family = self.system_ui_font_name.clone(); self.find_font_id( font_name_with_fallbacks(target_font.family.as_ref(), family.as_ref()), target_font.weight, target_font.style, &target_font.features, target_font.fallbacks.as_ref(), )