1972 lines · 67.3 KB · Rust
RawDownload
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.