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            println!("trying to rasterize");
 837            let res = self.rasterize_color(
 838                &glyph_run,
 839                rendering_mode,
 840                measuring_mode,
 841                &transform,
 842                point(baseline_origin_x, baseline_origin_y),
 843                bitmap_size,
 844                size(texture_width, texture_height),
 845            );
 846            // // todo: support more glyph image formats for more exotic fonts, for now it should fallback to monochrome rendering
 847            // let color_enumerator = unsafe {
 848            //     self.components.factory.TranslateColorGlyphRun(
 849            //         Vector2::new(baseline_origin_x, baseline_origin_y),
 850            //         &glyph_run,
 851            //         None,
 852            //         DWRITE_GLYPH_IMAGE_FORMATS_COLR
 853            //             | DWRITE_GLYPH_IMAGE_FORMATS_PREMULTIPLIED_B8G8R8A8,
 854            //         measuring_mode,
 855            //         Some(&transform),
 856            //         0,
 857            //     )
 858            // };
 859
 860            // if let Ok(color_enumerator) = color_enumerator {
 861            //     loop {
 862            //         let color_run = unsafe { color_enumerator.GetCurrentRun() };
 863            //         if let Ok(color_run) = color_run {
 864            //             let color_glyph_run = unsafe { &*color_run };
 865            //             let color_value = color_glyph_run.Base.runColor;
 866
 867            //             // Create analysis for this color layer
 868            //             let color_analysis = unsafe {
 869            //                 self.components.factory.CreateGlyphRunAnalysis(
 870            //                     &color_glyph_run.Base.glyphRun as *const _,
 871            //                     Some(&transform),
 872            //                     rendering_mode,
 873            //                     measuring_mode,
 874            //                     DWRITE_GRID_FIT_MODE_DEFAULT,
 875            //                     DWRITE_TEXT_ANTIALIAS_MODE_CLEARTYPE,
 876            //                     baseline_origin_x,
 877            //                     baseline_origin_y,
 878            //                 )
 879            //             };
 880
 881            //             // todo: move this block completely to the gpu
 882            //             // this is important because fonts can bundle quite large icons
 883            //             // and compositing them on the cpu is quite expensive
 884            //             // also the code is ugly
 885            //             if let Ok(color_analysis) = color_analysis {
 886            //                 let color_bounds =
 887            //                     unsafe { color_analysis.GetAlphaTextureBounds(texture_type) };
 888            //                 if let Ok(color_bounds) = color_bounds {
 889            //                     let color_width = (color_bounds.right - color_bounds.left) as u32;
 890            //                     let color_height = (color_bounds.bottom - color_bounds.top) as u32;
 891
 892            //                     if color_width > 0 && color_height > 0 {
 893            //                         let mut alpha_data =
 894            //                             vec![0u8; (color_width * color_height * 3) as usize];
 895            //                         if unsafe {
 896            //                             color_analysis.CreateAlphaTexture(
 897            //                                 texture_type,
 898            //                                 &color_bounds,
 899            //                                 &mut alpha_data,
 900            //                             )
 901            //                         }
 902            //                         .is_ok()
 903            //                         {
 904            //                             let r = (color_value.r * 255.0) as u8;
 905            //                             let g = (color_value.g * 255.0) as u8;
 906            //                             let b = (color_value.b * 255.0) as u8;
 907            //                             let a = (color_value.a * 255.0) as u8;
 908
 909            //                             let offset_x = color_bounds.left.max(0) as usize;
 910            //                             let offset_y = color_bounds.top.max(0) as usize;
 911
 912            //                             for y in 0..color_height as usize {
 913            //                                 for x in 0..color_width as usize {
 914            //                                     let bitmap_x = offset_x + x;
 915            //                                     let bitmap_y = offset_y + y;
 916
 917            //                                     if bitmap_x < bitmap_size.width.0 as usize
 918            //                                         && bitmap_y < bitmap_size.height.0 as usize
 919            //                                     {
 920            //                                         let alpha_idx =
 921            //                                             (y * color_width as usize + x) * 3;
 922            //                                         let bitmap_idx = (bitmap_y
 923            //                                             * bitmap_size.width.0 as usize
 924            //                                             + bitmap_x)
 925            //                                             * 4;
 926
 927            //                                         if alpha_idx + 2 < alpha_data.len()
 928            //                                             && bitmap_idx + 3 < bitmap_data.len()
 929            //                                         {
 930            //                                             let alpha_value = (alpha_data[alpha_idx]
 931            //                                                 as u32
 932            //                                                 + alpha_data[alpha_idx + 1] as u32
 933            //                                                 + alpha_data[alpha_idx + 2] as u32)
 934            //                                                 / 3;
 935            //                                             let final_alpha =
 936            //                                                 ((alpha_value * a as u32) / 255) as u8;
 937
 938            //                                             if final_alpha > 0 {
 939            //                                                 let existing_r =
 940            //                                                     bitmap_data[bitmap_idx];
 941            //                                                 let existing_g =
 942            //                                                     bitmap_data[bitmap_idx + 1];
 943            //                                                 let existing_b =
 944            //                                                     bitmap_data[bitmap_idx + 2];
 945            //                                                 let existing_a =
 946            //                                                     bitmap_data[bitmap_idx + 3];
 947
 948            //                                                 let src_alpha =
 949            //                                                     final_alpha as f32 / 255.0;
 950            //                                                 let dst_alpha =
 951            //                                                     existing_a as f32 / 255.0;
 952            //                                                 let out_alpha = src_alpha
 953            //                                                     + dst_alpha * (1.0 - src_alpha);
 954
 955            //                                                 if out_alpha > 0.0 {
 956            //                                                     bitmap_data[bitmap_idx] =
 957            //                                                         ((r as f32 * src_alpha
 958            //                                                             + existing_r as f32
 959            //                                                                 * dst_alpha
 960            //                                                                 * (1.0 - src_alpha))
 961            //                                                             / out_alpha)
 962            //                                                             as u8;
 963            //                                                     bitmap_data[bitmap_idx + 1] =
 964            //                                                         ((g as f32 * src_alpha
 965            //                                                             + existing_g as f32
 966            //                                                                 * dst_alpha
 967            //                                                                 * (1.0 - src_alpha))
 968            //                                                             / out_alpha)
 969            //                                                             as u8;
 970            //                                                     bitmap_data[bitmap_idx + 2] =
 971            //                                                         ((b as f32 * src_alpha
 972            //                                                             + existing_b as f32
 973            //                                                                 * dst_alpha
 974            //                                                                 * (1.0 - src_alpha))
 975            //                                                             / out_alpha)
 976            //                                                             as u8;
 977            //                                                     bitmap_data[bitmap_idx + 3] =
 978            //                                                         (out_alpha * 255.0) as u8;
 979            //                                                 }
 980            //                                             }
 981            //                                         }
 982            //                                     }
 983            //                                 }
 984            //                             }
 985            //                         }
 986            //                     }
 987            //                 }
 988            //             }
 989            //         }
 990
 991            //         if !unsafe { color_enumerator.MoveNext() }?.as_bool() {
 992            //             break;
 993            //         }
 994            //     }
 995
 996            //     // bitmap_data.chunks_mut(4).for_each(|chunk| {
 997            //     //     let tmp = chunk[2];
 998            //     //     chunk[2] = chunk[0];
 999            //     //     chunk[0] = tmp;
1000            //     // });
1001
1002            //     std::fs::write(
1003            //         &format!(
1004            //             "{}x{}_{}_color.raw",
1005            //             texture_width, texture_height, params.glyph_id.0
1006            //         ),
1007            //         &bitmap_data,
1008            //     )
1009            //     .unwrap();
1010            // } else {
1011            //     let monochrome_data = Self::rasterize_monochrome(
1012            //         &glyph_analysis,
1013            //         bitmap_size,
1014            //         size(texture_width, texture_height),
1015            //         &texture_bounds,
1016            //     )?;
1017            //     // todo: monochrome emojis should be handled gracefully by the renderer
1018            //     // currently they just get drawn as their reported color because it assumes they are always colored
1019            //     // but in reality monochrome emojis should be colored the same as text is
1020            //     bitmap_data = monochrome_data
1021            //         .into_iter()
1022            //         .flat_map(|e| [0, 0, 0, e])
1023            //         .collect::<Vec<u8>>();
1024            // }
1025        } else {
1026            bitmap_data = Self::rasterize_monochrome(
1027                &glyph_analysis,
1028                bitmap_size,
1029                size(texture_width, texture_height),
1030                &texture_bounds,
1031            )?;
1032        }
1033
1034        Ok((bitmap_size, bitmap_data))
1035    }
1036
1037    fn rasterize_monochrome(
1038        glyph_analysis: &IDWriteGlyphRunAnalysis,
1039        bitmap_size: Size<DevicePixels>,
1040        texture_size: Size<u32>,
1041        texture_bounds: &RECT,
1042    ) -> Result<Vec<u8>> {
1043        let mut bitmap_data =
1044            vec![0u8; bitmap_size.width.0 as usize * bitmap_size.height.0 as usize];
1045
1046        let mut alpha_data = vec![0u8; (texture_size.width * texture_size.height * 3) as usize];
1047        unsafe {
1048            glyph_analysis.CreateAlphaTexture(
1049                DWRITE_TEXTURE_CLEARTYPE_3x1,
1050                texture_bounds,
1051                &mut alpha_data,
1052            )?;
1053        }
1054
1055        // Convert ClearType RGB data to grayscale and place in bitmap
1056        let offset_x = texture_bounds.left.max(0) as usize;
1057        let offset_y = texture_bounds.top.max(0) as usize;
1058
1059        for y in 0..texture_size.height as usize {
1060            for x in 0..texture_size.width as usize {
1061                let bitmap_x = offset_x + x;
1062                let bitmap_y = offset_y + y;
1063
1064                if bitmap_x < bitmap_size.width.0 as usize
1065                    && bitmap_y < bitmap_size.height.0 as usize
1066                {
1067                    let texture_idx = (y * texture_size.width as usize + x) * 3;
1068                    let bitmap_idx = bitmap_y * bitmap_size.width.0 as usize + bitmap_x;
1069
1070                    if texture_idx + 2 < alpha_data.len() && bitmap_idx < bitmap_data.len() {
1071                        let avg = (alpha_data[texture_idx] as u32
1072                            + alpha_data[texture_idx + 1] as u32
1073                            + alpha_data[texture_idx + 2] as u32)
1074                            / 3;
1075                        bitmap_data[bitmap_idx] = avg as u8;
1076                    }
1077                }
1078            }
1079        }
1080
1081        Ok(bitmap_data)
1082    }
1083
1084    fn rasterize_color(
1085        &self,
1086        glyph_run: &DWRITE_GLYPH_RUN,
1087        rendering_mode: DWRITE_RENDERING_MODE1,
1088        measuring_mode: DWRITE_MEASURING_MODE,
1089        transform: &DWRITE_MATRIX,
1090        baseline_origin: Point<f32>,
1091        bitmap_size: Size<DevicePixels>,
1092        texture_size: Size<u32>,
1093    ) -> Result<Vec<u8>> {
1094        // todo: support formats other than COLR
1095        let color_enumerator = unsafe {
1096            self.components.factory.TranslateColorGlyphRun(
1097                Vector2::new(baseline_origin.x, baseline_origin.y),
1098                glyph_run,
1099                None,
1100                DWRITE_GLYPH_IMAGE_FORMATS_COLR,
1101                measuring_mode,
1102                Some(transform),
1103                0,
1104            )
1105        }?;
1106
1107        let mut glyph_layers = Vec::new();
1108        loop {
1109            let color_run = unsafe { color_enumerator.GetCurrentRun() }?;
1110            let color_run = unsafe { &*color_run };
1111            let image_format = color_run.glyphImageFormat & !DWRITE_GLYPH_IMAGE_FORMATS_TRUETYPE;
1112            if image_format == DWRITE_GLYPH_IMAGE_FORMATS_COLR {
1113                let color_analysis = unsafe {
1114                    self.components.factory.CreateGlyphRunAnalysis(
1115                        &color_run.Base.glyphRun as *const _,
1116                        Some(transform),
1117                        rendering_mode,
1118                        measuring_mode,
1119                        DWRITE_GRID_FIT_MODE_DEFAULT,
1120                        DWRITE_TEXT_ANTIALIAS_MODE_CLEARTYPE,
1121                        baseline_origin.x,
1122                        baseline_origin.y,
1123                    )
1124                }?;
1125
1126                let color_bounds =
1127                    unsafe { color_analysis.GetAlphaTextureBounds(DWRITE_TEXTURE_CLEARTYPE_3x1) }?;
1128
1129                let color_size = size(
1130                    color_bounds.right - color_bounds.left,
1131                    color_bounds.bottom - color_bounds.top,
1132                );
1133                if color_size.width > 0 && color_size.height > 0 {
1134                    let mut alpha_data =
1135                        vec![0u8; (color_size.width * color_size.height * 3) as usize];
1136                    unsafe {
1137                        color_analysis.CreateAlphaTexture(
1138                            DWRITE_TEXTURE_CLEARTYPE_3x1,
1139                            &color_bounds,
1140                            &mut alpha_data,
1141                        )
1142                    }?;
1143
1144                    let run_color = {
1145                        let run_color = color_run.Base.runColor;
1146                        Rgba {
1147                            r: run_color.r,
1148                            g: run_color.g,
1149                            b: run_color.b,
1150                            a: run_color.a,
1151                        }
1152                    };
1153                    let bounds = bounds(point(color_bounds.left, color_bounds.top), color_size);
1154                    let alpha_data = alpha_data
1155                        .chunks_exact(3)
1156                        .flat_map(|chunk| [chunk[0], chunk[1], chunk[2], 255])
1157                        .collect::<Vec<_>>();
1158                    glyph_layers.push(GlyphLayerTexture::new(
1159                        &self.gpu_state,
1160                        run_color,
1161                        bounds,
1162                        &alpha_data,
1163                    )?);
1164                }
1165            }
1166
1167            let has_next = unsafe { color_enumerator.MoveNext() }
1168                .map(|e| e.as_bool())
1169                .unwrap_or(false);
1170            if !has_next {
1171                break;
1172            }
1173        }
1174
1175        let params_buffer = {
1176            let desc = D3D11_BUFFER_DESC {
1177                ByteWidth: std::mem::size_of::<GlyphLayerTextureParams>() as u32,
1178                Usage: D3D11_USAGE_DYNAMIC,
1179                BindFlags: D3D11_BIND_CONSTANT_BUFFER.0 as u32,
1180                CPUAccessFlags: D3D11_CPU_ACCESS_WRITE.0 as u32,
1181                MiscFlags: 0,
1182                StructureByteStride: 0,
1183            };
1184
1185            let mut buffer = None;
1186            unsafe {
1187                self.gpu_state
1188                    .device
1189                    .CreateBuffer(&desc, None, Some(&mut buffer))
1190            }?;
1191            [buffer]
1192        };
1193
1194        let vertex_shader = {
1195            let source =
1196                shader_resources::build_shader_blob("color_text_raster", "vertex", "vs_5_0")?;
1197            let bytes = unsafe {
1198                std::slice::from_raw_parts(
1199                    source.GetBufferPointer() as *mut u8,
1200                    source.GetBufferSize(),
1201                )
1202            };
1203            let mut shader = None;
1204            unsafe {
1205                self.gpu_state
1206                    .device
1207                    .CreateVertexShader(bytes, None, Some(&mut shader))
1208            }?;
1209            shader.unwrap()
1210        };
1211
1212        let render_target_texture = {
1213            let mut texture = None;
1214            let desc = D3D11_TEXTURE2D_DESC {
1215                Width: bitmap_size.width.0 as u32,
1216                Height: bitmap_size.height.0 as u32,
1217                MipLevels: 1,
1218                ArraySize: 1,
1219                Format: DXGI_FORMAT_B8G8R8A8_UNORM,
1220                SampleDesc: DXGI_SAMPLE_DESC {
1221                    Count: 1,
1222                    Quality: 0,
1223                },
1224                Usage: D3D11_USAGE_DEFAULT,
1225                BindFlags: D3D11_BIND_RENDER_TARGET.0 as u32,
1226                CPUAccessFlags: 0,
1227                MiscFlags: 0,
1228            };
1229            unsafe {
1230                self.gpu_state
1231                    .device
1232                    .CreateTexture2D(&desc, None, Some(&mut texture))
1233            }?;
1234            texture.unwrap()
1235        };
1236
1237        let render_target_view = {
1238            let desc = D3D11_RENDER_TARGET_VIEW_DESC {
1239                Format: DXGI_FORMAT_B8G8R8A8_UNORM,
1240                ViewDimension: D3D11_RTV_DIMENSION_TEXTURE2D,
1241                Anonymous: D3D11_RENDER_TARGET_VIEW_DESC_0 {
1242                    Texture2D: D3D11_TEX2D_RTV { MipSlice: 0 },
1243                },
1244            };
1245            let mut rtv = None;
1246            unsafe {
1247                self.gpu_state.device.CreateRenderTargetView(
1248                    &render_target_texture,
1249                    Some(&desc),
1250                    Some(&mut rtv),
1251                )
1252            }?;
1253            [rtv]
1254        };
1255
1256        let staging_texture = {
1257            let mut texture = None;
1258            let desc = D3D11_TEXTURE2D_DESC {
1259                Width: bitmap_size.width.0 as u32,
1260                Height: bitmap_size.height.0 as u32,
1261                MipLevels: 1,
1262                ArraySize: 1,
1263                Format: DXGI_FORMAT_B8G8R8A8_UNORM,
1264                SampleDesc: DXGI_SAMPLE_DESC {
1265                    Count: 1,
1266                    Quality: 0,
1267                },
1268                Usage: D3D11_USAGE_STAGING,
1269                BindFlags: 0,
1270                CPUAccessFlags: D3D11_CPU_ACCESS_READ.0 as u32,
1271                MiscFlags: 0,
1272            };
1273            unsafe {
1274                self.gpu_state
1275                    .device
1276                    .CreateTexture2D(&desc, None, Some(&mut texture))
1277            }?;
1278            texture.unwrap()
1279        };
1280
1281        let blend_state = {
1282            let mut blend_state = None;
1283            let desc = D3D11_BLEND_DESC {
1284                AlphaToCoverageEnable: false.into(),
1285                IndependentBlendEnable: false.into(),
1286                RenderTarget: [
1287                    D3D11_RENDER_TARGET_BLEND_DESC {
1288                        BlendEnable: true.into(),
1289                        SrcBlend: D3D11_BLEND_SRC_ALPHA,
1290                        DestBlend: D3D11_BLEND_INV_SRC_ALPHA,
1291                        BlendOp: D3D11_BLEND_OP_ADD,
1292                        SrcBlendAlpha: D3D11_BLEND_ONE,
1293                        DestBlendAlpha: D3D11_BLEND_INV_SRC_ALPHA,
1294                        BlendOpAlpha: D3D11_BLEND_OP_ADD,
1295                        RenderTargetWriteMask: D3D11_COLOR_WRITE_ENABLE_ALL.0 as u8,
1296                    },
1297                    Default::default(),
1298                    Default::default(),
1299                    Default::default(),
1300                    Default::default(),
1301                    Default::default(),
1302                    Default::default(),
1303                    Default::default(),
1304                ],
1305            };
1306            unsafe {
1307                self.gpu_state
1308                    .device
1309                    .CreateBlendState(&desc, Some(&mut blend_state))
1310            }?;
1311            blend_state.unwrap()
1312        };
1313
1314        let sampler = {
1315            let mut sampler = None;
1316            let desc = D3D11_SAMPLER_DESC {
1317                Filter: D3D11_FILTER_MIN_MAG_MIP_POINT,
1318                AddressU: D3D11_TEXTURE_ADDRESS_BORDER,
1319                AddressV: D3D11_TEXTURE_ADDRESS_BORDER,
1320                AddressW: D3D11_TEXTURE_ADDRESS_BORDER,
1321                MipLODBias: 0.0,
1322                MaxAnisotropy: 1,
1323                ComparisonFunc: D3D11_COMPARISON_ALWAYS,
1324                BorderColor: [0.0, 0.0, 0.0, 0.0],
1325                MinLOD: 0.0,
1326                MaxLOD: 0.0,
1327            };
1328            unsafe {
1329                self.gpu_state
1330                    .device
1331                    .CreateSamplerState(&desc, Some(&mut sampler))
1332            }?;
1333            [sampler]
1334        };
1335
1336        let pixel_shader = {
1337            let source =
1338                shader_resources::build_shader_blob("color_text_raster", "pixel", "ps_5_0")?;
1339            let bytes = unsafe {
1340                std::slice::from_raw_parts(
1341                    source.GetBufferPointer() as *mut u8,
1342                    source.GetBufferSize(),
1343                )
1344            };
1345            let mut shader = None;
1346            unsafe {
1347                self.gpu_state
1348                    .device
1349                    .CreatePixelShader(bytes, None, Some(&mut shader))
1350            }?;
1351            shader.unwrap()
1352        };
1353
1354        #[cfg(feature = "enable-renderdoc")]
1355        self.renderdoc
1356            .0
1357            .write()
1358            .start_frame_capture(std::ptr::null(), std::ptr::null());
1359
1360        let device_context = &self.gpu_state.device_context;
1361        unsafe { device_context.IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP) };
1362        unsafe { device_context.VSSetShader(&vertex_shader, None) };
1363        unsafe { device_context.PSSetShader(&pixel_shader, None) };
1364        unsafe { device_context.VSSetConstantBuffers(0, Some(&params_buffer)) };
1365        unsafe { device_context.PSSetConstantBuffers(0, Some(&params_buffer)) };
1366        unsafe { device_context.OMSetRenderTargets(Some(&render_target_view), None) };
1367        unsafe { device_context.PSSetSamplers(0, Some(&sampler)) };
1368        unsafe { device_context.OMSetBlendState(&blend_state, None, 0xffffffff) };
1369
1370        for layer in glyph_layers {
1371            let params = GlyphLayerTextureParams {
1372                run_color: layer.run_color,
1373                bounds: layer.bounds,
1374            };
1375            unsafe {
1376                let mut dest = std::mem::zeroed();
1377                self.gpu_state.device_context.Map(
1378                    params_buffer[0].as_ref().unwrap(),
1379                    0,
1380                    D3D11_MAP_WRITE_DISCARD,
1381                    0,
1382                    Some(&mut dest),
1383                )?;
1384                std::ptr::copy_nonoverlapping(&params as *const _, dest.pData as *mut _, 1);
1385                self.gpu_state
1386                    .device_context
1387                    .Unmap(params_buffer[0].as_ref().unwrap(), 0);
1388            };
1389
1390            let texture = [Some(layer.texture_view)];
1391            unsafe { device_context.PSSetShaderResources(0, Some(&texture)) };
1392
1393            let viewport = [D3D11_VIEWPORT {
1394                TopLeftX: layer.bounds.origin.x as f32,
1395                TopLeftY: layer.bounds.origin.y as f32,
1396                Width: layer.bounds.size.width as f32,
1397                Height: layer.bounds.size.height as f32,
1398                MinDepth: 0.0,
1399                MaxDepth: 1.0,
1400            }];
1401            unsafe { device_context.RSSetViewports(Some(&viewport)) };
1402
1403            unsafe { device_context.Draw(4, 0) };
1404        }
1405
1406        unsafe { device_context.CopyResource(&staging_texture, &render_target_texture) };
1407
1408        let mapped_data = {
1409            let mut mapped_data = D3D11_MAPPED_SUBRESOURCE::default();
1410            unsafe {
1411                device_context.Map(
1412                    &staging_texture,
1413                    0,
1414                    D3D11_MAP_READ,
1415                    0,
1416                    Some(&mut mapped_data),
1417                )
1418            }?;
1419            mapped_data
1420        };
1421        let mut rasterized =
1422            vec![0u8; (bitmap_size.width.0 as u32 * bitmap_size.height.0 as u32 * 4) as usize];
1423
1424        for y in 0..bitmap_size.height.0 as usize {
1425            let width = bitmap_size.width.0 as usize;
1426            unsafe {
1427                std::ptr::copy_nonoverlapping::<u8>(
1428                    (mapped_data.pData as *const u8).byte_add(mapped_data.RowPitch as usize * y),
1429                    rasterized
1430                        .as_mut_ptr()
1431                        .byte_add(width * y * std::mem::size_of::<u32>()),
1432                    width * std::mem::size_of::<u32>(),
1433                )
1434            };
1435        }
1436
1437        #[cfg(feature = "enable-renderdoc")]
1438        self.renderdoc
1439            .0
1440            .write()
1441            .end_frame_capture(std::ptr::null(), std::ptr::null());
1442
1443        println!("render finished");
1444
1445        Ok(rasterized)
1446    }
1447
1448    fn get_typographic_bounds(&self, font_id: FontId, glyph_id: GlyphId) -> Result<Bounds<f32>> {
1449        unsafe {
1450            let font = &self.fonts[font_id.0].font_face;
1451            let glyph_indices = [glyph_id.0 as u16];
1452            let mut metrics = [DWRITE_GLYPH_METRICS::default()];
1453            font.GetDesignGlyphMetrics(glyph_indices.as_ptr(), 1, metrics.as_mut_ptr(), false)?;
1454
1455            let metrics = &metrics[0];
1456            let advance_width = metrics.advanceWidth as i32;
1457            let advance_height = metrics.advanceHeight as i32;
1458            let left_side_bearing = metrics.leftSideBearing;
1459            let right_side_bearing = metrics.rightSideBearing;
1460            let top_side_bearing = metrics.topSideBearing;
1461            let bottom_side_bearing = metrics.bottomSideBearing;
1462            let vertical_origin_y = metrics.verticalOriginY;
1463
1464            let y_offset = vertical_origin_y + bottom_side_bearing - advance_height;
1465            let width = advance_width - (left_side_bearing + right_side_bearing);
1466            let height = advance_height - (top_side_bearing + bottom_side_bearing);
1467
1468            Ok(Bounds {
1469                origin: Point {
1470                    x: left_side_bearing as f32,
1471                    y: y_offset as f32,
1472                },
1473                size: Size {
1474                    width: width as f32,
1475                    height: height as f32,
1476                },
1477            })
1478        }
1479    }
1480
1481    fn get_advance(&self, font_id: FontId, glyph_id: GlyphId) -> Result<Size<f32>> {
1482        unsafe {
1483            let font = &self.fonts[font_id.0].font_face;
1484            let glyph_indices = [glyph_id.0 as u16];
1485            let mut metrics = [DWRITE_GLYPH_METRICS::default()];
1486            font.GetDesignGlyphMetrics(glyph_indices.as_ptr(), 1, metrics.as_mut_ptr(), false)?;
1487
1488            let metrics = &metrics[0];
1489
1490            Ok(Size {
1491                width: metrics.advanceWidth as f32,
1492                height: 0.0,
1493            })
1494        }
1495    }
1496
1497    fn all_font_names(&self) -> Vec<String> {
1498        let mut result =
1499            get_font_names_from_collection(&self.system_font_collection, &self.components.locale);
1500        result.extend(get_font_names_from_collection(
1501            &self.custom_font_collection,
1502            &self.components.locale,
1503        ));
1504        result
1505    }
1506}
1507
1508impl Drop for DirectWriteState {
1509    fn drop(&mut self) {
1510        unsafe {
1511            let _ = self
1512                .components
1513                .factory
1514                .UnregisterFontFileLoader(&self.components.in_memory_loader);
1515        }
1516    }
1517}
1518
1519struct GlyphLayerTexture {
1520    run_color: Rgba,
1521    bounds: Bounds<i32>,
1522    texture: ID3D11Texture2D,
1523    texture_view: ID3D11ShaderResourceView,
1524}
1525
1526impl GlyphLayerTexture {
1527    pub fn new(
1528        gpu_state: &GPUState,
1529        run_color: Rgba,
1530        bounds: Bounds<i32>,
1531        alpha_data: &[u8],
1532    ) -> Result<Self> {
1533        let texture_size = bounds.size;
1534
1535        let desc = D3D11_TEXTURE2D_DESC {
1536            Width: texture_size.width as u32,
1537            Height: texture_size.height as u32,
1538            MipLevels: 1,
1539            ArraySize: 1,
1540            Format: DXGI_FORMAT_R8G8B8A8_UNORM,
1541            SampleDesc: DXGI_SAMPLE_DESC {
1542                Count: 1,
1543                Quality: 0,
1544            },
1545            Usage: D3D11_USAGE_DEFAULT,
1546            BindFlags: D3D11_BIND_SHADER_RESOURCE.0 as u32,
1547            CPUAccessFlags: D3D11_CPU_ACCESS_WRITE.0 as u32,
1548            MiscFlags: 0,
1549        };
1550
1551        let texture = {
1552            let mut texture: Option<ID3D11Texture2D> = None;
1553            unsafe {
1554                gpu_state
1555                    .device
1556                    .CreateTexture2D(&desc, None, Some(&mut texture))?
1557            };
1558            texture.unwrap()
1559        };
1560        let texture_view = {
1561            let mut view: Option<ID3D11ShaderResourceView> = None;
1562            unsafe {
1563                gpu_state
1564                    .device
1565                    .CreateShaderResourceView(&texture, None, Some(&mut view))?
1566            };
1567            view.unwrap()
1568        };
1569
1570        unsafe {
1571            gpu_state.device_context.UpdateSubresource(
1572                &texture,
1573                0,
1574                None,
1575                alpha_data.as_ptr() as _,
1576                (texture_size.width * 4) as u32,
1577                0,
1578            )
1579        };
1580
1581        Ok(GlyphLayerTexture {
1582            run_color,
1583            bounds,
1584            texture,
1585            texture_view,
1586        })
1587    }
1588}
1589
1590#[repr(C)]
1591struct GlyphLayerTextureParams {
1592    bounds: Bounds<i32>,
1593    run_color: Rgba,
1594}
1595
1596struct TextRendererWrapper(pub IDWriteTextRenderer);
1597
1598impl TextRendererWrapper {
1599    pub fn new(locale_str: &str) -> Self {
1600        let inner = TextRenderer::new(locale_str);
1601        TextRendererWrapper(inner.into())
1602    }
1603}
1604
1605#[implement(IDWriteTextRenderer)]
1606struct TextRenderer {
1607    locale: String,
1608}
1609
1610impl TextRenderer {
1611    pub fn new(locale_str: &str) -> Self {
1612        TextRenderer {
1613            locale: locale_str.to_owned(),
1614        }
1615    }
1616}
1617
1618struct RendererContext<'t, 'a, 'b> {
1619    text_system: &'t mut DirectWriteState,
1620    index_converter: StringIndexConverter<'a>,
1621    runs: &'b mut Vec<ShapedRun>,
1622    width: f32,
1623}
1624
1625#[derive(Debug)]
1626struct ClusterAnalyzer<'t> {
1627    utf16_idx: usize,
1628    glyph_idx: usize,
1629    glyph_count: usize,
1630    cluster_map: &'t [u16],
1631}
1632
1633impl<'t> ClusterAnalyzer<'t> {
1634    pub fn new(cluster_map: &'t [u16], glyph_count: usize) -> Self {
1635        ClusterAnalyzer {
1636            utf16_idx: 0,
1637            glyph_idx: 0,
1638            glyph_count,
1639            cluster_map,
1640        }
1641    }
1642}
1643
1644impl Iterator for ClusterAnalyzer<'_> {
1645    type Item = (usize, usize);
1646
1647    fn next(&mut self) -> Option<(usize, usize)> {
1648        if self.utf16_idx >= self.cluster_map.len() {
1649            return None; // No more clusters
1650        }
1651        let start_utf16_idx = self.utf16_idx;
1652        let current_glyph = self.cluster_map[start_utf16_idx] as usize;
1653
1654        // Find the end of current cluster (where glyph index changes)
1655        let mut end_utf16_idx = start_utf16_idx + 1;
1656        while end_utf16_idx < self.cluster_map.len()
1657            && self.cluster_map[end_utf16_idx] as usize == current_glyph
1658        {
1659            end_utf16_idx += 1;
1660        }
1661
1662        let utf16_len = end_utf16_idx - start_utf16_idx;
1663
1664        // Calculate glyph count for this cluster
1665        let next_glyph = if end_utf16_idx < self.cluster_map.len() {
1666            self.cluster_map[end_utf16_idx] as usize
1667        } else {
1668            self.glyph_count
1669        };
1670
1671        let glyph_count = next_glyph - current_glyph;
1672
1673        // Update state for next call
1674        self.utf16_idx = end_utf16_idx;
1675        self.glyph_idx = next_glyph;
1676
1677        Some((utf16_len, glyph_count))
1678    }
1679}
1680
1681#[allow(non_snake_case)]
1682impl IDWritePixelSnapping_Impl for TextRenderer_Impl {
1683    fn IsPixelSnappingDisabled(
1684        &self,
1685        _clientdrawingcontext: *const ::core::ffi::c_void,
1686    ) -> windows::core::Result<BOOL> {
1687        Ok(BOOL(0))
1688    }
1689
1690    fn GetCurrentTransform(
1691        &self,
1692        _clientdrawingcontext: *const ::core::ffi::c_void,
1693        transform: *mut DWRITE_MATRIX,
1694    ) -> windows::core::Result<()> {
1695        unsafe {
1696            *transform = DWRITE_MATRIX {
1697                m11: 1.0,
1698                m12: 0.0,
1699                m21: 0.0,
1700                m22: 1.0,
1701                dx: 0.0,
1702                dy: 0.0,
1703            };
1704        }
1705        Ok(())
1706    }
1707
1708    fn GetPixelsPerDip(
1709        &self,
1710        _clientdrawingcontext: *const ::core::ffi::c_void,
1711    ) -> windows::core::Result<f32> {
1712        Ok(1.0)
1713    }
1714}
1715
1716#[allow(non_snake_case)]
1717impl IDWriteTextRenderer_Impl for TextRenderer_Impl {
1718    fn DrawGlyphRun(
1719        &self,
1720        clientdrawingcontext: *const ::core::ffi::c_void,
1721        _baselineoriginx: f32,
1722        _baselineoriginy: f32,
1723        _measuringmode: DWRITE_MEASURING_MODE,
1724        glyphrun: *const DWRITE_GLYPH_RUN,
1725        glyphrundescription: *const DWRITE_GLYPH_RUN_DESCRIPTION,
1726        _clientdrawingeffect: windows::core::Ref<windows::core::IUnknown>,
1727    ) -> windows::core::Result<()> {
1728        let glyphrun = unsafe { &*glyphrun };
1729        let glyph_count = glyphrun.glyphCount as usize;
1730        if glyph_count == 0 || glyphrun.fontFace.is_none() {
1731            return Ok(());
1732        }
1733        let desc = unsafe { &*glyphrundescription };
1734        let context = unsafe {
1735            &mut *(clientdrawingcontext as *const RendererContext as *mut RendererContext)
1736        };
1737        let font_face = glyphrun.fontFace.as_ref().unwrap();
1738        // This `cast()` action here should never fail since we are running on Win10+, and
1739        // `IDWriteFontFace3` requires Win10
1740        let font_face = &font_face.cast::<IDWriteFontFace3>().unwrap();
1741        let Some((font_identifier, font_struct, color_font)) =
1742            get_font_identifier_and_font_struct(font_face, &self.locale)
1743        else {
1744            return Ok(());
1745        };
1746
1747        let font_id = if let Some(id) = context
1748            .text_system
1749            .font_id_by_identifier
1750            .get(&font_identifier)
1751        {
1752            *id
1753        } else {
1754            context.text_system.select_font(&font_struct)
1755        };
1756
1757        let glyph_ids = unsafe { std::slice::from_raw_parts(glyphrun.glyphIndices, glyph_count) };
1758        let glyph_advances =
1759            unsafe { std::slice::from_raw_parts(glyphrun.glyphAdvances, glyph_count) };
1760        let glyph_offsets =
1761            unsafe { std::slice::from_raw_parts(glyphrun.glyphOffsets, glyph_count) };
1762        let cluster_map =
1763            unsafe { std::slice::from_raw_parts(desc.clusterMap, desc.stringLength as usize) };
1764
1765        let mut cluster_analyzer = ClusterAnalyzer::new(cluster_map, glyph_count);
1766        let mut utf16_idx = desc.textPosition as usize;
1767        let mut glyph_idx = 0;
1768        let mut glyphs = Vec::with_capacity(glyph_count);
1769        for (cluster_utf16_len, cluster_glyph_count) in cluster_analyzer {
1770            context.index_converter.advance_to_utf16_ix(utf16_idx);
1771            utf16_idx += cluster_utf16_len;
1772            for (cluster_glyph_idx, glyph_id) in glyph_ids
1773                [glyph_idx..(glyph_idx + cluster_glyph_count)]
1774                .iter()
1775                .enumerate()
1776            {
1777                let id = GlyphId(*glyph_id as u32);
1778                let is_emoji = color_font
1779                    && is_color_glyph(font_face, id, &context.text_system.components.factory);
1780                let this_glyph_idx = glyph_idx + cluster_glyph_idx;
1781                glyphs.push(ShapedGlyph {
1782                    id,
1783                    position: point(
1784                        px(context.width + glyph_offsets[this_glyph_idx].advanceOffset),
1785                        px(0.0),
1786                    ),
1787                    index: context.index_converter.utf8_ix,
1788                    is_emoji,
1789                });
1790                context.width += glyph_advances[this_glyph_idx];
1791            }
1792            glyph_idx += cluster_glyph_count;
1793        }
1794        context.runs.push(ShapedRun { font_id, glyphs });
1795        Ok(())
1796    }
1797
1798    fn DrawUnderline(
1799        &self,
1800        _clientdrawingcontext: *const ::core::ffi::c_void,
1801        _baselineoriginx: f32,
1802        _baselineoriginy: f32,
1803        _underline: *const DWRITE_UNDERLINE,
1804        _clientdrawingeffect: windows::core::Ref<windows::core::IUnknown>,
1805    ) -> windows::core::Result<()> {
1806        Err(windows::core::Error::new(
1807            E_NOTIMPL,
1808            "DrawUnderline unimplemented",
1809        ))
1810    }
1811
1812    fn DrawStrikethrough(
1813        &self,
1814        _clientdrawingcontext: *const ::core::ffi::c_void,
1815        _baselineoriginx: f32,
1816        _baselineoriginy: f32,
1817        _strikethrough: *const DWRITE_STRIKETHROUGH,
1818        _clientdrawingeffect: windows::core::Ref<windows::core::IUnknown>,
1819    ) -> windows::core::Result<()> {
1820        Err(windows::core::Error::new(
1821            E_NOTIMPL,
1822            "DrawStrikethrough unimplemented",
1823        ))
1824    }
1825
1826    fn DrawInlineObject(
1827        &self,
1828        _clientdrawingcontext: *const ::core::ffi::c_void,
1829        _originx: f32,
1830        _originy: f32,
1831        _inlineobject: windows::core::Ref<IDWriteInlineObject>,
1832        _issideways: BOOL,
1833        _isrighttoleft: BOOL,
1834        _clientdrawingeffect: windows::core::Ref<windows::core::IUnknown>,
1835    ) -> windows::core::Result<()> {
1836        Err(windows::core::Error::new(
1837            E_NOTIMPL,
1838            "DrawInlineObject unimplemented",
1839        ))
1840    }
1841}
1842
1843struct StringIndexConverter<'a> {
1844    text: &'a str,
1845    utf8_ix: usize,
1846    utf16_ix: usize,
1847}
1848
1849impl<'a> StringIndexConverter<'a> {
1850    fn new(text: &'a str) -> Self {
1851        Self {
1852            text,
1853            utf8_ix: 0,
1854            utf16_ix: 0,
1855        }
1856    }
1857
1858    #[allow(dead_code)]
1859    fn advance_to_utf8_ix(&mut self, utf8_target: usize) {
1860        for (ix, c) in self.text[self.utf8_ix..].char_indices() {
1861            if self.utf8_ix + ix >= utf8_target {
1862                self.utf8_ix += ix;
1863                return;
1864            }
1865            self.utf16_ix += c.len_utf16();
1866        }
1867        self.utf8_ix = self.text.len();
1868    }
1869
1870    fn advance_to_utf16_ix(&mut self, utf16_target: usize) {
1871        for (ix, c) in self.text[self.utf8_ix..].char_indices() {
1872            if self.utf16_ix >= utf16_target {
1873                self.utf8_ix += ix;
1874                return;
1875            }
1876            self.utf16_ix += c.len_utf16();
1877        }
1878        self.utf8_ix = self.text.len();
1879    }
1880}
1881
1882impl Into<DWRITE_FONT_STYLE> for FontStyle {
1883    fn into(self) -> DWRITE_FONT_STYLE {
1884        match self {
1885            FontStyle::Normal => DWRITE_FONT_STYLE_NORMAL,
1886            FontStyle::Italic => DWRITE_FONT_STYLE_ITALIC,
1887            FontStyle::Oblique => DWRITE_FONT_STYLE_OBLIQUE,
1888        }
1889    }
1890}
1891
1892impl From<DWRITE_FONT_STYLE> for FontStyle {
1893    fn from(value: DWRITE_FONT_STYLE) -> Self {
1894        match value.0 {
1895            0 => FontStyle::Normal,
1896            1 => FontStyle::Italic,
1897            2 => FontStyle::Oblique,
1898            _ => unreachable!(),
1899        }
1900    }
1901}
1902
1903impl Into<DWRITE_FONT_WEIGHT> for FontWeight {
1904    fn into(self) -> DWRITE_FONT_WEIGHT {
1905        DWRITE_FONT_WEIGHT(self.0 as i32)
1906    }
1907}
1908
1909impl From<DWRITE_FONT_WEIGHT> for FontWeight {
1910    fn from(value: DWRITE_FONT_WEIGHT) -> Self {
1911        FontWeight(value.0 as f32)
1912    }
1913}
1914
1915fn get_font_names_from_collection(
1916    collection: &IDWriteFontCollection1,
1917    locale: &str,
1918) -> Vec<String> {
1919    unsafe {
1920        let mut result = Vec::new();
1921        let family_count = collection.GetFontFamilyCount();
1922        for index in 0..family_count {
1923            let Some(font_family) = collection.GetFontFamily(index).log_err() else {
1924                continue;
1925            };
1926            let Some(localized_family_name) = font_family.GetFamilyNames().log_err() else {
1927                continue;
1928            };
1929            let Some(family_name) = get_name(localized_family_name, locale).log_err() else {
1930                continue;
1931            };
1932            result.push(family_name);
1933        }
1934
1935        result
1936    }
1937}
1938
1939fn get_font_identifier_and_font_struct(
1940    font_face: &IDWriteFontFace3,
1941    locale: &str,
1942) -> Option<(FontIdentifier, Font, bool)> {
1943    let postscript_name = get_postscript_name(font_face, locale).log_err()?;
1944    let localized_family_name = unsafe { font_face.GetFamilyNames().log_err() }?;
1945    let family_name = get_name(localized_family_name, locale).log_err()?;
1946    let weight = unsafe { font_face.GetWeight() };
1947    let style = unsafe { font_face.GetStyle() };
1948    let identifier = FontIdentifier {
1949        postscript_name,
1950        weight: weight.0,
1951        style: style.0,
1952    };
1953    let font_struct = Font {
1954        family: family_name.into(),
1955        features: FontFeatures::default(),
1956        weight: weight.into(),
1957        style: style.into(),
1958        fallbacks: None,
1959    };
1960    let is_emoji = unsafe { font_face.IsColorFont().as_bool() };
1961    Some((identifier, font_struct, is_emoji))
1962}
1963
1964#[inline]
1965fn get_font_identifier(font_face: &IDWriteFontFace3, locale: &str) -> Option<FontIdentifier> {
1966    let weight = unsafe { font_face.GetWeight().0 };
1967    let style = unsafe { font_face.GetStyle().0 };
1968    get_postscript_name(font_face, locale)
1969        .log_err()
1970        .map(|postscript_name| FontIdentifier {
1971            postscript_name,
1972            weight,
1973            style,
1974        })
1975}
1976
1977#[inline]
1978fn get_postscript_name(font_face: &IDWriteFontFace3, locale: &str) -> Result<String> {
1979    let mut info = None;
1980    let mut exists = BOOL(0);
1981    unsafe {
1982        font_face.GetInformationalStrings(
1983            DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_NAME,
1984            &mut info,
1985            &mut exists,
1986        )?
1987    };
1988    if !exists.as_bool() || info.is_none() {
1989        anyhow::bail!("No postscript name found for font face");
1990    }
1991
1992    get_name(info.unwrap(), locale)
1993}
1994
1995// https://learn.microsoft.com/en-us/windows/win32/api/dwrite/ne-dwrite-dwrite_font_feature_tag
1996fn apply_font_features(
1997    direct_write_features: &IDWriteTypography,
1998    features: &FontFeatures,
1999) -> Result<()> {
2000    let tag_values = features.tag_value_list();
2001    if tag_values.is_empty() {
2002        return Ok(());
2003    }
2004
2005    // All of these features are enabled by default by DirectWrite.
2006    // If you want to (and can) peek into the source of DirectWrite
2007    let mut feature_liga = make_direct_write_feature("liga", 1);
2008    let mut feature_clig = make_direct_write_feature("clig", 1);
2009    let mut feature_calt = make_direct_write_feature("calt", 1);
2010
2011    for (tag, value) in tag_values {
2012        if tag.as_str() == "liga" && *value == 0 {
2013            feature_liga.parameter = 0;
2014            continue;
2015        }
2016        if tag.as_str() == "clig" && *value == 0 {
2017            feature_clig.parameter = 0;
2018            continue;
2019        }
2020        if tag.as_str() == "calt" && *value == 0 {
2021            feature_calt.parameter = 0;
2022            continue;
2023        }
2024
2025        unsafe {
2026            direct_write_features.AddFontFeature(make_direct_write_feature(&tag, *value))?;
2027        }
2028    }
2029    unsafe {
2030        direct_write_features.AddFontFeature(feature_liga)?;
2031        direct_write_features.AddFontFeature(feature_clig)?;
2032        direct_write_features.AddFontFeature(feature_calt)?;
2033    }
2034
2035    Ok(())
2036}
2037
2038#[inline]
2039const fn make_direct_write_feature(feature_name: &str, parameter: u32) -> DWRITE_FONT_FEATURE {
2040    let tag = make_direct_write_tag(feature_name);
2041    DWRITE_FONT_FEATURE {
2042        nameTag: tag,
2043        parameter,
2044    }
2045}
2046
2047#[inline]
2048const fn make_open_type_tag(tag_name: &str) -> u32 {
2049    let bytes = tag_name.as_bytes();
2050    debug_assert!(bytes.len() == 4);
2051    u32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]])
2052}
2053
2054#[inline]
2055const fn make_direct_write_tag(tag_name: &str) -> DWRITE_FONT_FEATURE_TAG {
2056    DWRITE_FONT_FEATURE_TAG(make_open_type_tag(tag_name))
2057}
2058
2059#[inline]
2060fn get_name(string: IDWriteLocalizedStrings, locale: &str) -> Result<String> {
2061    let mut locale_name_index = 0u32;
2062    let mut exists = BOOL(0);
2063    unsafe {
2064        string.FindLocaleName(
2065            &HSTRING::from(locale),
2066            &mut locale_name_index,
2067            &mut exists as _,
2068        )?
2069    };
2070    if !exists.as_bool() {
2071        unsafe {
2072            string.FindLocaleName(
2073                DEFAULT_LOCALE_NAME,
2074                &mut locale_name_index as _,
2075                &mut exists as _,
2076            )?
2077        };
2078        anyhow::ensure!(exists.as_bool(), "No localised string for {locale}");
2079    }
2080
2081    let name_length = unsafe { string.GetStringLength(locale_name_index) }? as usize;
2082    let mut name_vec = vec![0u16; name_length + 1];
2083    unsafe {
2084        string.GetString(locale_name_index, &mut name_vec)?;
2085    }
2086
2087    Ok(String::from_utf16_lossy(&name_vec[..name_length]))
2088}
2089
2090#[inline]
2091fn translate_color(color: &DWRITE_COLOR_F) -> [f32; 4] {
2092    [color.r, color.g, color.b, color.a]
2093}
2094
2095fn get_system_ui_font_name() -> SharedString {
2096    unsafe {
2097        let mut info: LOGFONTW = std::mem::zeroed();
2098        let font_family = if SystemParametersInfoW(
2099            SPI_GETICONTITLELOGFONT,
2100            std::mem::size_of::<LOGFONTW>() as u32,
2101            Some(&mut info as *mut _ as _),
2102            SYSTEM_PARAMETERS_INFO_UPDATE_FLAGS(0),
2103        )
2104        .log_err()
2105        .is_none()
2106        {
2107            // https://learn.microsoft.com/en-us/windows/win32/uxguide/vis-fonts
2108            // Segoe UI is the Windows font intended for user interface text strings.
2109            "Segoe UI".into()
2110        } else {
2111            let font_name = String::from_utf16_lossy(&info.lfFaceName);
2112            font_name.trim_matches(char::from(0)).to_owned().into()
2113        };
2114        log::info!("Use {} as UI font.", font_family);
2115        font_family
2116    }
2117}
2118
2119// One would think that with newer DirectWrite method: IDWriteFontFace4::GetGlyphImageFormats
2120// but that doesn't seem to work for some glyphs, say โค
2121fn is_color_glyph(
2122    font_face: &IDWriteFontFace3,
2123    glyph_id: GlyphId,
2124    factory: &IDWriteFactory5,
2125) -> bool {
2126    let glyph_run = DWRITE_GLYPH_RUN {
2127        fontFace: unsafe { std::mem::transmute_copy(font_face) },
2128        fontEmSize: 14.0,
2129        glyphCount: 1,
2130        glyphIndices: &(glyph_id.0 as u16),
2131        glyphAdvances: &0.0,
2132        glyphOffsets: &DWRITE_GLYPH_OFFSET {
2133            advanceOffset: 0.0,
2134            ascenderOffset: 0.0,
2135        },
2136        isSideways: BOOL(0),
2137        bidiLevel: 0,
2138    };
2139    unsafe {
2140        factory.TranslateColorGlyphRun(
2141            Vector2::default(),
2142            &glyph_run as _,
2143            None,
2144            DWRITE_GLYPH_IMAGE_FORMATS_COLR
2145                | DWRITE_GLYPH_IMAGE_FORMATS_SVG
2146                | DWRITE_GLYPH_IMAGE_FORMATS_PNG
2147                | DWRITE_GLYPH_IMAGE_FORMATS_JPEG
2148                | DWRITE_GLYPH_IMAGE_FORMATS_PREMULTIPLIED_B8G8R8A8,
2149            DWRITE_MEASURING_MODE_NATURAL,
2150            None,
2151            0,
2152        )
2153    }
2154    .is_ok()
2155}
2156
2157const DEFAULT_LOCALE_NAME: PCWSTR = windows::core::w!("en-US");
2158
2159#[cfg(test)]
2160mod tests {
2161    use crate::platform::windows::direct_write::ClusterAnalyzer;
2162
2163    #[test]
2164    fn test_cluster_map() {
2165        let cluster_map = [0];
2166        let mut analyzer = ClusterAnalyzer::new(&cluster_map, 1);
2167        let next = analyzer.next();
2168        assert_eq!(next, Some((1, 1)));
2169        let next = analyzer.next();
2170        assert_eq!(next, None);
2171
2172        let cluster_map = [0, 1, 2];
2173        let mut analyzer = ClusterAnalyzer::new(&cluster_map, 3);
2174        let next = analyzer.next();
2175        assert_eq!(next, Some((1, 1)));
2176        let next = analyzer.next();
2177        assert_eq!(next, Some((1, 1)));
2178        let next = analyzer.next();
2179        assert_eq!(next, Some((1, 1)));
2180        let next = analyzer.next();
2181        assert_eq!(next, None);
2182        // ๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ฆ๐Ÿ‘ฉโ€๐Ÿ’ป
2183        let cluster_map = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4];
2184        let mut analyzer = ClusterAnalyzer::new(&cluster_map, 5);
2185        let next = analyzer.next();
2186        assert_eq!(next, Some((11, 4)));
2187        let next = analyzer.next();
2188        assert_eq!(next, Some((5, 1)));
2189        let next = analyzer.next();
2190        assert_eq!(next, None);
2191        // ๐Ÿ‘ฉโ€๐Ÿ’ป
2192        let cluster_map = [0, 0, 0, 0, 0];
2193        let mut analyzer = ClusterAnalyzer::new(&cluster_map, 1);
2194        let next = analyzer.next();
2195        assert_eq!(next, Some((5, 1)));
2196        let next = analyzer.next();
2197        assert_eq!(next, None);
2198    }
2199}