Skip to repository content

tenant.openagents/omega

No repository description is available.

OpenAgents Git authority 2026-07-28T01:50:16.259Z Public web read
NIP-34 coordinate30617:7649603503856e5148d571eac2766b288a8ff1e9e35d380337a1d2b0015b4f92:omega
MaintainersHidden in public view
References2 branches · 1 tag
Read-only clonegit clone https://openagents.com/git/tenant.openagents/omega.git
Browse files

direct_write.rs

1973 lines · 68.9 KB · rust
1use std::{
2    borrow::Cow,
3    ffi::{c_uint, c_void},
4    mem::ManuallyDrop,
5};
6
7use anyhow::{Context, Result};
8use collections::HashMap;
9use gpui_util::{ResultExt, maybe};
10use parking_lot::{RwLock, RwLockUpgradableReadGuard};
11use windows::{
12    Win32::{
13        Foundation::*,
14        Globalization::GetUserDefaultLocaleName,
15        Graphics::{
16            Direct3D::D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP, Direct3D11::*, DirectWrite::*,
17            Dxgi::Common::*, Gdi::LOGFONTW,
18        },
19        System::SystemServices::LOCALE_NAME_MAX_LENGTH,
20        UI::WindowsAndMessaging::*,
21    },
22    core::*,
23};
24use windows_numerics::Vector2;
25
26use crate::*;
27use gpui::*;
28
29#[derive(Debug)]
30struct FontInfo {
31    font_family_h: HSTRING,
32    font_face: IDWriteFontFace3,
33    features: IDWriteTypography,
34    fallbacks: Option<IDWriteFontFallback>,
35    font_collection: IDWriteFontCollection1,
36}
37
38pub(crate) struct DirectWriteTextSystem {
39    components: DirectWriteComponents,
40    state: RwLock<DirectWriteState>,
41}
42
43struct DirectWriteComponents {
44    locale: HSTRING,
45    factory: IDWriteFactory5,
46    in_memory_loader: IDWriteInMemoryFontFileLoader,
47    builder: IDWriteFontSetBuilder1,
48    text_renderer: TextRendererWrapper,
49    system_ui_font_name: SharedString,
50    system_subpixel_rendering: bool,
51}
52
53impl Drop for DirectWriteComponents {
54    fn drop(&mut self) {
55        unsafe {
56            let _ = self
57                .factory
58                .UnregisterFontFileLoader(&self.in_memory_loader);
59        }
60    }
61}
62
63struct GPUState {
64    device: ID3D11Device,
65    device_context: ID3D11DeviceContext,
66    sampler: Option<ID3D11SamplerState>,
67    blend_state: ID3D11BlendState,
68    vertex_shader: ID3D11VertexShader,
69    pixel_shader: ID3D11PixelShader,
70}
71
72struct DirectWriteState {
73    gpu_state: GPUState,
74    system_font_collection: IDWriteFontCollection1,
75    custom_font_collection: IDWriteFontCollection1,
76    fonts: Vec<FontInfo>,
77    font_to_font_id: HashMap<Font, FontId>,
78    font_info_cache: HashMap<usize, FontId>,
79    layout_line_scratch: Vec<u16>,
80}
81
82impl GPUState {
83    fn new(directx_devices: &DirectXDevices) -> Result<Self> {
84        let device = directx_devices.device.clone();
85        let device_context = directx_devices.device_context.clone();
86
87        let blend_state = {
88            let mut blend_state = None;
89            let desc = D3D11_BLEND_DESC {
90                AlphaToCoverageEnable: false.into(),
91                IndependentBlendEnable: false.into(),
92                RenderTarget: [
93                    D3D11_RENDER_TARGET_BLEND_DESC {
94                        BlendEnable: true.into(),
95                        SrcBlend: D3D11_BLEND_ONE,
96                        DestBlend: D3D11_BLEND_INV_SRC_ALPHA,
97                        BlendOp: D3D11_BLEND_OP_ADD,
98                        SrcBlendAlpha: D3D11_BLEND_ONE,
99                        DestBlendAlpha: D3D11_BLEND_INV_SRC_ALPHA,
100                        BlendOpAlpha: D3D11_BLEND_OP_ADD,
101                        RenderTargetWriteMask: D3D11_COLOR_WRITE_ENABLE_ALL.0 as u8,
102                    },
103                    Default::default(),
104                    Default::default(),
105                    Default::default(),
106                    Default::default(),
107                    Default::default(),
108                    Default::default(),
109                    Default::default(),
110                ],
111            };
112            unsafe { device.CreateBlendState(&desc, Some(&mut blend_state)) }?;
113            blend_state.unwrap()
114        };
115
116        let sampler = {
117            let mut sampler = None;
118            let desc = D3D11_SAMPLER_DESC {
119                Filter: D3D11_FILTER_MIN_MAG_MIP_POINT,
120                AddressU: D3D11_TEXTURE_ADDRESS_BORDER,
121                AddressV: D3D11_TEXTURE_ADDRESS_BORDER,
122                AddressW: D3D11_TEXTURE_ADDRESS_BORDER,
123                MipLODBias: 0.0,
124                MaxAnisotropy: 1,
125                ComparisonFunc: D3D11_COMPARISON_ALWAYS,
126                BorderColor: [0.0, 0.0, 0.0, 0.0],
127                MinLOD: 0.0,
128                MaxLOD: 0.0,
129            };
130            unsafe { device.CreateSamplerState(&desc, Some(&mut sampler)) }?;
131            sampler
132        };
133
134        let vertex_shader = {
135            let source = shader_resources::RawShaderBytes::new(
136                shader_resources::ShaderModule::EmojiRasterization,
137                shader_resources::ShaderTarget::Vertex,
138            )?;
139            let mut shader = None;
140            unsafe { device.CreateVertexShader(source.as_bytes(), None, Some(&mut shader)) }?;
141            shader.unwrap()
142        };
143
144        let pixel_shader = {
145            let source = shader_resources::RawShaderBytes::new(
146                shader_resources::ShaderModule::EmojiRasterization,
147                shader_resources::ShaderTarget::Fragment,
148            )?;
149            let mut shader = None;
150            unsafe { device.CreatePixelShader(source.as_bytes(), None, Some(&mut shader)) }?;
151            shader.unwrap()
152        };
153
154        Ok(Self {
155            device,
156            device_context,
157            sampler,
158            blend_state,
159            vertex_shader,
160            pixel_shader,
161        })
162    }
163}
164
165impl DirectWriteTextSystem {
166    pub(crate) fn new(directx_devices: &DirectXDevices) -> Result<Self> {
167        let factory: IDWriteFactory5 = unsafe { DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED)? };
168        // The `IDWriteInMemoryFontFileLoader` here is supported starting from
169        // Windows 10 Creators Update, which consequently requires the entire
170        // `DirectWriteTextSystem` to run on `win10 1703`+.
171        let in_memory_loader = unsafe { factory.CreateInMemoryFontFileLoader()? };
172        unsafe { factory.RegisterFontFileLoader(&in_memory_loader)? };
173        let builder = unsafe { factory.CreateFontSetBuilder()? };
174        let mut locale = [0u16; LOCALE_NAME_MAX_LENGTH as usize];
175        unsafe { GetUserDefaultLocaleName(&mut locale) };
176        let locale = HSTRING::from_wide(&locale);
177        let text_renderer = TextRendererWrapper::new(locale.clone());
178
179        let gpu_state = GPUState::new(directx_devices)?;
180
181        let system_subpixel_rendering = get_system_subpixel_rendering();
182        let system_ui_font_name = get_system_ui_font_name();
183        let components = DirectWriteComponents {
184            locale,
185            factory,
186            in_memory_loader,
187            builder,
188            text_renderer,
189            system_ui_font_name,
190            system_subpixel_rendering,
191        };
192
193        let system_font_collection = unsafe {
194            let mut result = None;
195            components
196                .factory
197                .GetSystemFontCollection(false, &mut result, true)?;
198            result.context("Failed to get system font collection")?
199        };
200        let custom_font_set = unsafe { components.builder.CreateFontSet()? };
201        let custom_font_collection = unsafe {
202            components
203                .factory
204                .CreateFontCollectionFromFontSet(&custom_font_set)?
205        };
206
207        Ok(Self {
208            components,
209            state: RwLock::new(DirectWriteState {
210                gpu_state,
211                system_font_collection,
212                custom_font_collection,
213                fonts: Vec::new(),
214                font_to_font_id: HashMap::default(),
215                font_info_cache: HashMap::default(),
216                layout_line_scratch: Vec::new(),
217            }),
218        })
219    }
220
221    pub(crate) fn handle_gpu_lost(&self, directx_devices: &DirectXDevices) -> Result<()> {
222        self.state.write().handle_gpu_lost(directx_devices)
223    }
224}
225
226impl PlatformTextSystem for DirectWriteTextSystem {
227    fn add_fonts(&self, fonts: Vec<Cow<'static, [u8]>>) -> Result<()> {
228        self.state.write().add_fonts(&self.components, fonts)
229    }
230
231    fn all_font_names(&self) -> Vec<String> {
232        self.state.read().all_font_names(&self.components)
233    }
234
235    fn font_id(&self, font: &Font) -> Result<FontId> {
236        let lock = self.state.upgradable_read();
237        if let Some(font_id) = lock.font_to_font_id.get(font) {
238            Ok(*font_id)
239        } else {
240            RwLockUpgradableReadGuard::upgrade(lock)
241                .select_and_cache_font(&self.components, font)
242                .with_context(|| format!("Failed to select font: {:?}", font))
243        }
244    }
245
246    fn font_metrics(&self, font_id: FontId) -> FontMetrics {
247        self.state.read().font_metrics(font_id)
248    }
249
250    fn typographic_bounds(&self, font_id: FontId, glyph_id: GlyphId) -> Result<Bounds<f32>> {
251        self.state.read().get_typographic_bounds(font_id, glyph_id)
252    }
253
254    fn advance(&self, font_id: FontId, glyph_id: GlyphId) -> anyhow::Result<Size<f32>> {
255        self.state.read().get_advance(font_id, glyph_id)
256    }
257
258    fn glyph_for_char(&self, font_id: FontId, ch: char) -> Option<GlyphId> {
259        self.state.read().glyph_for_char(font_id, ch)
260    }
261
262    fn glyph_raster_bounds(
263        &self,
264        params: &RenderGlyphParams,
265    ) -> anyhow::Result<Bounds<DevicePixels>> {
266        self.state.read().raster_bounds(&self.components, params)
267    }
268
269    fn rasterize_glyph(
270        &self,
271        params: &RenderGlyphParams,
272        raster_bounds: Bounds<DevicePixels>,
273    ) -> anyhow::Result<(Size<DevicePixels>, Vec<u8>)> {
274        self.state
275            .read()
276            .rasterize_glyph(&self.components, params, raster_bounds)
277    }
278
279    fn layout_line(&self, text: &str, font_size: Pixels, runs: &[FontRun]) -> LineLayout {
280        self.state
281            .write()
282            .layout_line(&self.components, text, font_size, runs)
283            .log_err()
284            .unwrap_or(LineLayout {
285                font_size,
286                ..Default::default()
287            })
288    }
289
290    fn recommended_rendering_mode(
291        &self,
292        _font_id: FontId,
293        _font_size: Pixels,
294    ) -> TextRenderingMode {
295        if self.components.system_subpixel_rendering {
296            TextRenderingMode::Subpixel
297        } else {
298            TextRenderingMode::Grayscale
299        }
300    }
301}
302
303impl DirectWriteState {
304    fn select_and_cache_font(
305        &mut self,
306        components: &DirectWriteComponents,
307        font: &Font,
308    ) -> Option<FontId> {
309        let select_font = |this: &mut DirectWriteState, font: &Font| -> Option<FontId> {
310            let info = [&this.custom_font_collection, &this.system_font_collection]
311                .into_iter()
312                .find_map(|font_collection| unsafe {
313                    DirectWriteState::make_font_from_font_collection(
314                        font,
315                        font_collection,
316                        &components.factory,
317                        &this.system_font_collection,
318                        &components.system_ui_font_name,
319                    )
320                })?;
321
322            let font_id = FontId(this.fonts.len());
323            let font_face_key = info.font_face.cast::<IUnknown>().unwrap().as_raw().addr();
324            this.fonts.push(info);
325            this.font_info_cache.insert(font_face_key, font_id);
326            Some(font_id)
327        };
328
329        let mut font_id = select_font(self, font);
330        if font_id.is_none() {
331            // try updating system fonts and reselect
332            let mut collection = None;
333            let font_collection_updated = unsafe {
334                components
335                    .factory
336                    .GetSystemFontCollection(false, &mut collection, true)
337            }
338            .log_err()
339            .is_some();
340            if font_collection_updated && let Some(collection) = collection {
341                self.system_font_collection = collection;
342            }
343            font_id = select_font(self, font);
344        };
345        let font_id = font_id?;
346        self.font_to_font_id.insert(font.clone(), font_id);
347        Some(font_id)
348    }
349
350    fn add_fonts(
351        &mut self,
352        components: &DirectWriteComponents,
353        fonts: Vec<Cow<'static, [u8]>>,
354    ) -> Result<()> {
355        for font_data in fonts {
356            match font_data {
357                Cow::Borrowed(data) => unsafe {
358                    let font_file = components
359                        .in_memory_loader
360                        .CreateInMemoryFontFileReference(
361                            &components.factory,
362                            data.as_ptr().cast(),
363                            data.len() as _,
364                            None,
365                        )?;
366                    components.builder.AddFontFile(&font_file)?;
367                },
368                Cow::Owned(data) => unsafe {
369                    let font_file = components
370                        .in_memory_loader
371                        .CreateInMemoryFontFileReference(
372                            &components.factory,
373                            data.as_ptr().cast(),
374                            data.len() as _,
375                            None,
376                        )?;
377                    components.builder.AddFontFile(&font_file)?;
378                },
379            }
380        }
381        let set = unsafe { components.builder.CreateFontSet()? };
382        let collection = unsafe { components.factory.CreateFontCollectionFromFontSet(&set)? };
383        self.custom_font_collection = collection;
384
385        Ok(())
386    }
387
388    fn generate_font_fallbacks(
389        fallbacks: &FontFallbacks,
390        factory: &IDWriteFactory5,
391        system_font_collection: &IDWriteFontCollection1,
392    ) -> Result<Option<IDWriteFontFallback>> {
393        let fallback_list = fallbacks.fallback_list();
394        if fallback_list.is_empty() {
395            return Ok(None);
396        }
397        unsafe {
398            let builder = factory.CreateFontFallbackBuilder()?;
399            let font_set = &system_font_collection.GetFontSet()?;
400            let mut unicode_ranges = Vec::new();
401            for family_name in fallback_list {
402                let family_name = HSTRING::from(family_name);
403                let Some(fonts) = font_set
404                    .GetMatchingFonts(
405                        &family_name,
406                        DWRITE_FONT_WEIGHT_NORMAL,
407                        DWRITE_FONT_STRETCH_NORMAL,
408                        DWRITE_FONT_STYLE_NORMAL,
409                    )
410                    .log_err()
411                else {
412                    continue;
413                };
414                let Ok(font_face) = fonts.GetFontFaceReference(0) else {
415                    continue;
416                };
417                let font = font_face.CreateFontFace()?;
418                let mut count = 0;
419                font.GetUnicodeRanges(None, &mut count).ok();
420                if count == 0 {
421                    continue;
422                }
423                unicode_ranges.clear();
424                unicode_ranges.resize_with(count as usize, DWRITE_UNICODE_RANGE::default);
425                let Some(_) = font
426                    .GetUnicodeRanges(Some(&mut unicode_ranges), &mut count)
427                    .log_err()
428                else {
429                    continue;
430                };
431                builder.AddMapping(
432                    &unicode_ranges,
433                    &[family_name.as_ptr()],
434                    None,
435                    None,
436                    None,
437                    1.0,
438                )?;
439            }
440            let system_fallbacks = factory.GetSystemFontFallback()?;
441            builder.AddMappings(&system_fallbacks)?;
442            Ok(Some(builder.CreateFontFallback()?))
443        }
444    }
445
446    unsafe fn generate_font_features(
447        factory: &IDWriteFactory5,
448        font_features: &FontFeatures,
449    ) -> Result<IDWriteTypography> {
450        let direct_write_features = unsafe { factory.CreateTypography()? };
451        apply_font_features(&direct_write_features, font_features)?;
452        Ok(direct_write_features)
453    }
454
455    unsafe fn make_font_from_font_collection(
456        &Font {
457            ref family,
458            ref features,
459            ref fallbacks,
460            weight,
461            style,
462        }: &Font,
463        collection: &IDWriteFontCollection1,
464        factory: &IDWriteFactory5,
465        system_font_collection: &IDWriteFontCollection1,
466        system_ui_font_name: &SharedString,
467    ) -> Option<FontInfo> {
468        const SYSTEM_UI_FONT_NAME: &str = ".SystemUIFont";
469        let family = if family == SYSTEM_UI_FONT_NAME {
470            system_ui_font_name
471        } else {
472            gpui::font_name_with_fallbacks_shared(&family, &system_ui_font_name)
473        };
474        let fontset = unsafe { collection.GetFontSet().log_err()? };
475        let font_family_h = HSTRING::from(family.as_str());
476        let font = unsafe {
477            fontset
478                .GetMatchingFonts(
479                    &font_family_h,
480                    font_weight_to_dwrite(weight),
481                    DWRITE_FONT_STRETCH_NORMAL,
482                    font_style_to_dwrite(style),
483                )
484                .log_err()?
485        };
486        let total_number = unsafe { font.GetFontCount() };
487        for index in 0..total_number {
488            let res = maybe!({
489                let font_face_ref = unsafe { font.GetFontFaceReference(index).log_err()? };
490                let font_face = unsafe { font_face_ref.CreateFontFace().log_err()? };
491                let direct_write_features =
492                    unsafe { Self::generate_font_features(factory, features).log_err()? };
493                let fallbacks = fallbacks.as_ref().and_then(|fallbacks| {
494                    Self::generate_font_fallbacks(fallbacks, factory, system_font_collection)
495                        .log_err()
496                        .flatten()
497                });
498                let font_info = FontInfo {
499                    font_family_h: font_family_h.clone(),
500                    font_face,
501                    features: direct_write_features,
502                    fallbacks,
503                    font_collection: collection.clone(),
504                };
505                Some(font_info)
506            });
507            if res.is_some() {
508                return res;
509            }
510        }
511        None
512    }
513
514    fn layout_line(
515        &mut self,
516        components: &DirectWriteComponents,
517        text: &str,
518        font_size: Pixels,
519        font_runs: &[FontRun],
520    ) -> Result<LineLayout> {
521        if font_runs.is_empty() {
522            return Ok(LineLayout {
523                font_size,
524                ..Default::default()
525            });
526        }
527        unsafe {
528            self.layout_line_scratch.clear();
529            self.layout_line_scratch.extend(text.encode_utf16());
530            let text_wide = &*self.layout_line_scratch;
531
532            let mut utf8_offset = 0usize;
533            let mut utf16_offset = 0u32;
534            let text_layout = {
535                let first_run = &font_runs[0];
536                let font_info = &self.fonts[first_run.font_id.0];
537                let collection = &font_info.font_collection;
538                let format: IDWriteTextFormat1 = components
539                    .factory
540                    .CreateTextFormat(
541                        &font_info.font_family_h,
542                        collection,
543                        font_info.font_face.GetWeight(),
544                        font_info.font_face.GetStyle(),
545                        DWRITE_FONT_STRETCH_NORMAL,
546                        font_size.as_f32(),
547                        &components.locale,
548                    )?
549                    .cast()?;
550                if let Some(ref fallbacks) = font_info.fallbacks {
551                    format.SetFontFallback(fallbacks)?;
552                }
553
554                let layout = components.factory.CreateTextLayout(
555                    text_wide,
556                    &format,
557                    f32::INFINITY,
558                    f32::INFINITY,
559                )?;
560                let current_text = &text[utf8_offset..(utf8_offset + first_run.len)];
561                utf8_offset += first_run.len;
562                let current_text_utf16_length = current_text.encode_utf16().count() as u32;
563                let text_range = DWRITE_TEXT_RANGE {
564                    startPosition: utf16_offset,
565                    length: current_text_utf16_length,
566                };
567                layout.SetTypography(&font_info.features, text_range)?;
568                utf16_offset += current_text_utf16_length;
569
570                layout
571            };
572
573            let (ascent, descent) = {
574                let mut first_metrics = [DWRITE_LINE_METRICS::default(); 4];
575                let mut line_count = 0u32;
576                text_layout.GetLineMetrics(Some(&mut first_metrics), &mut line_count)?;
577                (
578                    px(first_metrics[0].baseline),
579                    px(first_metrics[0].height - first_metrics[0].baseline),
580                )
581            };
582            let mut break_ligatures = true;
583            for run in &font_runs[1..] {
584                let font_info = &self.fonts[run.font_id.0];
585                let current_text = &text[utf8_offset..(utf8_offset + run.len)];
586                utf8_offset += run.len;
587                let current_text_utf16_length = current_text.encode_utf16().count() as u32;
588
589                let collection = &font_info.font_collection;
590                let text_range = DWRITE_TEXT_RANGE {
591                    startPosition: utf16_offset,
592                    length: current_text_utf16_length,
593                };
594                utf16_offset += current_text_utf16_length;
595                text_layout.SetFontCollection(collection, text_range)?;
596                text_layout.SetFontFamilyName(&font_info.font_family_h, text_range)?;
597                let font_size = if break_ligatures {
598                    font_size.as_f32().next_up()
599                } else {
600                    font_size.as_f32()
601                };
602                text_layout.SetFontSize(font_size, text_range)?;
603                text_layout.SetFontStyle(font_info.font_face.GetStyle(), text_range)?;
604                text_layout.SetFontWeight(font_info.font_face.GetWeight(), text_range)?;
605                text_layout.SetTypography(&font_info.features, text_range)?;
606
607                break_ligatures = !break_ligatures;
608            }
609
610            let mut runs = Vec::new();
611            let mut renderer_context = RendererContext {
612                text_system: self,
613                components,
614                index_converter: StringIndexConverter::new(text),
615                runs: &mut runs,
616                width: 0.0,
617            };
618            text_layout.Draw(
619                Some((&raw mut renderer_context).cast::<c_void>().cast_const()),
620                &components.text_renderer.0,
621                0.0,
622                0.0,
623            )?;
624            let width = px(renderer_context.width);
625
626            Ok(LineLayout {
627                font_size,
628                width,
629                ascent,
630                descent,
631                runs,
632                len: text.len(),
633            })
634        }
635    }
636
637    fn font_metrics(&self, font_id: FontId) -> FontMetrics {
638        unsafe {
639            let font_info = &self.fonts[font_id.0];
640            let mut metrics = std::mem::zeroed();
641            font_info.font_face.GetMetrics(&mut metrics);
642
643            FontMetrics {
644                units_per_em: metrics.Base.designUnitsPerEm as _,
645                ascent: metrics.Base.ascent as _,
646                descent: -(metrics.Base.descent as f32),
647                line_gap: metrics.Base.lineGap as _,
648                underline_position: metrics.Base.underlinePosition as _,
649                underline_thickness: metrics.Base.underlineThickness as _,
650                cap_height: metrics.Base.capHeight as _,
651                x_height: metrics.Base.xHeight as _,
652                bounding_box: Bounds {
653                    origin: Point {
654                        x: metrics.glyphBoxLeft as _,
655                        y: metrics.glyphBoxBottom as _,
656                    },
657                    size: Size {
658                        width: (metrics.glyphBoxRight - metrics.glyphBoxLeft) as _,
659                        height: (metrics.glyphBoxTop - metrics.glyphBoxBottom) as _,
660                    },
661                },
662            }
663        }
664    }
665
666    fn create_glyph_run_analysis(
667        &self,
668        components: &DirectWriteComponents,
669        params: &RenderGlyphParams,
670    ) -> Result<IDWriteGlyphRunAnalysis> {
671        let font = &self.fonts[params.font_id.0];
672        let glyph_id = [params.glyph_id.0 as u16];
673        let advance = [0.0];
674        let offset = [DWRITE_GLYPH_OFFSET::default()];
675        let glyph_run = DWRITE_GLYPH_RUN {
676            fontFace: ManuallyDrop::new(Some(unsafe { std::ptr::read(&***font.font_face) })),
677            fontEmSize: params.font_size.as_f32(),
678            glyphCount: 1,
679            glyphIndices: glyph_id.as_ptr(),
680            glyphAdvances: advance.as_ptr(),
681            glyphOffsets: offset.as_ptr(),
682            isSideways: BOOL(0),
683            bidiLevel: 0,
684        };
685        let transform = DWRITE_MATRIX {
686            m11: params.scale_factor,
687            m12: 0.0,
688            m21: 0.0,
689            m22: params.scale_factor,
690            dx: 0.0,
691            dy: 0.0,
692        };
693        let baseline_origin_x =
694            params.subpixel_variant.x as f32 / SUBPIXEL_VARIANTS_X as f32 / params.scale_factor;
695        let baseline_origin_y = params.subpixel_variant.y as f32
696            / gpui::SUBPIXEL_VARIANTS_Y as f32
697            / params.scale_factor;
698
699        let mut rendering_mode = DWRITE_RENDERING_MODE1::default();
700        let mut grid_fit_mode = DWRITE_GRID_FIT_MODE::default();
701        unsafe {
702            font.font_face.GetRecommendedRenderingMode(
703                params.font_size.as_f32(),
704                // Using 96 as scale is applied by the transform
705                96.0,
706                96.0,
707                Some(&transform),
708                false,
709                DWRITE_OUTLINE_THRESHOLD_ANTIALIASED,
710                DWRITE_MEASURING_MODE_NATURAL,
711                None,
712                &mut rendering_mode,
713                &mut grid_fit_mode,
714            )?;
715        }
716        let rendering_mode = match rendering_mode {
717            DWRITE_RENDERING_MODE1_OUTLINE => DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC,
718            m => m,
719        };
720
721        let antialias_mode = if params.subpixel_rendering {
722            DWRITE_TEXT_ANTIALIAS_MODE_CLEARTYPE
723        } else {
724            DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE
725        };
726
727        let glyph_analysis = unsafe {
728            components.factory.CreateGlyphRunAnalysis(
729                &glyph_run,
730                Some(&transform),
731                rendering_mode,
732                DWRITE_MEASURING_MODE_NATURAL,
733                grid_fit_mode,
734                antialias_mode,
735                baseline_origin_x,
736                baseline_origin_y,
737            )
738        }?;
739        Ok(glyph_analysis)
740    }
741
742    fn raster_bounds(
743        &self,
744        components: &DirectWriteComponents,
745        params: &RenderGlyphParams,
746    ) -> Result<Bounds<DevicePixels>> {
747        let glyph_analysis = self.create_glyph_run_analysis(components, params)?;
748
749        let texture_type = if params.subpixel_rendering {
750            DWRITE_TEXTURE_CLEARTYPE_3x1
751        } else {
752            DWRITE_TEXTURE_ALIASED_1x1
753        };
754
755        let bounds = unsafe { glyph_analysis.GetAlphaTextureBounds(texture_type)? };
756
757        if bounds.right < bounds.left {
758            Ok(Bounds {
759                origin: point(0.into(), 0.into()),
760                size: size(0.into(), 0.into()),
761            })
762        } else {
763            Ok(Bounds {
764                origin: point(bounds.left.into(), bounds.top.into()),
765                size: size(
766                    (bounds.right - bounds.left).into(),
767                    (bounds.bottom - bounds.top).into(),
768                ),
769            })
770        }
771    }
772
773    fn glyph_for_char(&self, font_id: FontId, ch: char) -> Option<GlyphId> {
774        let font_info = &self.fonts[font_id.0];
775        let codepoints = ch as u32;
776        let mut glyph_indices = 0u16;
777        unsafe {
778            font_info
779                .font_face
780                .GetGlyphIndices(&raw const codepoints, 1, &raw mut glyph_indices)
781                .log_err()
782        }
783        .map(|_| GlyphId(glyph_indices as u32))
784    }
785
786    fn rasterize_glyph(
787        &self,
788        components: &DirectWriteComponents,
789        params: &RenderGlyphParams,
790        glyph_bounds: Bounds<DevicePixels>,
791    ) -> Result<(Size<DevicePixels>, Vec<u8>)> {
792        if glyph_bounds.size.width.0 == 0 || glyph_bounds.size.height.0 == 0 {
793            anyhow::bail!("glyph bounds are empty");
794        }
795
796        let bitmap_data = if params.is_emoji {
797            if let Ok(color) = self.rasterize_color(components, params, glyph_bounds) {
798                color
799            } else {
800                let monochrome = self.rasterize_monochrome(components, params, glyph_bounds)?;
801                monochrome
802                    .into_iter()
803                    .flat_map(|pixel| [0, 0, 0, pixel])
804                    .collect::<Vec<_>>()
805            }
806        } else {
807            self.rasterize_monochrome(components, params, glyph_bounds)?
808        };
809
810        Ok((glyph_bounds.size, bitmap_data))
811    }
812
813    fn rasterize_monochrome(
814        &self,
815        components: &DirectWriteComponents,
816        params: &RenderGlyphParams,
817        glyph_bounds: Bounds<DevicePixels>,
818    ) -> Result<Vec<u8>> {
819        let glyph_analysis = self.create_glyph_run_analysis(components, params)?;
820        if !params.subpixel_rendering {
821            let mut bitmap_data =
822                vec![0u8; glyph_bounds.size.width.0 as usize * glyph_bounds.size.height.0 as usize];
823            unsafe {
824                glyph_analysis.CreateAlphaTexture(
825                    DWRITE_TEXTURE_ALIASED_1x1,
826                    &RECT {
827                        left: glyph_bounds.origin.x.0,
828                        top: glyph_bounds.origin.y.0,
829                        right: glyph_bounds.size.width.0 + glyph_bounds.origin.x.0,
830                        bottom: glyph_bounds.size.height.0 + glyph_bounds.origin.y.0,
831                    },
832                    &mut bitmap_data,
833                )?;
834            }
835
836            return Ok(bitmap_data);
837        }
838
839        let width = glyph_bounds.size.width.0 as usize;
840        let height = glyph_bounds.size.height.0 as usize;
841        let pixel_count = width * height;
842
843        let mut bitmap_data = vec![0u8; pixel_count * 4];
844
845        unsafe {
846            glyph_analysis.CreateAlphaTexture(
847                DWRITE_TEXTURE_CLEARTYPE_3x1,
848                &RECT {
849                    left: glyph_bounds.origin.x.0,
850                    top: glyph_bounds.origin.y.0,
851                    right: glyph_bounds.size.width.0 + glyph_bounds.origin.x.0,
852                    bottom: glyph_bounds.size.height.0 + glyph_bounds.origin.y.0,
853                },
854                &mut bitmap_data[..pixel_count * 3],
855            )?;
856        }
857
858        // The output buffer expects RGBA data, so pad the alpha channel with zeros.
859        for pixel_ix in (0..pixel_count).rev() {
860            let src = pixel_ix * 3;
861            let dst = pixel_ix * 4;
862            (
863                bitmap_data[dst],
864                bitmap_data[dst + 1],
865                bitmap_data[dst + 2],
866                bitmap_data[dst + 3],
867            ) = (
868                bitmap_data[src],
869                bitmap_data[src + 1],
870                bitmap_data[src + 2],
871                0,
872            );
873        }
874
875        Ok(bitmap_data)
876    }
877
878    fn rasterize_color(
879        &self,
880        components: &DirectWriteComponents,
881        params: &RenderGlyphParams,
882        glyph_bounds: Bounds<DevicePixels>,
883    ) -> Result<Vec<u8>> {
884        // INVARIANT: the code below drives the *shared* D3D11 immediate context
885        // (`Map`/`Unmap`/`Draw`/`CopyResource`), which `DirectXRenderer` and `DirectXAtlas` also
886        // touch. An immediate `ID3D11DeviceContext` is not thread-safe, so this must only run on
887        // the main UI thread (which it always is; text rasterization never leaves that thread).
888        let bitmap_size = glyph_bounds.size;
889        let subpixel_shift = params
890            .subpixel_variant
891            .map(|v| v as f32 / SUBPIXEL_VARIANTS_X as f32);
892        let baseline_origin_x = subpixel_shift.x / params.scale_factor;
893        let baseline_origin_y = subpixel_shift.y / params.scale_factor;
894
895        let transform = DWRITE_MATRIX {
896            m11: params.scale_factor,
897            m12: 0.0,
898            m21: 0.0,
899            m22: params.scale_factor,
900            dx: 0.0,
901            dy: 0.0,
902        };
903
904        let font = &self.fonts[params.font_id.0];
905        let glyph_id = [params.glyph_id.0 as u16];
906        let advance = [glyph_bounds.size.width.0 as f32];
907        let offset = [DWRITE_GLYPH_OFFSET {
908            advanceOffset: -glyph_bounds.origin.x.0 as f32 / params.scale_factor,
909            ascenderOffset: glyph_bounds.origin.y.0 as f32 / params.scale_factor,
910        }];
911        let glyph_run = DWRITE_GLYPH_RUN {
912            fontFace: ManuallyDrop::new(Some(unsafe { std::ptr::read(&***font.font_face) })),
913            fontEmSize: params.font_size.as_f32(),
914            glyphCount: 1,
915            glyphIndices: glyph_id.as_ptr(),
916            glyphAdvances: advance.as_ptr(),
917            glyphOffsets: offset.as_ptr(),
918            isSideways: BOOL(0),
919            bidiLevel: 0,
920        };
921
922        // todo: support formats other than COLR
923        let color_enumerator = unsafe {
924            components.factory.TranslateColorGlyphRun(
925                Vector2::new(baseline_origin_x, baseline_origin_y),
926                &glyph_run,
927                None,
928                DWRITE_GLYPH_IMAGE_FORMATS_COLR,
929                DWRITE_MEASURING_MODE_NATURAL,
930                Some(&transform),
931                0,
932            )
933        }?;
934
935        let mut glyph_layers = Vec::new();
936        let mut alpha_data = Vec::new();
937        loop {
938            let color_run = unsafe { color_enumerator.GetCurrentRun() }?;
939            let color_run = unsafe { &*color_run };
940            let image_format = color_run.glyphImageFormat & !DWRITE_GLYPH_IMAGE_FORMATS_TRUETYPE;
941            if image_format == DWRITE_GLYPH_IMAGE_FORMATS_COLR {
942                let color_analysis = unsafe {
943                    components.factory.CreateGlyphRunAnalysis(
944                        &color_run.Base.glyphRun as *const _,
945                        Some(&transform),
946                        DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC,
947                        DWRITE_MEASURING_MODE_NATURAL,
948                        DWRITE_GRID_FIT_MODE_DEFAULT,
949                        DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE,
950                        baseline_origin_x,
951                        baseline_origin_y,
952                    )
953                }?;
954
955                let color_bounds =
956                    unsafe { color_analysis.GetAlphaTextureBounds(DWRITE_TEXTURE_ALIASED_1x1) }?;
957
958                let color_size = size(
959                    color_bounds.right - color_bounds.left,
960                    color_bounds.bottom - color_bounds.top,
961                );
962                if color_size.width > 0 && color_size.height > 0 {
963                    alpha_data.clear();
964                    alpha_data.resize((color_size.width * color_size.height) as usize, 0);
965                    unsafe {
966                        color_analysis.CreateAlphaTexture(
967                            DWRITE_TEXTURE_ALIASED_1x1,
968                            &color_bounds,
969                            &mut alpha_data,
970                        )
971                    }?;
972
973                    let run_color = {
974                        let run_color = color_run.Base.runColor;
975                        Rgba {
976                            r: run_color.r,
977                            g: run_color.g,
978                            b: run_color.b,
979                            a: run_color.a,
980                        }
981                    };
982                    let bounds = bounds(point(color_bounds.left, color_bounds.top), color_size);
983                    glyph_layers.push(GlyphLayerTexture::new(
984                        &self.gpu_state,
985                        run_color,
986                        bounds,
987                        &alpha_data,
988                    )?);
989                }
990            }
991
992            let has_next = unsafe { color_enumerator.MoveNext() }
993                .map(|e| e.as_bool())
994                .unwrap_or(false);
995            if !has_next {
996                break;
997            }
998        }
999
1000        let gpu_state = &self.gpu_state;
1001        let params_buffer = {
1002            let desc = D3D11_BUFFER_DESC {
1003                ByteWidth: std::mem::size_of::<GlyphLayerTextureParams>() as u32,
1004                Usage: D3D11_USAGE_DYNAMIC,
1005                BindFlags: D3D11_BIND_CONSTANT_BUFFER.0 as u32,
1006                CPUAccessFlags: D3D11_CPU_ACCESS_WRITE.0 as u32,
1007                MiscFlags: 0,
1008                StructureByteStride: 0,
1009            };
1010
1011            let mut buffer = None;
1012            unsafe {
1013                gpu_state
1014                    .device
1015                    .CreateBuffer(&desc, None, Some(&mut buffer))
1016            }?;
1017            buffer
1018        };
1019
1020        let render_target_texture = {
1021            let mut texture = None;
1022            let desc = D3D11_TEXTURE2D_DESC {
1023                Width: bitmap_size.width.0 as u32,
1024                Height: bitmap_size.height.0 as u32,
1025                MipLevels: 1,
1026                ArraySize: 1,
1027                Format: DXGI_FORMAT_B8G8R8A8_UNORM,
1028                SampleDesc: DXGI_SAMPLE_DESC {
1029                    Count: 1,
1030                    Quality: 0,
1031                },
1032                Usage: D3D11_USAGE_DEFAULT,
1033                BindFlags: D3D11_BIND_RENDER_TARGET.0 as u32,
1034                CPUAccessFlags: 0,
1035                MiscFlags: 0,
1036            };
1037            unsafe {
1038                gpu_state
1039                    .device
1040                    .CreateTexture2D(&desc, None, Some(&mut texture))
1041            }?;
1042            texture.unwrap()
1043        };
1044
1045        let render_target_view = {
1046            let desc = D3D11_RENDER_TARGET_VIEW_DESC {
1047                Format: DXGI_FORMAT_B8G8R8A8_UNORM,
1048                ViewDimension: D3D11_RTV_DIMENSION_TEXTURE2D,
1049                Anonymous: D3D11_RENDER_TARGET_VIEW_DESC_0 {
1050                    Texture2D: D3D11_TEX2D_RTV { MipSlice: 0 },
1051                },
1052            };
1053            let mut rtv = None;
1054            unsafe {
1055                gpu_state.device.CreateRenderTargetView(
1056                    &render_target_texture,
1057                    Some(&desc),
1058                    Some(&mut rtv),
1059                )
1060            }?;
1061            rtv
1062        };
1063
1064        let staging_texture = {
1065            let mut texture = None;
1066            let desc = D3D11_TEXTURE2D_DESC {
1067                Width: bitmap_size.width.0 as u32,
1068                Height: bitmap_size.height.0 as u32,
1069                MipLevels: 1,
1070                ArraySize: 1,
1071                Format: DXGI_FORMAT_B8G8R8A8_UNORM,
1072                SampleDesc: DXGI_SAMPLE_DESC {
1073                    Count: 1,
1074                    Quality: 0,
1075                },
1076                Usage: D3D11_USAGE_STAGING,
1077                BindFlags: 0,
1078                CPUAccessFlags: D3D11_CPU_ACCESS_READ.0 as u32,
1079                MiscFlags: 0,
1080            };
1081            unsafe {
1082                gpu_state
1083                    .device
1084                    .CreateTexture2D(&desc, None, Some(&mut texture))
1085            }?;
1086            texture.unwrap()
1087        };
1088
1089        let device_context = &gpu_state.device_context;
1090        unsafe { device_context.IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP) };
1091        unsafe { device_context.VSSetShader(&gpu_state.vertex_shader, None) };
1092        unsafe { device_context.PSSetShader(&gpu_state.pixel_shader, None) };
1093        unsafe {
1094            device_context.VSSetConstantBuffers(0, Some(std::slice::from_ref(&params_buffer)))
1095        };
1096        unsafe {
1097            device_context.PSSetConstantBuffers(0, Some(std::slice::from_ref(&params_buffer)))
1098        };
1099        unsafe {
1100            device_context.OMSetRenderTargets(Some(std::slice::from_ref(&render_target_view)), None)
1101        };
1102        unsafe { device_context.PSSetSamplers(0, Some(std::slice::from_ref(&gpu_state.sampler))) };
1103        unsafe { device_context.OMSetBlendState(&gpu_state.blend_state, None, 0xffffffff) };
1104
1105        let crate::FontInfo {
1106            gamma_ratios,
1107            grayscale_enhanced_contrast,
1108            ..
1109        } = DirectXRenderer::get_font_info();
1110
1111        for layer in glyph_layers {
1112            let params = GlyphLayerTextureParams {
1113                run_color: layer.run_color,
1114                bounds: layer.bounds,
1115                gamma_ratios: *gamma_ratios,
1116                grayscale_enhanced_contrast: *grayscale_enhanced_contrast,
1117                _pad: [0f32; 3],
1118            };
1119            unsafe {
1120                let mut dest = std::mem::zeroed();
1121                gpu_state.device_context.Map(
1122                    params_buffer.as_ref().unwrap(),
1123                    0,
1124                    D3D11_MAP_WRITE_DISCARD,
1125                    0,
1126                    Some(&mut dest),
1127                )?;
1128                std::ptr::copy_nonoverlapping(&params as *const _, dest.pData as *mut _, 1);
1129                gpu_state
1130                    .device_context
1131                    .Unmap(params_buffer.as_ref().unwrap(), 0);
1132            };
1133
1134            let texture = [Some(layer.texture_view)];
1135            unsafe { device_context.PSSetShaderResources(0, Some(&texture)) };
1136
1137            let viewport = [D3D11_VIEWPORT {
1138                TopLeftX: layer.bounds.origin.x as f32,
1139                TopLeftY: layer.bounds.origin.y as f32,
1140                Width: layer.bounds.size.width as f32,
1141                Height: layer.bounds.size.height as f32,
1142                MinDepth: 0.0,
1143                MaxDepth: 1.0,
1144            }];
1145            unsafe { device_context.RSSetViewports(Some(&viewport)) };
1146
1147            unsafe { device_context.Draw(4, 0) };
1148        }
1149
1150        unsafe { device_context.CopyResource(&staging_texture, &render_target_texture) };
1151
1152        let mapped_data = {
1153            let mut mapped_data = D3D11_MAPPED_SUBRESOURCE::default();
1154            unsafe {
1155                device_context.Map(
1156                    &staging_texture,
1157                    0,
1158                    D3D11_MAP_READ,
1159                    0,
1160                    Some(&mut mapped_data),
1161                )
1162            }?;
1163            mapped_data
1164        };
1165        let mut rasterized =
1166            vec![0u8; (bitmap_size.width.0 as u32 * bitmap_size.height.0 as u32 * 4) as usize];
1167
1168        for y in 0..bitmap_size.height.0 as usize {
1169            let width = bitmap_size.width.0 as usize;
1170            unsafe {
1171                std::ptr::copy_nonoverlapping::<u8>(
1172                    (mapped_data.pData as *const u8).byte_add(mapped_data.RowPitch as usize * y),
1173                    rasterized
1174                        .as_mut_ptr()
1175                        .byte_add(width * y * std::mem::size_of::<u32>()),
1176                    width * std::mem::size_of::<u32>(),
1177                )
1178            };
1179        }
1180
1181        // Release the mapping now that the rows have been copied out; leaving `staging_texture`
1182        // mapped would leak the mapping and keep the resource pinned for later reuse.
1183        unsafe { device_context.Unmap(&staging_texture, 0) };
1184
1185        // Convert from premultiplied to straight alpha
1186        for chunk in rasterized.chunks_exact_mut(4) {
1187            let b = chunk[0] as f32;
1188            let g = chunk[1] as f32;
1189            let r = chunk[2] as f32;
1190            let a = chunk[3] as f32;
1191            if a > 0.0 {
1192                let inv_a = 255.0 / a;
1193                chunk[0] = (b * inv_a).clamp(0.0, 255.0) as u8;
1194                chunk[1] = (g * inv_a).clamp(0.0, 255.0) as u8;
1195                chunk[2] = (r * inv_a).clamp(0.0, 255.0) as u8;
1196            }
1197        }
1198
1199        Ok(rasterized)
1200    }
1201
1202    fn get_typographic_bounds(&self, font_id: FontId, glyph_id: GlyphId) -> Result<Bounds<f32>> {
1203        unsafe {
1204            let font = &self.fonts[font_id.0].font_face;
1205            let glyph_indices = [glyph_id.0 as u16];
1206            let mut metrics = [DWRITE_GLYPH_METRICS::default()];
1207            font.GetDesignGlyphMetrics(glyph_indices.as_ptr(), 1, metrics.as_mut_ptr(), false)?;
1208
1209            let metrics = &metrics[0];
1210            let advance_width = metrics.advanceWidth as i32;
1211            let advance_height = metrics.advanceHeight as i32;
1212            let left_side_bearing = metrics.leftSideBearing;
1213            let right_side_bearing = metrics.rightSideBearing;
1214            let top_side_bearing = metrics.topSideBearing;
1215            let bottom_side_bearing = metrics.bottomSideBearing;
1216            let vertical_origin_y = metrics.verticalOriginY;
1217
1218            let y_offset = vertical_origin_y + bottom_side_bearing - advance_height;
1219            let width = advance_width - (left_side_bearing + right_side_bearing);
1220            let height = advance_height - (top_side_bearing + bottom_side_bearing);
1221
1222            Ok(Bounds {
1223                origin: Point {
1224                    x: left_side_bearing as f32,
1225                    y: y_offset as f32,
1226                },
1227                size: Size {
1228                    width: width as f32,
1229                    height: height as f32,
1230                },
1231            })
1232        }
1233    }
1234
1235    fn get_advance(&self, font_id: FontId, glyph_id: GlyphId) -> Result<Size<f32>> {
1236        unsafe {
1237            let font = &self.fonts[font_id.0].font_face;
1238            let glyph_indices = [glyph_id.0 as u16];
1239            let mut metrics = [DWRITE_GLYPH_METRICS::default()];
1240            font.GetDesignGlyphMetrics(glyph_indices.as_ptr(), 1, metrics.as_mut_ptr(), false)?;
1241
1242            let metrics = &metrics[0];
1243
1244            Ok(Size {
1245                width: metrics.advanceWidth as f32,
1246                height: 0.0,
1247            })
1248        }
1249    }
1250
1251    fn all_font_names(&self, components: &DirectWriteComponents) -> Vec<String> {
1252        let mut result =
1253            get_font_names_from_collection(&self.system_font_collection, &components.locale);
1254        result.extend(get_font_names_from_collection(
1255            &self.custom_font_collection,
1256            &components.locale,
1257        ));
1258        result
1259    }
1260
1261    fn handle_gpu_lost(&mut self, directx_devices: &DirectXDevices) -> Result<()> {
1262        try_to_recover_from_device_lost(|| {
1263            GPUState::new(directx_devices).context("Recreating GPU state for DirectWrite")
1264        })
1265        .map(|gpu_state| self.gpu_state = gpu_state)
1266    }
1267}
1268
1269struct GlyphLayerTexture {
1270    run_color: Rgba,
1271    bounds: Bounds<i32>,
1272    texture_view: ID3D11ShaderResourceView,
1273    // holding on to the texture to not RAII drop it
1274    _texture: ID3D11Texture2D,
1275}
1276
1277impl GlyphLayerTexture {
1278    fn new(
1279        gpu_state: &GPUState,
1280        run_color: Rgba,
1281        bounds: Bounds<i32>,
1282        alpha_data: &[u8],
1283    ) -> Result<Self> {
1284        let texture_size = bounds.size;
1285
1286        let desc = D3D11_TEXTURE2D_DESC {
1287            Width: texture_size.width as u32,
1288            Height: texture_size.height as u32,
1289            MipLevels: 1,
1290            ArraySize: 1,
1291            Format: DXGI_FORMAT_R8_UNORM,
1292            SampleDesc: DXGI_SAMPLE_DESC {
1293                Count: 1,
1294                Quality: 0,
1295            },
1296            Usage: D3D11_USAGE_DEFAULT,
1297            BindFlags: D3D11_BIND_SHADER_RESOURCE.0 as u32,
1298            CPUAccessFlags: 0,
1299            MiscFlags: 0,
1300        };
1301
1302        let texture = {
1303            let mut texture: Option<ID3D11Texture2D> = None;
1304            unsafe {
1305                gpu_state
1306                    .device
1307                    .CreateTexture2D(&desc, None, Some(&mut texture))?
1308            };
1309            texture.unwrap()
1310        };
1311        let texture_view = {
1312            let mut view: Option<ID3D11ShaderResourceView> = None;
1313            unsafe {
1314                gpu_state
1315                    .device
1316                    .CreateShaderResourceView(&texture, None, Some(&mut view))?
1317            };
1318            view.unwrap()
1319        };
1320
1321        unsafe {
1322            gpu_state.device_context.UpdateSubresource(
1323                &texture,
1324                0,
1325                None,
1326                alpha_data.as_ptr() as _,
1327                texture_size.width as u32,
1328                0,
1329            )
1330        };
1331
1332        Ok(GlyphLayerTexture {
1333            run_color,
1334            bounds,
1335            texture_view,
1336            _texture: texture,
1337        })
1338    }
1339}
1340
1341#[repr(C)]
1342struct GlyphLayerTextureParams {
1343    bounds: Bounds<i32>,
1344    run_color: Rgba,
1345    gamma_ratios: [f32; 4],
1346    grayscale_enhanced_contrast: f32,
1347    _pad: [f32; 3],
1348}
1349
1350struct TextRendererWrapper(IDWriteTextRenderer);
1351
1352impl TextRendererWrapper {
1353    fn new(locale_str: HSTRING) -> Self {
1354        let inner = TextRenderer::new(locale_str);
1355        TextRendererWrapper(inner.into())
1356    }
1357}
1358
1359#[implement(IDWriteTextRenderer)]
1360struct TextRenderer {
1361    locale: HSTRING,
1362}
1363
1364impl TextRenderer {
1365    fn new(locale: HSTRING) -> Self {
1366        TextRenderer { locale }
1367    }
1368}
1369
1370struct RendererContext<'t, 'a, 'b> {
1371    text_system: &'t mut DirectWriteState,
1372    components: &'a DirectWriteComponents,
1373    index_converter: StringIndexConverter<'a>,
1374    runs: &'b mut Vec<ShapedRun>,
1375    width: f32,
1376}
1377
1378#[derive(Debug)]
1379struct ClusterAnalyzer<'t> {
1380    utf16_idx: usize,
1381    glyph_idx: usize,
1382    glyph_count: usize,
1383    cluster_map: &'t [u16],
1384}
1385
1386impl<'t> ClusterAnalyzer<'t> {
1387    fn new(cluster_map: &'t [u16], glyph_count: usize) -> Self {
1388        ClusterAnalyzer {
1389            utf16_idx: 0,
1390            glyph_idx: 0,
1391            glyph_count,
1392            cluster_map,
1393        }
1394    }
1395}
1396
1397impl Iterator for ClusterAnalyzer<'_> {
1398    type Item = (usize, usize);
1399
1400    fn next(&mut self) -> Option<(usize, usize)> {
1401        if self.utf16_idx >= self.cluster_map.len() {
1402            return None; // No more clusters
1403        }
1404        let start_utf16_idx = self.utf16_idx;
1405        let current_glyph = self.cluster_map[start_utf16_idx] as usize;
1406
1407        // Find the end of current cluster (where glyph index changes)
1408        let mut end_utf16_idx = start_utf16_idx + 1;
1409        while end_utf16_idx < self.cluster_map.len()
1410            && self.cluster_map[end_utf16_idx] as usize == current_glyph
1411        {
1412            end_utf16_idx += 1;
1413        }
1414
1415        let utf16_len = end_utf16_idx - start_utf16_idx;
1416
1417        // Calculate glyph count for this cluster
1418        let next_glyph = if end_utf16_idx < self.cluster_map.len() {
1419            self.cluster_map[end_utf16_idx] as usize
1420        } else {
1421            self.glyph_count
1422        };
1423
1424        let glyph_count = next_glyph - current_glyph;
1425
1426        // Update state for next call
1427        self.utf16_idx = end_utf16_idx;
1428        self.glyph_idx = next_glyph;
1429
1430        Some((utf16_len, glyph_count))
1431    }
1432}
1433
1434#[allow(non_snake_case)]
1435impl IDWritePixelSnapping_Impl for TextRenderer_Impl {
1436    fn IsPixelSnappingDisabled(
1437        &self,
1438        _clientdrawingcontext: *const ::core::ffi::c_void,
1439    ) -> windows::core::Result<BOOL> {
1440        Ok(BOOL(0))
1441    }
1442
1443    fn GetCurrentTransform(
1444        &self,
1445        _clientdrawingcontext: *const ::core::ffi::c_void,
1446        transform: *mut DWRITE_MATRIX,
1447    ) -> windows::core::Result<()> {
1448        unsafe {
1449            *transform = DWRITE_MATRIX {
1450                m11: 1.0,
1451                m12: 0.0,
1452                m21: 0.0,
1453                m22: 1.0,
1454                dx: 0.0,
1455                dy: 0.0,
1456            };
1457        }
1458        Ok(())
1459    }
1460
1461    fn GetPixelsPerDip(
1462        &self,
1463        _clientdrawingcontext: *const ::core::ffi::c_void,
1464    ) -> windows::core::Result<f32> {
1465        Ok(1.0)
1466    }
1467}
1468
1469#[allow(non_snake_case)]
1470impl IDWriteTextRenderer_Impl for TextRenderer_Impl {
1471    fn DrawGlyphRun(
1472        &self,
1473        clientdrawingcontext: *const ::core::ffi::c_void,
1474        _baselineoriginx: f32,
1475        _baselineoriginy: f32,
1476        _measuringmode: DWRITE_MEASURING_MODE,
1477        glyphrun: *const DWRITE_GLYPH_RUN,
1478        glyphrundescription: *const DWRITE_GLYPH_RUN_DESCRIPTION,
1479        _clientdrawingeffect: windows::core::Ref<windows::core::IUnknown>,
1480    ) -> windows::core::Result<()> {
1481        let glyphrun = unsafe { &*glyphrun };
1482        let glyph_count = glyphrun.glyphCount as usize;
1483        if glyph_count == 0 {
1484            return Ok(());
1485        }
1486        let desc = unsafe { &*glyphrundescription };
1487        let context = unsafe { &mut *(clientdrawingcontext.cast::<RendererContext>().cast_mut()) };
1488        let Some(font_face) = glyphrun.fontFace.as_ref() else {
1489            return Ok(());
1490        };
1491        // This `cast()` action here should never fail since we are running on Win10+, and
1492        // `IDWriteFontFace3` requires Win10
1493        let Ok(font_face) = &font_face.cast::<IDWriteFontFace3>() else {
1494            return Err(Error::new(
1495                DWRITE_E_UNSUPPORTEDOPERATION,
1496                "Failed to cast font face",
1497            ));
1498        };
1499
1500        let font_face_key = font_face.cast::<IUnknown>().unwrap().as_raw().addr();
1501        let font_id = context
1502            .text_system
1503            .font_info_cache
1504            .get(&font_face_key)
1505            .copied()
1506            // in some circumstances, we might be getting served a FontFace that we did not create ourselves
1507            // so create a new font from it and cache it accordingly. The usual culprit here seems to be Segoe UI Symbol
1508            .map_or_else(
1509                || {
1510                    let font = font_face_to_font(font_face, &self.locale)
1511                        .ok_or_else(|| Error::new(DWRITE_E_NOFONT, "Failed to create font"))?;
1512                    let font_id = match context.text_system.font_to_font_id.get(&font) {
1513                        Some(&font_id) => font_id,
1514                        None => context
1515                            .text_system
1516                            .select_and_cache_font(context.components, &font)
1517                            .ok_or_else(|| Error::new(DWRITE_E_NOFONT, "Failed to create font"))?,
1518                    };
1519                    context
1520                        .text_system
1521                        .font_info_cache
1522                        .insert(font_face_key, font_id);
1523                    windows::core::Result::Ok(font_id)
1524                },
1525                Ok,
1526            )?;
1527
1528        let color_font = unsafe { font_face.IsColorFont().as_bool() };
1529
1530        let glyph_ids = unsafe {
1531            slice_from_nullable(
1532                glyphrun.glyphIndices,
1533                glyph_count,
1534                "DirectWrite returned a null glyph indices array",
1535            )?
1536        };
1537        let glyph_advances = unsafe {
1538            slice_from_nullable(
1539                glyphrun.glyphAdvances,
1540                glyph_count,
1541                "DirectWrite returned a null glyph advances array",
1542            )?
1543        };
1544        let glyph_offsets = unsafe {
1545            slice_from_nullable(
1546                glyphrun.glyphOffsets,
1547                glyph_count,
1548                "DirectWrite returned a null glyph offsets array",
1549            )?
1550        };
1551        let cluster_map = unsafe {
1552            slice_from_nullable(
1553                desc.clusterMap,
1554                desc.stringLength as usize,
1555                "DirectWrite returned a null cluster map",
1556            )?
1557        };
1558
1559        let cluster_analyzer = ClusterAnalyzer::new(cluster_map, glyph_count);
1560        let mut utf16_idx = desc.textPosition as usize;
1561        let mut glyph_idx = 0;
1562        let mut glyphs = Vec::with_capacity(glyph_count);
1563        for (cluster_utf16_len, cluster_glyph_count) in cluster_analyzer {
1564            context.index_converter.advance_to_utf16_ix(utf16_idx);
1565            utf16_idx += cluster_utf16_len;
1566            for (cluster_glyph_idx, glyph_id) in glyph_ids
1567                [glyph_idx..(glyph_idx + cluster_glyph_count)]
1568                .iter()
1569                .enumerate()
1570            {
1571                let id = GlyphId(*glyph_id as u32);
1572                let is_emoji =
1573                    color_font && is_color_glyph(font_face, id, &context.components.factory);
1574                let this_glyph_idx = glyph_idx + cluster_glyph_idx;
1575                glyphs.push(ShapedGlyph {
1576                    id,
1577                    position: point(
1578                        px(context.width + glyph_offsets[this_glyph_idx].advanceOffset),
1579                        px(-glyph_offsets[this_glyph_idx].ascenderOffset),
1580                    ),
1581                    index: context.index_converter.utf8_ix,
1582                    is_emoji,
1583                });
1584                context.width += glyph_advances[this_glyph_idx];
1585            }
1586            glyph_idx += cluster_glyph_count;
1587        }
1588        context.runs.push(ShapedRun { font_id, glyphs });
1589        Ok(())
1590    }
1591
1592    fn DrawUnderline(
1593        &self,
1594        _clientdrawingcontext: *const ::core::ffi::c_void,
1595        _baselineoriginx: f32,
1596        _baselineoriginy: f32,
1597        _underline: *const DWRITE_UNDERLINE,
1598        _clientdrawingeffect: windows::core::Ref<windows::core::IUnknown>,
1599    ) -> windows::core::Result<()> {
1600        Err(windows::core::Error::new(
1601            E_NOTIMPL,
1602            "DrawUnderline unimplemented",
1603        ))
1604    }
1605
1606    fn DrawStrikethrough(
1607        &self,
1608        _clientdrawingcontext: *const ::core::ffi::c_void,
1609        _baselineoriginx: f32,
1610        _baselineoriginy: f32,
1611        _strikethrough: *const DWRITE_STRIKETHROUGH,
1612        _clientdrawingeffect: windows::core::Ref<windows::core::IUnknown>,
1613    ) -> windows::core::Result<()> {
1614        Err(windows::core::Error::new(
1615            E_NOTIMPL,
1616            "DrawStrikethrough unimplemented",
1617        ))
1618    }
1619
1620    fn DrawInlineObject(
1621        &self,
1622        _clientdrawingcontext: *const ::core::ffi::c_void,
1623        _originx: f32,
1624        _originy: f32,
1625        _inlineobject: windows::core::Ref<IDWriteInlineObject>,
1626        _issideways: BOOL,
1627        _isrighttoleft: BOOL,
1628        _clientdrawingeffect: windows::core::Ref<windows::core::IUnknown>,
1629    ) -> windows::core::Result<()> {
1630        Err(windows::core::Error::new(
1631            E_NOTIMPL,
1632            "DrawInlineObject unimplemented",
1633        ))
1634    }
1635}
1636
1637/// Interprets an optional DirectWrite array pointer as a slice, treating a
1638/// null pointer with a zero length as an empty slice. A null pointer with a
1639/// nonzero length fails with `null_error_message`.
1640///
1641/// # Safety
1642///
1643/// When `ptr` is non-null, the caller must guarantee that it points to a valid
1644/// array of at least `len` elements that outlives the returned slice.
1645unsafe fn slice_from_nullable<'a, T>(
1646    ptr: *const T,
1647    len: usize,
1648    null_error_message: &str,
1649) -> windows::core::Result<&'a [T]> {
1650    if ptr.is_null() {
1651        if len != 0 {
1652            return Err(Error::new(E_INVALIDARG, null_error_message));
1653        }
1654        Ok(&[])
1655    } else {
1656        Ok(unsafe { std::slice::from_raw_parts(ptr, len) })
1657    }
1658}
1659
1660struct StringIndexConverter<'a> {
1661    text: &'a str,
1662    utf8_ix: usize,
1663    utf16_ix: usize,
1664}
1665
1666impl<'a> StringIndexConverter<'a> {
1667    fn new(text: &'a str) -> Self {
1668        Self {
1669            text,
1670            utf8_ix: 0,
1671            utf16_ix: 0,
1672        }
1673    }
1674
1675    #[allow(dead_code)]
1676    fn advance_to_utf8_ix(&mut self, utf8_target: usize) {
1677        for (ix, c) in self.text[self.utf8_ix..].char_indices() {
1678            if self.utf8_ix + ix >= utf8_target {
1679                self.utf8_ix += ix;
1680                return;
1681            }
1682            self.utf16_ix += c.len_utf16();
1683        }
1684        self.utf8_ix = self.text.len();
1685    }
1686
1687    fn advance_to_utf16_ix(&mut self, utf16_target: usize) {
1688        for (ix, c) in self.text[self.utf8_ix..].char_indices() {
1689            if self.utf16_ix >= utf16_target {
1690                self.utf8_ix += ix;
1691                return;
1692            }
1693            self.utf16_ix += c.len_utf16();
1694        }
1695        self.utf8_ix = self.text.len();
1696    }
1697}
1698
1699fn font_style_to_dwrite(style: FontStyle) -> DWRITE_FONT_STYLE {
1700    match style {
1701        FontStyle::Normal => DWRITE_FONT_STYLE_NORMAL,
1702        FontStyle::Italic => DWRITE_FONT_STYLE_ITALIC,
1703        FontStyle::Oblique => DWRITE_FONT_STYLE_OBLIQUE,
1704    }
1705}
1706
1707fn font_style_from_dwrite(value: DWRITE_FONT_STYLE) -> FontStyle {
1708    match value.0 {
1709        0 => FontStyle::Normal,
1710        1 => FontStyle::Italic,
1711        2 => FontStyle::Oblique,
1712        _ => unreachable!(),
1713    }
1714}
1715
1716fn font_weight_to_dwrite(weight: FontWeight) -> DWRITE_FONT_WEIGHT {
1717    DWRITE_FONT_WEIGHT(weight.0 as i32)
1718}
1719
1720fn font_weight_from_dwrite(value: DWRITE_FONT_WEIGHT) -> FontWeight {
1721    FontWeight(value.0 as f32)
1722}
1723
1724fn get_font_names_from_collection(
1725    collection: &IDWriteFontCollection1,
1726    locale: &HSTRING,
1727) -> Vec<String> {
1728    unsafe {
1729        let mut result = Vec::new();
1730        let family_count = collection.GetFontFamilyCount();
1731        for index in 0..family_count {
1732            let Some(font_family) = collection.GetFontFamily(index).log_err() else {
1733                continue;
1734            };
1735            let Some(localized_family_name) = font_family.GetFamilyNames().log_err() else {
1736                continue;
1737            };
1738            let Some(family_name) = get_name(localized_family_name, locale).log_err() else {
1739                continue;
1740            };
1741            result.push(family_name);
1742        }
1743
1744        result
1745    }
1746}
1747
1748fn font_face_to_font(font_face: &IDWriteFontFace3, locale: &HSTRING) -> Option<Font> {
1749    let localized_family_name = unsafe { font_face.GetFamilyNames().log_err() }?;
1750    let family_name = get_name(localized_family_name, locale).log_err()?;
1751    let weight = unsafe { font_face.GetWeight() };
1752    let style = unsafe { font_face.GetStyle() };
1753    Some(Font {
1754        family: family_name.into(),
1755        features: FontFeatures::default(),
1756        weight: font_weight_from_dwrite(weight),
1757        style: font_style_from_dwrite(style),
1758        fallbacks: None,
1759    })
1760}
1761
1762// https://learn.microsoft.com/en-us/windows/win32/api/dwrite/ne-dwrite-dwrite_font_feature_tag
1763fn apply_font_features(
1764    direct_write_features: &IDWriteTypography,
1765    features: &FontFeatures,
1766) -> Result<()> {
1767    let tag_values = features.tag_value_list();
1768    if tag_values.is_empty() {
1769        return Ok(());
1770    }
1771
1772    // All of these features are enabled by default by DirectWrite.
1773    // If you want to (and can) peek into the source of DirectWrite
1774    let mut feature_liga = make_direct_write_feature("liga", 1);
1775    let mut feature_clig = make_direct_write_feature("clig", 1);
1776    let mut feature_calt = make_direct_write_feature("calt", 1);
1777
1778    for (tag, value) in tag_values {
1779        if tag.as_str() == "liga" && *value == 0 {
1780            feature_liga.parameter = 0;
1781            continue;
1782        }
1783        if tag.as_str() == "clig" && *value == 0 {
1784            feature_clig.parameter = 0;
1785            continue;
1786        }
1787        if tag.as_str() == "calt" && *value == 0 {
1788            feature_calt.parameter = 0;
1789            continue;
1790        }
1791
1792        unsafe {
1793            direct_write_features.AddFontFeature(make_direct_write_feature(tag, *value))?;
1794        }
1795    }
1796    unsafe {
1797        direct_write_features.AddFontFeature(feature_liga)?;
1798        direct_write_features.AddFontFeature(feature_clig)?;
1799        direct_write_features.AddFontFeature(feature_calt)?;
1800    }
1801
1802    Ok(())
1803}
1804
1805#[inline]
1806const fn make_direct_write_feature(feature_name: &str, parameter: u32) -> DWRITE_FONT_FEATURE {
1807    let tag = make_direct_write_tag(feature_name);
1808    DWRITE_FONT_FEATURE {
1809        nameTag: tag,
1810        parameter,
1811    }
1812}
1813
1814#[inline]
1815const fn make_open_type_tag(tag_name: &str) -> u32 {
1816    let bytes = tag_name.as_bytes();
1817    debug_assert!(bytes.len() == 4);
1818    u32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]])
1819}
1820
1821#[inline]
1822const fn make_direct_write_tag(tag_name: &str) -> DWRITE_FONT_FEATURE_TAG {
1823    DWRITE_FONT_FEATURE_TAG(make_open_type_tag(tag_name))
1824}
1825
1826#[inline]
1827fn get_name(string: IDWriteLocalizedStrings, locale: &HSTRING) -> Result<String> {
1828    let mut locale_name_index = 0u32;
1829    let mut exists = BOOL(0);
1830    unsafe { string.FindLocaleName(locale, &mut locale_name_index, &mut exists as _)? };
1831    if !exists.as_bool() {
1832        unsafe {
1833            string.FindLocaleName(
1834                DEFAULT_LOCALE_NAME,
1835                &mut locale_name_index as _,
1836                &mut exists as _,
1837            )?
1838        };
1839        anyhow::ensure!(exists.as_bool(), "No localised string for {locale}");
1840    }
1841
1842    let name_length = unsafe { string.GetStringLength(locale_name_index) }? as usize;
1843    let mut name_vec = vec![0u16; name_length + 1];
1844    unsafe {
1845        string.GetString(locale_name_index, &mut name_vec)?;
1846    }
1847
1848    Ok(String::from_utf16_lossy(&name_vec[..name_length]))
1849}
1850
1851fn get_system_subpixel_rendering() -> bool {
1852    let mut value = c_uint::default();
1853    let result = unsafe {
1854        SystemParametersInfoW(
1855            SPI_GETFONTSMOOTHINGTYPE,
1856            0,
1857            Some((&mut value) as *mut c_uint as *mut c_void),
1858            SYSTEM_PARAMETERS_INFO_UPDATE_FLAGS::default(),
1859        )
1860    };
1861    if result.log_err().is_some() {
1862        value == FE_FONTSMOOTHINGCLEARTYPE
1863    } else {
1864        true
1865    }
1866}
1867
1868fn get_system_ui_font_name() -> SharedString {
1869    unsafe {
1870        let mut info: LOGFONTW = std::mem::zeroed();
1871        let font_family = if SystemParametersInfoW(
1872            SPI_GETICONTITLELOGFONT,
1873            std::mem::size_of::<LOGFONTW>() as u32,
1874            Some(&mut info as *mut _ as _),
1875            SYSTEM_PARAMETERS_INFO_UPDATE_FLAGS(0),
1876        )
1877        .log_err()
1878        .is_none()
1879        {
1880            // https://learn.microsoft.com/en-us/windows/win32/uxguide/vis-fonts
1881            // Segoe UI is the Windows font intended for user interface text strings.
1882            "Segoe UI".into()
1883        } else {
1884            let font_name = String::from_utf16_lossy(&info.lfFaceName);
1885            font_name.trim_matches(char::from(0)).to_owned().into()
1886        };
1887        log::info!("Use {} as UI font.", font_family);
1888        font_family
1889    }
1890}
1891
1892// One would think that with newer DirectWrite method: IDWriteFontFace4::GetGlyphImageFormats
1893// but that doesn't seem to work for some glyphs, say ❤
1894fn is_color_glyph(
1895    font_face: &IDWriteFontFace3,
1896    glyph_id: GlyphId,
1897    factory: &IDWriteFactory5,
1898) -> bool {
1899    let glyph_run = DWRITE_GLYPH_RUN {
1900        fontFace: ManuallyDrop::new(Some(unsafe { std::ptr::read(&****font_face) })),
1901        fontEmSize: 14.0,
1902        glyphCount: 1,
1903        glyphIndices: &(glyph_id.0 as u16),
1904        glyphAdvances: &0.0,
1905        glyphOffsets: &DWRITE_GLYPH_OFFSET {
1906            advanceOffset: 0.0,
1907            ascenderOffset: 0.0,
1908        },
1909        isSideways: BOOL(0),
1910        bidiLevel: 0,
1911    };
1912    unsafe {
1913        factory.TranslateColorGlyphRun(
1914            Vector2::default(),
1915            &glyph_run as _,
1916            None,
1917            DWRITE_GLYPH_IMAGE_FORMATS_COLR
1918                | DWRITE_GLYPH_IMAGE_FORMATS_SVG
1919                | DWRITE_GLYPH_IMAGE_FORMATS_PNG
1920                | DWRITE_GLYPH_IMAGE_FORMATS_JPEG
1921                | DWRITE_GLYPH_IMAGE_FORMATS_PREMULTIPLIED_B8G8R8A8,
1922            DWRITE_MEASURING_MODE_NATURAL,
1923            None,
1924            0,
1925        )
1926    }
1927    .is_ok()
1928}
1929
1930const DEFAULT_LOCALE_NAME: PCWSTR = windows::core::w!("en-US");
1931
1932#[cfg(test)]
1933mod tests {
1934    use crate::direct_write::ClusterAnalyzer;
1935
1936    #[test]
1937    fn test_cluster_map() {
1938        let cluster_map = [0];
1939        let mut analyzer = ClusterAnalyzer::new(&cluster_map, 1);
1940        let next = analyzer.next();
1941        assert_eq!(next, Some((1, 1)));
1942        let next = analyzer.next();
1943        assert_eq!(next, None);
1944
1945        let cluster_map = [0, 1, 2];
1946        let mut analyzer = ClusterAnalyzer::new(&cluster_map, 3);
1947        let next = analyzer.next();
1948        assert_eq!(next, Some((1, 1)));
1949        let next = analyzer.next();
1950        assert_eq!(next, Some((1, 1)));
1951        let next = analyzer.next();
1952        assert_eq!(next, Some((1, 1)));
1953        let next = analyzer.next();
1954        assert_eq!(next, None);
1955        // 👨‍👩‍👧‍👦👩‍💻
1956        let cluster_map = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4];
1957        let mut analyzer = ClusterAnalyzer::new(&cluster_map, 5);
1958        let next = analyzer.next();
1959        assert_eq!(next, Some((11, 4)));
1960        let next = analyzer.next();
1961        assert_eq!(next, Some((5, 1)));
1962        let next = analyzer.next();
1963        assert_eq!(next, None);
1964        // 👩‍💻
1965        let cluster_map = [0, 0, 0, 0, 0];
1966        let mut analyzer = ClusterAnalyzer::new(&cluster_map, 1);
1967        let next = analyzer.next();
1968        assert_eq!(next, Some((5, 1)));
1969        let next = analyzer.next();
1970        assert_eq!(next, None);
1971    }
1972}
1973
Served at tenant.openagents/omega Member data and write actions are omitted.