1use std::{
2 borrow::Cow,
3 ffi::{c_uint, c_void},
4 mem::ManuallyDrop,
5};
6
7use ::util::{ResultExt, maybe};
8use anyhow::{Context, Result};
9use collections::HashMap;
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 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 const renderer_context).cast::<c_void>()),
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 let bitmap_size = glyph_bounds.size;
885 let subpixel_shift = params
886 .subpixel_variant
887 .map(|v| v as f32 / SUBPIXEL_VARIANTS_X as f32);
888 let baseline_origin_x = subpixel_shift.x / params.scale_factor;
889 let baseline_origin_y = subpixel_shift.y / params.scale_factor;
890
891 let transform = DWRITE_MATRIX {
892 m11: params.scale_factor,
893 m12: 0.0,
894 m21: 0.0,
895 m22: params.scale_factor,
896 dx: 0.0,
897 dy: 0.0,
898 };
899
900 let font = &self.fonts[params.font_id.0];
901 let glyph_id = [params.glyph_id.0 as u16];
902 let advance = [glyph_bounds.size.width.0 as f32];
903 let offset = [DWRITE_GLYPH_OFFSET {
904 advanceOffset: -glyph_bounds.origin.x.0 as f32 / params.scale_factor,
905 ascenderOffset: glyph_bounds.origin.y.0 as f32 / params.scale_factor,
906 }];
907 let glyph_run = DWRITE_GLYPH_RUN {
908 fontFace: ManuallyDrop::new(Some(unsafe { std::ptr::read(&***font.font_face) })),
909 fontEmSize: params.font_size.as_f32(),
910 glyphCount: 1,
911 glyphIndices: glyph_id.as_ptr(),
912 glyphAdvances: advance.as_ptr(),
913 glyphOffsets: offset.as_ptr(),
914 isSideways: BOOL(0),
915 bidiLevel: 0,
916 };
917
918 // todo: support formats other than COLR
919 let color_enumerator = unsafe {
920 components.factory.TranslateColorGlyphRun(
921 Vector2::new(baseline_origin_x, baseline_origin_y),
922 &glyph_run,
923 None,
924 DWRITE_GLYPH_IMAGE_FORMATS_COLR,
925 DWRITE_MEASURING_MODE_NATURAL,
926 Some(&transform),
927 0,
928 )
929 }?;
930
931 let mut glyph_layers = Vec::new();
932 let mut alpha_data = Vec::new();
933 loop {
934 let color_run = unsafe { color_enumerator.GetCurrentRun() }?;
935 let color_run = unsafe { &*color_run };
936 let image_format = color_run.glyphImageFormat & !DWRITE_GLYPH_IMAGE_FORMATS_TRUETYPE;
937 if image_format == DWRITE_GLYPH_IMAGE_FORMATS_COLR {
938 let color_analysis = unsafe {
939 components.factory.CreateGlyphRunAnalysis(
940 &color_run.Base.glyphRun as *const _,
941 Some(&transform),
942 DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC,
943 DWRITE_MEASURING_MODE_NATURAL,
944 DWRITE_GRID_FIT_MODE_DEFAULT,
945 DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE,
946 baseline_origin_x,
947 baseline_origin_y,
948 )
949 }?;
950
951 let color_bounds =
952 unsafe { color_analysis.GetAlphaTextureBounds(DWRITE_TEXTURE_ALIASED_1x1) }?;
953
954 let color_size = size(
955 color_bounds.right - color_bounds.left,
956 color_bounds.bottom - color_bounds.top,
957 );
958 if color_size.width > 0 && color_size.height > 0 {
959 alpha_data.clear();
960 alpha_data.resize((color_size.width * color_size.height) as usize, 0);
961 unsafe {
962 color_analysis.CreateAlphaTexture(
963 DWRITE_TEXTURE_ALIASED_1x1,
964 &color_bounds,
965 &mut alpha_data,
966 )
967 }?;
968
969 let run_color = {
970 let run_color = color_run.Base.runColor;
971 Rgba {
972 r: run_color.r,
973 g: run_color.g,
974 b: run_color.b,
975 a: run_color.a,
976 }
977 };
978 let bounds = bounds(point(color_bounds.left, color_bounds.top), color_size);
979 glyph_layers.push(GlyphLayerTexture::new(
980 &self.gpu_state,
981 run_color,
982 bounds,
983 &alpha_data,
984 )?);
985 }
986 }
987
988 let has_next = unsafe { color_enumerator.MoveNext() }
989 .map(|e| e.as_bool())
990 .unwrap_or(false);
991 if !has_next {
992 break;
993 }
994 }
995
996 let gpu_state = &self.gpu_state;
997 let params_buffer = {
998 let desc = D3D11_BUFFER_DESC {
999 ByteWidth: std::mem::size_of::<GlyphLayerTextureParams>() as u32,
1000 Usage: D3D11_USAGE_DYNAMIC,
1001 BindFlags: D3D11_BIND_CONSTANT_BUFFER.0 as u32,
1002 CPUAccessFlags: D3D11_CPU_ACCESS_WRITE.0 as u32,
1003 MiscFlags: 0,
1004 StructureByteStride: 0,
1005 };
1006
1007 let mut buffer = None;
1008 unsafe {
1009 gpu_state
1010 .device
1011 .CreateBuffer(&desc, None, Some(&mut buffer))
1012 }?;
1013 buffer
1014 };
1015
1016 let render_target_texture = {
1017 let mut texture = None;
1018 let desc = D3D11_TEXTURE2D_DESC {
1019 Width: bitmap_size.width.0 as u32,
1020 Height: bitmap_size.height.0 as u32,
1021 MipLevels: 1,
1022 ArraySize: 1,
1023 Format: DXGI_FORMAT_B8G8R8A8_UNORM,
1024 SampleDesc: DXGI_SAMPLE_DESC {
1025 Count: 1,
1026 Quality: 0,
1027 },
1028 Usage: D3D11_USAGE_DEFAULT,
1029 BindFlags: D3D11_BIND_RENDER_TARGET.0 as u32,
1030 CPUAccessFlags: 0,
1031 MiscFlags: 0,
1032 };
1033 unsafe {
1034 gpu_state
1035 .device
1036 .CreateTexture2D(&desc, None, Some(&mut texture))
1037 }?;
1038 texture.unwrap()
1039 };
1040
1041 let render_target_view = {
1042 let desc = D3D11_RENDER_TARGET_VIEW_DESC {
1043 Format: DXGI_FORMAT_B8G8R8A8_UNORM,
1044 ViewDimension: D3D11_RTV_DIMENSION_TEXTURE2D,
1045 Anonymous: D3D11_RENDER_TARGET_VIEW_DESC_0 {
1046 Texture2D: D3D11_TEX2D_RTV { MipSlice: 0 },
1047 },
1048 };
1049 let mut rtv = None;
1050 unsafe {
1051 gpu_state.device.CreateRenderTargetView(
1052 &render_target_texture,
1053 Some(&desc),
1054 Some(&mut rtv),
1055 )
1056 }?;
1057 rtv
1058 };
1059
1060 let staging_texture = {
1061 let mut texture = None;
1062 let desc = D3D11_TEXTURE2D_DESC {
1063 Width: bitmap_size.width.0 as u32,
1064 Height: bitmap_size.height.0 as u32,
1065 MipLevels: 1,
1066 ArraySize: 1,
1067 Format: DXGI_FORMAT_B8G8R8A8_UNORM,
1068 SampleDesc: DXGI_SAMPLE_DESC {
1069 Count: 1,
1070 Quality: 0,
1071 },
1072 Usage: D3D11_USAGE_STAGING,
1073 BindFlags: 0,
1074 CPUAccessFlags: D3D11_CPU_ACCESS_READ.0 as u32,
1075 MiscFlags: 0,
1076 };
1077 unsafe {
1078 gpu_state
1079 .device
1080 .CreateTexture2D(&desc, None, Some(&mut texture))
1081 }?;
1082 texture.unwrap()
1083 };
1084
1085 let device_context = &gpu_state.device_context;
1086 unsafe { device_context.IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP) };
1087 unsafe { device_context.VSSetShader(&gpu_state.vertex_shader, None) };
1088 unsafe { device_context.PSSetShader(&gpu_state.pixel_shader, None) };
1089 unsafe {
1090 device_context.VSSetConstantBuffers(0, Some(std::slice::from_ref(¶ms_buffer)))
1091 };
1092 unsafe {
1093 device_context.PSSetConstantBuffers(0, Some(std::slice::from_ref(¶ms_buffer)))
1094 };
1095 unsafe {
1096 device_context.OMSetRenderTargets(Some(std::slice::from_ref(&render_target_view)), None)
1097 };
1098 unsafe { device_context.PSSetSamplers(0, Some(std::slice::from_ref(&gpu_state.sampler))) };
1099 unsafe { device_context.OMSetBlendState(&gpu_state.blend_state, None, 0xffffffff) };
1100
1101 let crate::FontInfo {
1102 gamma_ratios,
1103 grayscale_enhanced_contrast,
1104 ..
1105 } = DirectXRenderer::get_font_info();
1106
1107 for layer in glyph_layers {
1108 let params = GlyphLayerTextureParams {
1109 run_color: layer.run_color,
1110 bounds: layer.bounds,
1111 gamma_ratios: *gamma_ratios,
1112 grayscale_enhanced_contrast: *grayscale_enhanced_contrast,
1113 _pad: [0f32; 3],
1114 };
1115 unsafe {
1116 let mut dest = std::mem::zeroed();
1117 gpu_state.device_context.Map(
1118 params_buffer.as_ref().unwrap(),
1119 0,
1120 D3D11_MAP_WRITE_DISCARD,
1121 0,
1122 Some(&mut dest),
1123 )?;
1124 std::ptr::copy_nonoverlapping(¶ms as *const _, dest.pData as *mut _, 1);
1125 gpu_state
1126 .device_context
1127 .Unmap(params_buffer.as_ref().unwrap(), 0);
1128 };
1129
1130 let texture = [Some(layer.texture_view)];
1131 unsafe { device_context.PSSetShaderResources(0, Some(&texture)) };
1132
1133 let viewport = [D3D11_VIEWPORT {
1134 TopLeftX: layer.bounds.origin.x as f32,
1135 TopLeftY: layer.bounds.origin.y as f32,
1136 Width: layer.bounds.size.width as f32,
1137 Height: layer.bounds.size.height as f32,
1138 MinDepth: 0.0,
1139 MaxDepth: 1.0,
1140 }];
1141 unsafe { device_context.RSSetViewports(Some(&viewport)) };
1142
1143 unsafe { device_context.Draw(4, 0) };
1144 }
1145
1146 unsafe { device_context.CopyResource(&staging_texture, &render_target_texture) };
1147
1148 let mapped_data = {
1149 let mut mapped_data = D3D11_MAPPED_SUBRESOURCE::default();
1150 unsafe {
1151 device_context.Map(
1152 &staging_texture,
1153 0,
1154 D3D11_MAP_READ,
1155 0,
1156 Some(&mut mapped_data),
1157 )
1158 }?;
1159 mapped_data
1160 };
1161 let mut rasterized =
1162 vec![0u8; (bitmap_size.width.0 as u32 * bitmap_size.height.0 as u32 * 4) as usize];
1163
1164 for y in 0..bitmap_size.height.0 as usize {
1165 let width = bitmap_size.width.0 as usize;
1166 unsafe {
1167 std::ptr::copy_nonoverlapping::<u8>(
1168 (mapped_data.pData as *const u8).byte_add(mapped_data.RowPitch as usize * y),
1169 rasterized
1170 .as_mut_ptr()
1171 .byte_add(width * y * std::mem::size_of::<u32>()),
1172 width * std::mem::size_of::<u32>(),
1173 )
1174 };
1175 }
1176
1177 // Convert from premultiplied to straight alpha
1178 for chunk in rasterized.chunks_exact_mut(4) {
1179 let b = chunk[0] as f32;
1180 let g = chunk[1] as f32;
1181 let r = chunk[2] as f32;
1182 let a = chunk[3] as f32;
1183 if a > 0.0 {
1184 let inv_a = 255.0 / a;
1185 chunk[0] = (b * inv_a).clamp(0.0, 255.0) as u8;
1186 chunk[1] = (g * inv_a).clamp(0.0, 255.0) as u8;
1187 chunk[2] = (r * inv_a).clamp(0.0, 255.0) as u8;
1188 }
1189 }
1190
1191 Ok(rasterized)
1192 }
1193
1194 fn get_typographic_bounds(&self, font_id: FontId, glyph_id: GlyphId) -> Result<Bounds<f32>> {
1195 unsafe {
1196 let font = &self.fonts[font_id.0].font_face;
1197 let glyph_indices = [glyph_id.0 as u16];
1198 let mut metrics = [DWRITE_GLYPH_METRICS::default()];
1199 font.GetDesignGlyphMetrics(glyph_indices.as_ptr(), 1, metrics.as_mut_ptr(), false)?;
1200
1201 let metrics = &metrics[0];
1202 let advance_width = metrics.advanceWidth as i32;
1203 let advance_height = metrics.advanceHeight as i32;
1204 let left_side_bearing = metrics.leftSideBearing;
1205 let right_side_bearing = metrics.rightSideBearing;
1206 let top_side_bearing = metrics.topSideBearing;
1207 let bottom_side_bearing = metrics.bottomSideBearing;
1208 let vertical_origin_y = metrics.verticalOriginY;
1209
1210 let y_offset = vertical_origin_y + bottom_side_bearing - advance_height;
1211 let width = advance_width - (left_side_bearing + right_side_bearing);
1212 let height = advance_height - (top_side_bearing + bottom_side_bearing);
1213
1214 Ok(Bounds {
1215 origin: Point {
1216 x: left_side_bearing as f32,
1217 y: y_offset as f32,
1218 },
1219 size: Size {
1220 width: width as f32,
1221 height: height as f32,
1222 },
1223 })
1224 }
1225 }
1226
1227 fn get_advance(&self, font_id: FontId, glyph_id: GlyphId) -> Result<Size<f32>> {
1228 unsafe {
1229 let font = &self.fonts[font_id.0].font_face;
1230 let glyph_indices = [glyph_id.0 as u16];
1231 let mut metrics = [DWRITE_GLYPH_METRICS::default()];
1232 font.GetDesignGlyphMetrics(glyph_indices.as_ptr(), 1, metrics.as_mut_ptr(), false)?;
1233
1234 let metrics = &metrics[0];
1235
1236 Ok(Size {
1237 width: metrics.advanceWidth as f32,
1238 height: 0.0,
1239 })
1240 }
1241 }
1242
1243 fn all_font_names(&self, components: &DirectWriteComponents) -> Vec<String> {
1244 let mut result =
1245 get_font_names_from_collection(&self.system_font_collection, &components.locale);
1246 result.extend(get_font_names_from_collection(
1247 &self.custom_font_collection,
1248 &components.locale,
1249 ));
1250 result
1251 }
1252
1253 fn handle_gpu_lost(&mut self, directx_devices: &DirectXDevices) -> Result<()> {
1254 try_to_recover_from_device_lost(|| {
1255 GPUState::new(directx_devices).context("Recreating GPU state for DirectWrite")
1256 })
1257 .map(|gpu_state| self.gpu_state = gpu_state)
1258 }
1259}
1260
1261struct GlyphLayerTexture {
1262 run_color: Rgba,
1263 bounds: Bounds<i32>,
1264 texture_view: ID3D11ShaderResourceView,
1265 // holding on to the texture to not RAII drop it
1266 _texture: ID3D11Texture2D,
1267}
1268
1269impl GlyphLayerTexture {
1270 fn new(
1271 gpu_state: &GPUState,
1272 run_color: Rgba,
1273 bounds: Bounds<i32>,
1274 alpha_data: &[u8],
1275 ) -> Result<Self> {
1276 let texture_size = bounds.size;
1277
1278 let desc = D3D11_TEXTURE2D_DESC {
1279 Width: texture_size.width as u32,
1280 Height: texture_size.height as u32,
1281 MipLevels: 1,
1282 ArraySize: 1,
1283 Format: DXGI_FORMAT_R8_UNORM,
1284 SampleDesc: DXGI_SAMPLE_DESC {
1285 Count: 1,
1286 Quality: 0,
1287 },
1288 Usage: D3D11_USAGE_DEFAULT,
1289 BindFlags: D3D11_BIND_SHADER_RESOURCE.0 as u32,
1290 CPUAccessFlags: 0,
1291 MiscFlags: 0,
1292 };
1293
1294 let texture = {
1295 let mut texture: Option<ID3D11Texture2D> = None;
1296 unsafe {
1297 gpu_state
1298 .device
1299 .CreateTexture2D(&desc, None, Some(&mut texture))?
1300 };
1301 texture.unwrap()
1302 };
1303 let texture_view = {
1304 let mut view: Option<ID3D11ShaderResourceView> = None;
1305 unsafe {
1306 gpu_state
1307 .device
1308 .CreateShaderResourceView(&texture, None, Some(&mut view))?
1309 };
1310 view.unwrap()
1311 };
1312
1313 unsafe {
1314 gpu_state.device_context.UpdateSubresource(
1315 &texture,
1316 0,
1317 None,
1318 alpha_data.as_ptr() as _,
1319 texture_size.width as u32,
1320 0,
1321 )
1322 };
1323
1324 Ok(GlyphLayerTexture {
1325 run_color,
1326 bounds,
1327 texture_view,
1328 _texture: texture,
1329 })
1330 }
1331}
1332
1333#[repr(C)]
1334struct GlyphLayerTextureParams {
1335 bounds: Bounds<i32>,
1336 run_color: Rgba,
1337 gamma_ratios: [f32; 4],
1338 grayscale_enhanced_contrast: f32,
1339 _pad: [f32; 3],
1340}
1341
1342struct TextRendererWrapper(IDWriteTextRenderer);
1343
1344impl TextRendererWrapper {
1345 fn new(locale_str: HSTRING) -> Self {
1346 let inner = TextRenderer::new(locale_str);
1347 TextRendererWrapper(inner.into())
1348 }
1349}
1350
1351#[implement(IDWriteTextRenderer)]
1352struct TextRenderer {
1353 locale: HSTRING,
1354}
1355
1356impl TextRenderer {
1357 fn new(locale: HSTRING) -> Self {
1358 TextRenderer { locale }
1359 }
1360}
1361
1362struct RendererContext<'t, 'a, 'b> {
1363 text_system: &'t mut DirectWriteState,
1364 components: &'a DirectWriteComponents,
1365 index_converter: StringIndexConverter<'a>,
1366 runs: &'b mut Vec<ShapedRun>,
1367 width: f32,
1368}
1369
1370#[derive(Debug)]
1371struct ClusterAnalyzer<'t> {
1372 utf16_idx: usize,
1373 glyph_idx: usize,
1374 glyph_count: usize,
1375 cluster_map: &'t [u16],
1376}
1377
1378impl<'t> ClusterAnalyzer<'t> {
1379 fn new(cluster_map: &'t [u16], glyph_count: usize) -> Self {
1380 ClusterAnalyzer {
1381 utf16_idx: 0,
1382 glyph_idx: 0,
1383 glyph_count,
1384 cluster_map,
1385 }
1386 }
1387}
1388
1389impl Iterator for ClusterAnalyzer<'_> {
1390 type Item = (usize, usize);
1391
1392 fn next(&mut self) -> Option<(usize, usize)> {
1393 if self.utf16_idx >= self.cluster_map.len() {
1394 return None; // No more clusters
1395 }
1396 let start_utf16_idx = self.utf16_idx;
1397 let current_glyph = self.cluster_map[start_utf16_idx] as usize;
1398
1399 // Find the end of current cluster (where glyph index changes)
1400 let mut end_utf16_idx = start_utf16_idx + 1;
1401 while end_utf16_idx < self.cluster_map.len()
1402 && self.cluster_map[end_utf16_idx] as usize == current_glyph
1403 {
1404 end_utf16_idx += 1;
1405 }
1406
1407 let utf16_len = end_utf16_idx - start_utf16_idx;
1408
1409 // Calculate glyph count for this cluster
1410 let next_glyph = if end_utf16_idx < self.cluster_map.len() {
1411 self.cluster_map[end_utf16_idx] as usize
1412 } else {
1413 self.glyph_count
1414 };
1415
1416 let glyph_count = next_glyph - current_glyph;
1417
1418 // Update state for next call
1419 self.utf16_idx = end_utf16_idx;
1420 self.glyph_idx = next_glyph;
1421
1422 Some((utf16_len, glyph_count))
1423 }
1424}
1425
1426#[allow(non_snake_case)]
1427impl IDWritePixelSnapping_Impl for TextRenderer_Impl {
1428 fn IsPixelSnappingDisabled(
1429 &self,
1430 _clientdrawingcontext: *const ::core::ffi::c_void,
1431 ) -> windows::core::Result<BOOL> {
1432 Ok(BOOL(0))
1433 }
1434
1435 fn GetCurrentTransform(
1436 &self,
1437 _clientdrawingcontext: *const ::core::ffi::c_void,
1438 transform: *mut DWRITE_MATRIX,
1439 ) -> windows::core::Result<()> {
1440 unsafe {
1441 *transform = DWRITE_MATRIX {
1442 m11: 1.0,
1443 m12: 0.0,
1444 m21: 0.0,
1445 m22: 1.0,
1446 dx: 0.0,
1447 dy: 0.0,
1448 };
1449 }
1450 Ok(())
1451 }
1452
1453 fn GetPixelsPerDip(
1454 &self,
1455 _clientdrawingcontext: *const ::core::ffi::c_void,
1456 ) -> windows::core::Result<f32> {
1457 Ok(1.0)
1458 }
1459}
1460
1461#[allow(non_snake_case)]
1462impl IDWriteTextRenderer_Impl for TextRenderer_Impl {
1463 fn DrawGlyphRun(
1464 &self,
1465 clientdrawingcontext: *const ::core::ffi::c_void,
1466 _baselineoriginx: f32,
1467 _baselineoriginy: f32,
1468 _measuringmode: DWRITE_MEASURING_MODE,
1469 glyphrun: *const DWRITE_GLYPH_RUN,
1470 glyphrundescription: *const DWRITE_GLYPH_RUN_DESCRIPTION,
1471 _clientdrawingeffect: windows::core::Ref<windows::core::IUnknown>,
1472 ) -> windows::core::Result<()> {
1473 let glyphrun = unsafe { &*glyphrun };
1474 let glyph_count = glyphrun.glyphCount as usize;
1475 if glyph_count == 0 {
1476 return Ok(());
1477 }
1478 let desc = unsafe { &*glyphrundescription };
1479 let context = unsafe { &mut *(clientdrawingcontext.cast::<RendererContext>().cast_mut()) };
1480 let Some(font_face) = glyphrun.fontFace.as_ref() else {
1481 return Ok(());
1482 };
1483 // This `cast()` action here should never fail since we are running on Win10+, and
1484 // `IDWriteFontFace3` requires Win10
1485 let Ok(font_face) = &font_face.cast::<IDWriteFontFace3>() else {
1486 return Err(Error::new(
1487 DWRITE_E_UNSUPPORTEDOPERATION,
1488 "Failed to cast font face",
1489 ));
1490 };
1491
1492 let font_face_key = font_face.cast::<IUnknown>().unwrap().as_raw().addr();
1493 let font_id = context
1494 .text_system
1495 .font_info_cache
1496 .get(&font_face_key)
1497 .copied()
1498 // in some circumstances, we might be getting served a FontFace that we did not create ourselves
1499 // so create a new font from it and cache it accordingly. The usual culprit here seems to be Segoe UI Symbol
1500 .map_or_else(
1501 || {
1502 let font = font_face_to_font(font_face, &self.locale)
1503 .ok_or_else(|| Error::new(DWRITE_E_NOFONT, "Failed to create font"))?;
1504 let font_id = match context.text_system.font_to_font_id.get(&font) {
1505 Some(&font_id) => font_id,
1506 None => context
1507 .text_system
1508 .select_and_cache_font(context.components, &font)
1509 .ok_or_else(|| Error::new(DWRITE_E_NOFONT, "Failed to create font"))?,
1510 };
1511 context
1512 .text_system
1513 .font_info_cache
1514 .insert(font_face_key, font_id);
1515 windows::core::Result::Ok(font_id)
1516 },
1517 Ok,
1518 )?;
1519
1520 let color_font = unsafe { font_face.IsColorFont().as_bool() };
1521
1522 let glyph_ids = unsafe { std::slice::from_raw_parts(glyphrun.glyphIndices, glyph_count) };
1523 let glyph_advances =
1524 unsafe { std::slice::from_raw_parts(glyphrun.glyphAdvances, glyph_count) };
1525 let glyph_offsets =
1526 unsafe { std::slice::from_raw_parts(glyphrun.glyphOffsets, glyph_count) };
1527 let cluster_map =
1528 unsafe { std::slice::from_raw_parts(desc.clusterMap, desc.stringLength as usize) };
1529
1530 let cluster_analyzer = ClusterAnalyzer::new(cluster_map, glyph_count);
1531 let mut utf16_idx = desc.textPosition as usize;
1532 let mut glyph_idx = 0;
1533 let mut glyphs = Vec::with_capacity(glyph_count);
1534 for (cluster_utf16_len, cluster_glyph_count) in cluster_analyzer {
1535 context.index_converter.advance_to_utf16_ix(utf16_idx);
1536 utf16_idx += cluster_utf16_len;
1537 for (cluster_glyph_idx, glyph_id) in glyph_ids
1538 [glyph_idx..(glyph_idx + cluster_glyph_count)]
1539 .iter()
1540 .enumerate()
1541 {
1542 let id = GlyphId(*glyph_id as u32);
1543 let is_emoji =
1544 color_font && is_color_glyph(font_face, id, &context.components.factory);
1545 let this_glyph_idx = glyph_idx + cluster_glyph_idx;
1546 glyphs.push(ShapedGlyph {
1547 id,
1548 position: point(
1549 px(context.width + glyph_offsets[this_glyph_idx].advanceOffset),
1550 px(-glyph_offsets[this_glyph_idx].ascenderOffset),
1551 ),
1552 index: context.index_converter.utf8_ix,
1553 is_emoji,
1554 });
1555 context.width += glyph_advances[this_glyph_idx];
1556 }
1557 glyph_idx += cluster_glyph_count;
1558 }
1559 context.runs.push(ShapedRun { font_id, glyphs });
1560 Ok(())
1561 }
1562
1563 fn DrawUnderline(
1564 &self,
1565 _clientdrawingcontext: *const ::core::ffi::c_void,
1566 _baselineoriginx: f32,
1567 _baselineoriginy: f32,
1568 _underline: *const DWRITE_UNDERLINE,
1569 _clientdrawingeffect: windows::core::Ref<windows::core::IUnknown>,
1570 ) -> windows::core::Result<()> {
1571 Err(windows::core::Error::new(
1572 E_NOTIMPL,
1573 "DrawUnderline unimplemented",
1574 ))
1575 }
1576
1577 fn DrawStrikethrough(
1578 &self,
1579 _clientdrawingcontext: *const ::core::ffi::c_void,
1580 _baselineoriginx: f32,
1581 _baselineoriginy: f32,
1582 _strikethrough: *const DWRITE_STRIKETHROUGH,
1583 _clientdrawingeffect: windows::core::Ref<windows::core::IUnknown>,
1584 ) -> windows::core::Result<()> {
1585 Err(windows::core::Error::new(
1586 E_NOTIMPL,
1587 "DrawStrikethrough unimplemented",
1588 ))
1589 }
1590
1591 fn DrawInlineObject(
1592 &self,
1593 _clientdrawingcontext: *const ::core::ffi::c_void,
1594 _originx: f32,
1595 _originy: f32,
1596 _inlineobject: windows::core::Ref<IDWriteInlineObject>,
1597 _issideways: BOOL,
1598 _isrighttoleft: BOOL,
1599 _clientdrawingeffect: windows::core::Ref<windows::core::IUnknown>,
1600 ) -> windows::core::Result<()> {
1601 Err(windows::core::Error::new(
1602 E_NOTIMPL,
1603 "DrawInlineObject unimplemented",
1604 ))
1605 }
1606}
1607
1608struct StringIndexConverter<'a> {
1609 text: &'a str,
1610 utf8_ix: usize,
1611 utf16_ix: usize,
1612}
1613
1614impl<'a> StringIndexConverter<'a> {
1615 fn new(text: &'a str) -> Self {
1616 Self {
1617 text,
1618 utf8_ix: 0,
1619 utf16_ix: 0,
1620 }
1621 }
1622
1623 #[allow(dead_code)]
1624 fn advance_to_utf8_ix(&mut self, utf8_target: usize) {
1625 for (ix, c) in self.text[self.utf8_ix..].char_indices() {
1626 if self.utf8_ix + ix >= utf8_target {
1627 self.utf8_ix += ix;
1628 return;
1629 }
1630 self.utf16_ix += c.len_utf16();
1631 }
1632 self.utf8_ix = self.text.len();
1633 }
1634
1635 fn advance_to_utf16_ix(&mut self, utf16_target: usize) {
1636 for (ix, c) in self.text[self.utf8_ix..].char_indices() {
1637 if self.utf16_ix >= utf16_target {
1638 self.utf8_ix += ix;
1639 return;
1640 }
1641 self.utf16_ix += c.len_utf16();
1642 }
1643 self.utf8_ix = self.text.len();
1644 }
1645}
1646
1647fn font_style_to_dwrite(style: FontStyle) -> DWRITE_FONT_STYLE {
1648 match style {
1649 FontStyle::Normal => DWRITE_FONT_STYLE_NORMAL,
1650 FontStyle::Italic => DWRITE_FONT_STYLE_ITALIC,
1651 FontStyle::Oblique => DWRITE_FONT_STYLE_OBLIQUE,
1652 }
1653}
1654
1655fn font_style_from_dwrite(value: DWRITE_FONT_STYLE) -> FontStyle {
1656 match value.0 {
1657 0 => FontStyle::Normal,
1658 1 => FontStyle::Italic,
1659 2 => FontStyle::Oblique,
1660 _ => unreachable!(),
1661 }
1662}
1663
1664fn font_weight_to_dwrite(weight: FontWeight) -> DWRITE_FONT_WEIGHT {
1665 DWRITE_FONT_WEIGHT(weight.0 as i32)
1666}
1667
1668fn font_weight_from_dwrite(value: DWRITE_FONT_WEIGHT) -> FontWeight {
1669 FontWeight(value.0 as f32)
1670}
1671
1672fn get_font_names_from_collection(
1673 collection: &IDWriteFontCollection1,
1674 locale: &HSTRING,
1675) -> Vec<String> {
1676 unsafe {
1677 let mut result = Vec::new();
1678 let family_count = collection.GetFontFamilyCount();
1679 for index in 0..family_count {
1680 let Some(font_family) = collection.GetFontFamily(index).log_err() else {
1681 continue;
1682 };
1683 let Some(localized_family_name) = font_family.GetFamilyNames().log_err() else {
1684 continue;
1685 };
1686 let Some(family_name) = get_name(localized_family_name, locale).log_err() else {
1687 continue;
1688 };
1689 result.push(family_name);
1690 }
1691
1692 result
1693 }
1694}
1695
1696fn font_face_to_font(font_face: &IDWriteFontFace3, locale: &HSTRING) -> Option<Font> {
1697 let localized_family_name = unsafe { font_face.GetFamilyNames().log_err() }?;
1698 let family_name = get_name(localized_family_name, locale).log_err()?;
1699 let weight = unsafe { font_face.GetWeight() };
1700 let style = unsafe { font_face.GetStyle() };
1701 Some(Font {
1702 family: family_name.into(),
1703 features: FontFeatures::default(),
1704 weight: font_weight_from_dwrite(weight),
1705 style: font_style_from_dwrite(style),
1706 fallbacks: None,
1707 })
1708}
1709
1710// https://learn.microsoft.com/en-us/windows/win32/api/dwrite/ne-dwrite-dwrite_font_feature_tag
1711fn apply_font_features(
1712 direct_write_features: &IDWriteTypography,
1713 features: &FontFeatures,
1714) -> Result<()> {
1715 let tag_values = features.tag_value_list();
1716 if tag_values.is_empty() {
1717 return Ok(());
1718 }
1719
1720 // All of these features are enabled by default by DirectWrite.
1721 // If you want to (and can) peek into the source of DirectWrite
1722 let mut feature_liga = make_direct_write_feature("liga", 1);
1723 let mut feature_clig = make_direct_write_feature("clig", 1);
1724 let mut feature_calt = make_direct_write_feature("calt", 1);
1725
1726 for (tag, value) in tag_values {
1727 if tag.as_str() == "liga" && *value == 0 {
1728 feature_liga.parameter = 0;
1729 continue;
1730 }
1731 if tag.as_str() == "clig" && *value == 0 {
1732 feature_clig.parameter = 0;
1733 continue;
1734 }
1735 if tag.as_str() == "calt" && *value == 0 {
1736 feature_calt.parameter = 0;
1737 continue;
1738 }
1739
1740 unsafe {
1741 direct_write_features.AddFontFeature(make_direct_write_feature(tag, *value))?;
1742 }
1743 }
1744 unsafe {
1745 direct_write_features.AddFontFeature(feature_liga)?;
1746 direct_write_features.AddFontFeature(feature_clig)?;
1747 direct_write_features.AddFontFeature(feature_calt)?;
1748 }
1749
1750 Ok(())
1751}
1752
1753#[inline]
1754const fn make_direct_write_feature(feature_name: &str, parameter: u32) -> DWRITE_FONT_FEATURE {
1755 let tag = make_direct_write_tag(feature_name);
1756 DWRITE_FONT_FEATURE {
1757 nameTag: tag,
1758 parameter,
1759 }
1760}
1761
1762#[inline]
1763const fn make_open_type_tag(tag_name: &str) -> u32 {
1764 let bytes = tag_name.as_bytes();
1765 debug_assert!(bytes.len() == 4);
1766 u32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]])
1767}
1768
1769#[inline]
1770const fn make_direct_write_tag(tag_name: &str) -> DWRITE_FONT_FEATURE_TAG {
1771 DWRITE_FONT_FEATURE_TAG(make_open_type_tag(tag_name))
1772}
1773
1774#[inline]
1775fn get_name(string: IDWriteLocalizedStrings, locale: &HSTRING) -> Result<String> {
1776 let mut locale_name_index = 0u32;
1777 let mut exists = BOOL(0);
1778 unsafe { string.FindLocaleName(locale, &mut locale_name_index, &mut exists as _)? };
1779 if !exists.as_bool() {
1780 unsafe {
1781 string.FindLocaleName(
1782 DEFAULT_LOCALE_NAME,
1783 &mut locale_name_index as _,
1784 &mut exists as _,
1785 )?
1786 };
1787 anyhow::ensure!(exists.as_bool(), "No localised string for {locale}");
1788 }
1789
1790 let name_length = unsafe { string.GetStringLength(locale_name_index) }? as usize;
1791 let mut name_vec = vec![0u16; name_length + 1];
1792 unsafe {
1793 string.GetString(locale_name_index, &mut name_vec)?;
1794 }
1795
1796 Ok(String::from_utf16_lossy(&name_vec[..name_length]))
1797}
1798
1799fn get_system_subpixel_rendering() -> bool {
1800 let mut value = c_uint::default();
1801 let result = unsafe {
1802 SystemParametersInfoW(
1803 SPI_GETFONTSMOOTHINGTYPE,
1804 0,
1805 Some((&mut value) as *mut c_uint as *mut c_void),
1806 SYSTEM_PARAMETERS_INFO_UPDATE_FLAGS::default(),
1807 )
1808 };
1809 if result.log_err().is_some() {
1810 value == FE_FONTSMOOTHINGCLEARTYPE
1811 } else {
1812 true
1813 }
1814}
1815
1816fn get_system_ui_font_name() -> SharedString {
1817 unsafe {
1818 let mut info: LOGFONTW = std::mem::zeroed();
1819 let font_family = if SystemParametersInfoW(
1820 SPI_GETICONTITLELOGFONT,
1821 std::mem::size_of::<LOGFONTW>() as u32,
1822 Some(&mut info as *mut _ as _),
1823 SYSTEM_PARAMETERS_INFO_UPDATE_FLAGS(0),
1824 )
1825 .log_err()
1826 .is_none()
1827 {
1828 // https://learn.microsoft.com/en-us/windows/win32/uxguide/vis-fonts
1829 // Segoe UI is the Windows font intended for user interface text strings.
1830 "Segoe UI".into()
1831 } else {
1832 let font_name = String::from_utf16_lossy(&info.lfFaceName);
1833 font_name.trim_matches(char::from(0)).to_owned().into()
1834 };
1835 log::info!("Use {} as UI font.", font_family);
1836 font_family
1837 }
1838}
1839
1840// One would think that with newer DirectWrite method: IDWriteFontFace4::GetGlyphImageFormats
1841// but that doesn't seem to work for some glyphs, say โค
1842fn is_color_glyph(
1843 font_face: &IDWriteFontFace3,
1844 glyph_id: GlyphId,
1845 factory: &IDWriteFactory5,
1846) -> bool {
1847 let glyph_run = DWRITE_GLYPH_RUN {
1848 fontFace: ManuallyDrop::new(Some(unsafe { std::ptr::read(&****font_face) })),
1849 fontEmSize: 14.0,
1850 glyphCount: 1,
1851 glyphIndices: &(glyph_id.0 as u16),
1852 glyphAdvances: &0.0,
1853 glyphOffsets: &DWRITE_GLYPH_OFFSET {
1854 advanceOffset: 0.0,
1855 ascenderOffset: 0.0,
1856 },
1857 isSideways: BOOL(0),
1858 bidiLevel: 0,
1859 };
1860 unsafe {
1861 factory.TranslateColorGlyphRun(
1862 Vector2::default(),
1863 &glyph_run as _,
1864 None,
1865 DWRITE_GLYPH_IMAGE_FORMATS_COLR
1866 | DWRITE_GLYPH_IMAGE_FORMATS_SVG
1867 | DWRITE_GLYPH_IMAGE_FORMATS_PNG
1868 | DWRITE_GLYPH_IMAGE_FORMATS_JPEG
1869 | DWRITE_GLYPH_IMAGE_FORMATS_PREMULTIPLIED_B8G8R8A8,
1870 DWRITE_MEASURING_MODE_NATURAL,
1871 None,
1872 0,
1873 )
1874 }
1875 .is_ok()
1876}
1877
1878const DEFAULT_LOCALE_NAME: PCWSTR = windows::core::w!("en-US");
1879
1880#[cfg(test)]
1881mod tests {
1882 use crate::direct_write::ClusterAnalyzer;
1883
1884 #[test]
1885 fn test_cluster_map() {
1886 let cluster_map = [0];
1887 let mut analyzer = ClusterAnalyzer::new(&cluster_map, 1);
1888 let next = analyzer.next();
1889 assert_eq!(next, Some((1, 1)));
1890 let next = analyzer.next();
1891 assert_eq!(next, None);
1892
1893 let cluster_map = [0, 1, 2];
1894 let mut analyzer = ClusterAnalyzer::new(&cluster_map, 3);
1895 let next = analyzer.next();
1896 assert_eq!(next, Some((1, 1)));
1897 let next = analyzer.next();
1898 assert_eq!(next, Some((1, 1)));
1899 let next = analyzer.next();
1900 assert_eq!(next, Some((1, 1)));
1901 let next = analyzer.next();
1902 assert_eq!(next, None);
1903 // ๐จโ๐ฉโ๐งโ๐ฆ๐ฉโ๐ป
1904 let cluster_map = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4];
1905 let mut analyzer = ClusterAnalyzer::new(&cluster_map, 5);
1906 let next = analyzer.next();
1907 assert_eq!(next, Some((11, 4)));
1908 let next = analyzer.next();
1909 assert_eq!(next, Some((5, 1)));
1910 let next = analyzer.next();
1911 assert_eq!(next, None);
1912 // ๐ฉโ๐ป
1913 let cluster_map = [0, 0, 0, 0, 0];
1914 let mut analyzer = ClusterAnalyzer::new(&cluster_map, 1);
1915 let next = analyzer.next();
1916 assert_eq!(next, Some((5, 1)));
1917 let next = analyzer.next();
1918 assert_eq!(next, None);
1919 }
1920}