1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 
5 use std::cell::UnsafeCell;
6 use std::ptr::null_mut;
7 use winapi::um::dwrite_2::{IDWriteFactory2, IDWriteFontFallback};
8 use wio::com::ComPtr;
9 
10 use super::*;
11 
12 pub struct FontFallback {
13     native: UnsafeCell<ComPtr<IDWriteFontFallback>>,
14 }
15 
16 pub struct FallbackResult {
17     /// Length of mapped substring, in utf-16 code units.
18     pub mapped_length: usize,
19     /// The font that should be used to render the substring.
20     pub mapped_font: Option<Font>,
21     /// The scale factor to apply.
22     pub scale: f32,
23 }
24 
25 impl FontFallback {
get_system_fallback() -> Option<FontFallback>26     pub fn get_system_fallback() -> Option<FontFallback> {
27         unsafe {
28             let factory = ComPtr::from_raw(DWriteFactory());
29             let factory2: Option<ComPtr<IDWriteFactory2>> = factory.cast().ok();
30             std::mem::forget(factory);
31             let factory2 = factory2?;
32             let mut native = null_mut();
33             let hr = factory2.GetSystemFontFallback(&mut native);
34             assert_eq!(hr, 0);
35             Some(Self::take(ComPtr::from_raw(native)))
36         }
37     }
38 
take(native: ComPtr<IDWriteFontFallback>) -> FontFallback39     pub fn take(native: ComPtr<IDWriteFontFallback>) -> FontFallback {
40         FontFallback {
41             native: UnsafeCell::new(native),
42         }
43     }
44 
45     // TODO: I'm following crate conventions for unsafe, but it's bullshit
as_ptr(&self) -> *mut IDWriteFontFallback46     pub unsafe fn as_ptr(&self) -> *mut IDWriteFontFallback {
47         (*self.native.get()).as_raw()
48     }
49 
50     // TODO: map_characters (main function)
map_characters( &self, text_analysis_source: &TextAnalysisSource, text_position: u32, text_length: u32, base_font: &FontCollection, base_family: Option<&str>, base_weight: FontWeight, base_style: FontStyle, base_stretch: FontStretch, ) -> FallbackResult51     pub fn map_characters(
52         &self,
53         text_analysis_source: &TextAnalysisSource,
54         text_position: u32,
55         text_length: u32,
56         base_font: &FontCollection,
57         base_family: Option<&str>,
58         base_weight: FontWeight,
59         base_style: FontStyle,
60         base_stretch: FontStretch,
61     ) -> FallbackResult {
62         unsafe {
63             let mut font = null_mut();
64             let mut mapped_length = 0;
65             let mut scale = 0.0;
66             let hr = (*self.as_ptr()).MapCharacters(
67                 text_analysis_source.as_ptr(),
68                 text_position,
69                 text_length,
70                 base_font.as_ptr(),
71                 base_family
72                     .map(|s| s.to_wide_null().as_mut_ptr())
73                     .unwrap_or(null_mut()),
74                 base_weight.t(),
75                 base_style.t(),
76                 base_stretch.t(),
77                 &mut mapped_length,
78                 &mut font,
79                 &mut scale,
80             );
81             assert_eq!(hr, 0);
82             let mapped_font = if font.is_null() {
83                 None
84             } else {
85                 Some(Font::take(ComPtr::from_raw(font)))
86             };
87             FallbackResult {
88                 mapped_length: mapped_length as usize,
89                 mapped_font,
90                 scale,
91             }
92         }
93     }
94 }
95