direct_write.rs

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