use std::{ borrow::Cow, ffi::{c_uint, c_void}, mem::ManuallyDrop,}; use anyhow::{Context, Result};use collections::HashMap;use gpui_util::{ResultExt, maybe};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::*;use gpui::*; #[derive(Debug)]struct FontInfo { font_family_h: HSTRING, font_face: IDWriteFontFace3, features: IDWriteTypography, fallbacks: Option<IDWriteFontFallback>, font_collection: IDWriteFontCollection1,} pub(crate) struct DirectWriteTextSystem { components: DirectWriteComponents, state: RwLock<DirectWriteState>,} struct DirectWriteComponents { locale: HSTRING, factory: IDWriteFactory5, in_memory_loader: IDWriteInMemoryFontFileLoader, builder: IDWriteFontSetBuilder1, text_renderer: TextRendererWrapper, system_ui_font_name: SharedString, system_subpixel_rendering: bool,} impl Drop for DirectWriteComponents { fn drop(&mut self) { unsafe { let _ = self .factory .UnregisterFontFileLoader(&self.in_memory_loader); } }} struct GPUState { device: ID3D11Device, device_context: ID3D11DeviceContext, sampler: Option<ID3D11SamplerState>, blend_state: ID3D11BlendState, vertex_shader: ID3D11VertexShader, pixel_shader: ID3D11PixelShader,} struct DirectWriteState { gpu_state: GPUState, system_font_collection: IDWriteFontCollection1, custom_font_collection: IDWriteFontCollection1, fonts: Vec<FontInfo>, font_to_font_id: HashMap<Font, FontId>, font_info_cache: HashMap<usize, FontId>, layout_line_scratch: Vec<u16>,} 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 factory: IDWriteFactory5 = unsafe { 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 = unsafe { factory.CreateInMemoryFontFileLoader()? }; unsafe { factory.RegisterFontFileLoader(&in_memory_loader)? }; let builder = unsafe { factory.CreateFontSetBuilder()? }; let mut locale = [0u16; LOCALE_NAME_MAX_LENGTH as usize]; unsafe { GetUserDefaultLocaleName(&mut locale) }; let locale = HSTRING::from_wide(&locale); let text_renderer = TextRendererWrapper::new(locale.clone()); let gpu_state = GPUState::new(directx_devices)?; let system_subpixel_rendering = get_system_subpixel_rendering(); let system_ui_font_name = get_system_ui_font_name(); let components = DirectWriteComponents { locale, factory, in_memory_loader, builder, text_renderer, system_ui_font_name, system_subpixel_rendering, }; let system_font_collection = unsafe { let mut result = None; components .factory .GetSystemFontCollection(false, &mut result, true)?; result.context("Failed to get system font collection")? }; let custom_font_set = unsafe { components.builder.CreateFontSet()? }; let custom_font_collection = unsafe { components .factory .CreateFontCollectionFromFontSet(&custom_font_set)? }; Ok(Self { components, state: RwLock::new(DirectWriteState { gpu_state, system_font_collection, custom_font_collection, fonts: Vec::new(), font_to_font_id: HashMap::default(), font_info_cache: HashMap::default(), layout_line_scratch: Vec::new(), }), }) } pub(crate) fn handle_gpu_lost(&self, directx_devices: &DirectXDevices) -> Result<()> { self.state.write().handle_gpu_lost(directx_devices) }} impl PlatformTextSystem for DirectWriteTextSystem { fn add_fonts(&self, fonts: Vec<Cow<'static, [u8]>>) -> Result<()> { self.state.write().add_fonts(&self.components, fonts) } fn all_font_names(&self) -> Vec<String> { self.state.read().all_font_names(&self.components) } fn font_id(&self, font: &Font) -> Result<FontId> { let lock = self.state.upgradable_read(); if let Some(font_id) = lock.font_to_font_id.get(font) { Ok(*font_id) } else { RwLockUpgradableReadGuard::upgrade(lock) .select_and_cache_font(&self.components, font) .with_context(|| format!("Failed to select font: {:?}", font)) } } fn font_metrics(&self, font_id: FontId) -> FontMetrics { self.state.read().font_metrics(font_id) } fn typographic_bounds(&self, font_id: FontId, glyph_id: GlyphId) -> Result<Bounds<f32>> { self.state.read().get_typographic_bounds(font_id, glyph_id) } fn advance(&self, font_id: FontId, glyph_id: GlyphId) -> anyhow::Result<Size<f32>> { self.state.read().get_advance(font_id, glyph_id) } fn glyph_for_char(&self, font_id: FontId, ch: char) -> Option<GlyphId> { self.state.read().glyph_for_char(font_id, ch) } fn glyph_raster_bounds( &self, params: &RenderGlyphParams, ) -> anyhow::Result<Bounds<DevicePixels>> { self.state.read().raster_bounds(&self.components, params) } fn rasterize_glyph( &self, params: &RenderGlyphParams, raster_bounds: Bounds<DevicePixels>, ) -> anyhow::Result<(Size<DevicePixels>, Vec<u8>)> { self.state .read() .rasterize_glyph(&self.components, params, raster_bounds) } fn layout_line(&self, text: &str, font_size: Pixels, runs: &[FontRun]) -> LineLayout { self.state .write() .layout_line(&self.components, 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.components.system_subpixel_rendering { TextRenderingMode::Subpixel } else { TextRenderingMode::Grayscale } }} impl DirectWriteState { fn select_and_cache_font( &mut self, components: &DirectWriteComponents, font: &Font, ) -> Option<FontId> { let select_font = |this: &mut DirectWriteState, font: &Font| -> Option<FontId> { let info = [&this.custom_font_collection, &this.system_font_collection] .into_iter() .find_map(|font_collection| unsafe { DirectWriteState::make_font_from_font_collection( font, font_collection, &components.factory, &this.system_font_collection, &components.system_ui_font_name, ) })?; let font_id = FontId(this.fonts.len()); let font_face_key = info.font_face.cast::<IUnknown>().unwrap().as_raw().addr(); this.fonts.push(info); this.font_info_cache.insert(font_face_key, font_id); Some(font_id) }; let mut font_id = select_font(self, font); if font_id.is_none() { // try updating system fonts and reselect let mut collection = None; let font_collection_updated = unsafe { components .factory .GetSystemFontCollection(false, &mut collection, true) } .log_err() .is_some(); if font_collection_updated && let Some(collection) = collection { self.system_font_collection = collection; } font_id = select_font(self, font); }; let font_id = font_id?; self.font_to_font_id.insert(font.clone(), font_id); Some(font_id) } fn add_fonts( &mut self, components: &DirectWriteComponents, fonts: Vec<Cow<'static, [u8]>>, ) -> Result<()> { for font_data in fonts { match font_data { Cow::Borrowed(data) => unsafe { let font_file = components .in_memory_loader .CreateInMemoryFontFileReference( &components.factory, data.as_ptr().cast(), data.len() as _, None, )?; components.builder.AddFontFile(&font_file)?; }, Cow::Owned(data) => unsafe { let font_file = components .in_memory_loader .CreateInMemoryFontFileReference( &components.factory, data.as_ptr().cast(), data.len() as _, None, )?; components.builder.AddFontFile(&font_file)?; }, } } let set = unsafe { components.builder.CreateFontSet()? }; let collection = unsafe { components.factory.CreateFontCollectionFromFontSet(&set)? }; self.custom_font_collection = collection; Ok(()) } fn generate_font_fallbacks( fallbacks: &FontFallbacks, factory: &IDWriteFactory5, system_font_collection: &IDWriteFontCollection1, ) -> Result<Option<IDWriteFontFallback>> { let fallback_list = fallbacks.fallback_list(); if fallback_list.is_empty() { return Ok(None); } unsafe { let builder = factory.CreateFontFallbackBuilder()?; let font_set = &system_font_collection.GetFontSet()?; let mut unicode_ranges = Vec::new(); for family_name in fallback_list { let family_name = HSTRING::from(family_name); let Some(fonts) = font_set .GetMatchingFonts( &family_name, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, ) .log_err() else { continue; }; let Ok(font_face) = fonts.GetFontFaceReference(0) else { continue; }; let font = font_face.CreateFontFace()?; let mut count = 0; font.GetUnicodeRanges(None, &mut count).ok(); if count == 0 { continue; } unicode_ranges.clear(); unicode_ranges.resize_with(count as usize, DWRITE_UNICODE_RANGE::default); let Some(_) = font .GetUnicodeRanges(Some(&mut unicode_ranges), &mut count) .log_err() else { continue; }; builder.AddMapping( &unicode_ranges, &[family_name.as_ptr()], None, None, None, 1.0, )?; } let system_fallbacks = factory.GetSystemFontFallback()?; builder.AddMappings(&system_fallbacks)?; Ok(Some(builder.CreateFontFallback()?)) } } unsafe fn generate_font_features( factory: &IDWriteFactory5, font_features: &FontFeatures, ) -> Result<IDWriteTypography> { let direct_write_features = unsafe { factory.CreateTypography()? }; apply_font_features(&direct_write_features, font_features)?; Ok(direct_write_features) } unsafe fn make_font_from_font_collection( &Font { ref family, ref features, ref fallbacks, weight, style, }: &Font, collection: &IDWriteFontCollection1, factory: &IDWriteFactory5, system_font_collection: &IDWriteFontCollection1, system_ui_font_name: &SharedString, ) -> Option<FontInfo> { const SYSTEM_UI_FONT_NAME: &str = ".SystemUIFont"; let family = if family == SYSTEM_UI_FONT_NAME { system_ui_font_name } else { gpui::font_name_with_fallbacks_shared(&family, &system_ui_font_name) }; let fontset = unsafe { collection.GetFontSet().log_err()? }; let font_family_h = HSTRING::from(family.as_str()); let font = unsafe { fontset .GetMatchingFonts( &font_family_h, font_weight_to_dwrite(weight), DWRITE_FONT_STRETCH_NORMAL, font_style_to_dwrite(style), ) .log_err()? }; let total_number = unsafe { font.GetFontCount() }; for index in 0..total_number { let res = maybe!({ let font_face_ref = unsafe { font.GetFontFaceReference(index).log_err()? }; let font_face = unsafe { font_face_ref.CreateFontFace().log_err()? }; let direct_write_features = unsafe { Self::generate_font_features(factory, features).log_err()? }; let fallbacks = fallbacks.as_ref().and_then(|fallbacks| { Self::generate_font_fallbacks(fallbacks, factory, system_font_collection) .log_err() .flatten() }); let font_info = FontInfo { font_family_h: font_family_h.clone(), font_face,Lines 1–500 of 1972. Load more
use std::{ borrow::Cow, ffi::{c_uint, c_void}, mem::ManuallyDrop, }; use anyhow::{Context, Result}; use collections::HashMap; use gpui_util::{ResultExt, maybe}; 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::*; use gpui::*; #[derive(Debug)] struct FontInfo { font_family_h: HSTRING, font_face: IDWriteFontFace3, features: IDWriteTypography, fallbacks: Option<IDWriteFontFallback>, font_collection: IDWriteFontCollection1, } pub(crate) struct DirectWriteTextSystem { components: DirectWriteComponents, state: RwLock<DirectWriteState>, } struct DirectWriteComponents { locale: HSTRING, factory: IDWriteFactory5, in_memory_loader: IDWriteInMemoryFontFileLoader, builder: IDWriteFontSetBuilder1, text_renderer: TextRendererWrapper, system_ui_font_name: SharedString, system_subpixel_rendering: bool, } impl Drop for DirectWriteComponents { fn drop(&mut self) { unsafe { let _ = self .factory .UnregisterFontFileLoader(&self.in_memory_loader); } } } struct GPUState { device: ID3D11Device, device_context: ID3D11DeviceContext, sampler: Option<ID3D11SamplerState>, blend_state: ID3D11BlendState, vertex_shader: ID3D11VertexShader, pixel_shader: ID3D11PixelShader, } struct DirectWriteState { gpu_state: GPUState, system_font_collection: IDWriteFontCollection1, custom_font_collection: IDWriteFontCollection1, fonts: Vec<FontInfo>, font_to_font_id: HashMap<Font, FontId>, font_info_cache: HashMap<usize, FontId>, layout_line_scratch: Vec<u16>, } 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 factory: IDWriteFactory5 = unsafe { 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 = unsafe { factory.CreateInMemoryFontFileLoader()? }; unsafe { factory.RegisterFontFileLoader(&in_memory_loader)? }; let builder = unsafe { factory.CreateFontSetBuilder()? }; let mut locale = [0u16; LOCALE_NAME_MAX_LENGTH as usize]; unsafe { GetUserDefaultLocaleName(&mut locale) }; let locale = HSTRING::from_wide(&locale); let text_renderer = TextRendererWrapper::new(locale.clone()); let gpu_state = GPUState::new(directx_devices)?; let system_subpixel_rendering = get_system_subpixel_rendering(); let system_ui_font_name = get_system_ui_font_name(); let components = DirectWriteComponents { locale, factory, in_memory_loader, builder, text_renderer, system_ui_font_name, system_subpixel_rendering, }; let system_font_collection = unsafe { let mut result = None; components .factory .GetSystemFontCollection(false, &mut result, true)?; result.context("Failed to get system font collection")? }; let custom_font_set = unsafe { components.builder.CreateFontSet()? }; let custom_font_collection = unsafe { components .factory .CreateFontCollectionFromFontSet(&custom_font_set)? }; Ok(Self { components, state: RwLock::new(DirectWriteState { gpu_state, system_font_collection, custom_font_collection, fonts: Vec::new(), font_to_font_id: HashMap::default(), font_info_cache: HashMap::default(), layout_line_scratch: Vec::new(), }), }) } pub(crate) fn handle_gpu_lost(&self, directx_devices: &DirectXDevices) -> Result<()> { self.state.write().handle_gpu_lost(directx_devices) } } impl PlatformTextSystem for DirectWriteTextSystem { fn add_fonts(&self, fonts: Vec<Cow<'static, [u8]>>) -> Result<()> { self.state.write().add_fonts(&self.components, fonts) } fn all_font_names(&self) -> Vec<String> { self.state.read().all_font_names(&self.components) } fn font_id(&self, font: &Font) -> Result<FontId> { let lock = self.state.upgradable_read(); if let Some(font_id) = lock.font_to_font_id.get(font) { Ok(*font_id) } else { RwLockUpgradableReadGuard::upgrade(lock) .select_and_cache_font(&self.components, font) .with_context(|| format!("Failed to select font: {:?}", font)) } } fn font_metrics(&self, font_id: FontId) -> FontMetrics { self.state.read().font_metrics(font_id) } fn typographic_bounds(&self, font_id: FontId, glyph_id: GlyphId) -> Result<Bounds<f32>> { self.state.read().get_typographic_bounds(font_id, glyph_id) } fn advance(&self, font_id: FontId, glyph_id: GlyphId) -> anyhow::Result<Size<f32>> { self.state.read().get_advance(font_id, glyph_id) } fn glyph_for_char(&self, font_id: FontId, ch: char) -> Option<GlyphId> { self.state.read().glyph_for_char(font_id, ch) } fn glyph_raster_bounds( &self, params: &RenderGlyphParams, ) -> anyhow::Result<Bounds<DevicePixels>> { self.state.read().raster_bounds(&self.components, params) } fn rasterize_glyph( &self, params: &RenderGlyphParams, raster_bounds: Bounds<DevicePixels>, ) -> anyhow::Result<(Size<DevicePixels>, Vec<u8>)> { self.state .read() .rasterize_glyph(&self.components, params, raster_bounds) } fn layout_line(&self, text: &str, font_size: Pixels, runs: &[FontRun]) -> LineLayout { self.state .write() .layout_line(&self.components, 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.components.system_subpixel_rendering { TextRenderingMode::Subpixel } else { TextRenderingMode::Grayscale } } } impl DirectWriteState { fn select_and_cache_font( &mut self, components: &DirectWriteComponents, font: &Font, ) -> Option<FontId> { let select_font = |this: &mut DirectWriteState, font: &Font| -> Option<FontId> { let info = [&this.custom_font_collection, &this.system_font_collection] .into_iter() .find_map(|font_collection| unsafe { DirectWriteState::make_font_from_font_collection( font, font_collection, &components.factory, &this.system_font_collection, &components.system_ui_font_name, ) })?; let font_id = FontId(this.fonts.len()); let font_face_key = info.font_face.cast::<IUnknown>().unwrap().as_raw().addr(); this.fonts.push(info); this.font_info_cache.insert(font_face_key, font_id); Some(font_id) }; let mut font_id = select_font(self, font); if font_id.is_none() { // try updating system fonts and reselect let mut collection = None; let font_collection_updated = unsafe { components .factory .GetSystemFontCollection(false, &mut collection, true) } .log_err() .is_some(); if font_collection_updated && let Some(collection) = collection { self.system_font_collection = collection; } font_id = select_font(self, font); }; let font_id = font_id?; self.font_to_font_id.insert(font.clone(), font_id); Some(font_id) } fn add_fonts( &mut self, components: &DirectWriteComponents, fonts: Vec<Cow<'static, [u8]>>, ) -> Result<()> { for font_data in fonts { match font_data { Cow::Borrowed(data) => unsafe { let font_file = components .in_memory_loader .CreateInMemoryFontFileReference( &components.factory, data.as_ptr().cast(), data.len() as _, None, )?; components.builder.AddFontFile(&font_file)?; }, Cow::Owned(data) => unsafe { let font_file = components .in_memory_loader .CreateInMemoryFontFileReference( &components.factory, data.as_ptr().cast(), data.len() as _, None, )?; components.builder.AddFontFile(&font_file)?; }, } } let set = unsafe { components.builder.CreateFontSet()? }; let collection = unsafe { components.factory.CreateFontCollectionFromFontSet(&set)? }; self.custom_font_collection = collection; Ok(()) } fn generate_font_fallbacks( fallbacks: &FontFallbacks, factory: &IDWriteFactory5, system_font_collection: &IDWriteFontCollection1, ) -> Result<Option<IDWriteFontFallback>> { let fallback_list = fallbacks.fallback_list(); if fallback_list.is_empty() { return Ok(None); } unsafe { let builder = factory.CreateFontFallbackBuilder()?; let font_set = &system_font_collection.GetFontSet()?; let mut unicode_ranges = Vec::new(); for family_name in fallback_list { let family_name = HSTRING::from(family_name); let Some(fonts) = font_set .GetMatchingFonts( &family_name, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, ) .log_err() else { continue; }; let Ok(font_face) = fonts.GetFontFaceReference(0) else { continue; }; let font = font_face.CreateFontFace()?; let mut count = 0; font.GetUnicodeRanges(None, &mut count).ok(); if count == 0 { continue; } unicode_ranges.clear(); unicode_ranges.resize_with(count as usize, DWRITE_UNICODE_RANGE::default); let Some(_) = font .GetUnicodeRanges(Some(&mut unicode_ranges), &mut count) .log_err() else { continue; }; builder.AddMapping( &unicode_ranges, &[family_name.as_ptr()], None, None, None, 1.0, )?; } let system_fallbacks = factory.GetSystemFontFallback()?; builder.AddMappings(&system_fallbacks)?; Ok(Some(builder.CreateFontFallback()?)) } } unsafe fn generate_font_features( factory: &IDWriteFactory5, font_features: &FontFeatures, ) -> Result<IDWriteTypography> { let direct_write_features = unsafe { factory.CreateTypography()? }; apply_font_features(&direct_write_features, font_features)?; Ok(direct_write_features) } unsafe fn make_font_from_font_collection( &Font { ref family, ref features, ref fallbacks, weight, style, }: &Font, collection: &IDWriteFontCollection1, factory: &IDWriteFactory5, system_font_collection: &IDWriteFontCollection1, system_ui_font_name: &SharedString, ) -> Option<FontInfo> { const SYSTEM_UI_FONT_NAME: &str = ".SystemUIFont"; let family = if family == SYSTEM_UI_FONT_NAME { system_ui_font_name } else { gpui::font_name_with_fallbacks_shared(&family, &system_ui_font_name) }; let fontset = unsafe { collection.GetFontSet().log_err()? }; let font_family_h = HSTRING::from(family.as_str()); let font = unsafe { fontset .GetMatchingFonts( &font_family_h, font_weight_to_dwrite(weight), DWRITE_FONT_STRETCH_NORMAL, font_style_to_dwrite(style), ) .log_err()? }; let total_number = unsafe { font.GetFontCount() }; for index in 0..total_number { let res = maybe!({ let font_face_ref = unsafe { font.GetFontFaceReference(index).log_err()? }; let font_face = unsafe { font_face_ref.CreateFontFace().log_err()? }; let direct_write_features = unsafe { Self::generate_font_features(factory, features).log_err()? }; let fallbacks = fallbacks.as_ref().and_then(|fallbacks| { Self::generate_font_fallbacks(fallbacks, factory, system_font_collection) .log_err() .flatten() }); let font_info = FontInfo { font_family_h: font_family_h.clone(), font_face,