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::mem::{self, zeroed};
7 use std::ptr;
8 use std::slice;
9 use winapi::ctypes::c_void;
10 use winapi::shared::minwindef::{BOOL, FALSE, TRUE};
11 use winapi::shared::winerror::S_OK;
12 use winapi::um::dcommon::DWRITE_MEASURING_MODE;
13 use winapi::um::dwrite::IDWriteRenderingParams;
14 use winapi::um::dwrite::DWRITE_FONT_FACE_TYPE_TRUETYPE;
15 use winapi::um::dwrite::{IDWriteFontFace, IDWriteFontFile};
16 use winapi::um::dwrite::{DWRITE_FONT_FACE_TYPE_BITMAP, DWRITE_FONT_FACE_TYPE_CFF};
17 use winapi::um::dwrite::{DWRITE_FONT_FACE_TYPE_RAW_CFF, DWRITE_FONT_FACE_TYPE_TYPE1};
18 use winapi::um::dwrite::{DWRITE_FONT_FACE_TYPE_TRUETYPE_COLLECTION, DWRITE_FONT_FACE_TYPE_VECTOR};
19 use winapi::um::dwrite::{DWRITE_FONT_SIMULATIONS, DWRITE_GLYPH_METRICS};
20 use winapi::um::dwrite::{DWRITE_GLYPH_OFFSET, DWRITE_MATRIX, DWRITE_RENDERING_MODE};
21 use winapi::um::dwrite::{DWRITE_RENDERING_MODE_DEFAULT, DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC};
22 use winapi::um::dwrite_1::IDWriteFontFace1;
23 use winapi::um::dwrite_3::{IDWriteFontFace5, IDWriteFontResource, DWRITE_FONT_AXIS_VALUE};
24 use wio::com::ComPtr;
25 
26 use super::{DWriteFactory, DefaultDWriteRenderParams, FontFile, FontMetrics};
27 use crate::com_helpers::Com;
28 use crate::geometry_sink_impl::GeometrySinkImpl;
29 use crate::outline_builder::OutlineBuilder;
30 
31 pub struct FontFace {
32     native: UnsafeCell<ComPtr<IDWriteFontFace>>,
33     face5: UnsafeCell<Option<ComPtr<IDWriteFontFace5>>>,
34 }
35 
36 impl FontFace {
take(native: ComPtr<IDWriteFontFace>) -> FontFace37     pub fn take(native: ComPtr<IDWriteFontFace>) -> FontFace {
38         let cell = UnsafeCell::new(native);
39         FontFace {
40             native: cell,
41             face5: UnsafeCell::new(None),
42         }
43     }
44 
as_ptr(&self) -> *mut IDWriteFontFace45     pub unsafe fn as_ptr(&self) -> *mut IDWriteFontFace {
46         (*self.native.get()).as_raw()
47     }
48 
get_raw_files(&self) -> Vec<*mut IDWriteFontFile>49     unsafe fn get_raw_files(&self) -> Vec<*mut IDWriteFontFile> {
50         let mut number_of_files: u32 = 0;
51         let hr = (*self.native.get()).GetFiles(&mut number_of_files, ptr::null_mut());
52         assert!(hr == 0);
53 
54         let mut file_ptrs: Vec<*mut IDWriteFontFile> =
55             vec![ptr::null_mut(); number_of_files as usize];
56         let hr = (*self.native.get()).GetFiles(&mut number_of_files, file_ptrs.as_mut_ptr());
57         assert!(hr == 0);
58         file_ptrs
59     }
60 
get_files(&self) -> Vec<FontFile>61     pub fn get_files(&self) -> Vec<FontFile> {
62         unsafe {
63             let file_ptrs = self.get_raw_files();
64             file_ptrs
65                 .iter()
66                 .map(|p| FontFile::take(ComPtr::from_raw(*p)))
67                 .collect()
68         }
69     }
70 
create_font_face_with_simulations( &self, simulations: DWRITE_FONT_SIMULATIONS, ) -> FontFace71     pub fn create_font_face_with_simulations(
72         &self,
73         simulations: DWRITE_FONT_SIMULATIONS,
74     ) -> FontFace {
75         unsafe {
76             let file_ptrs = self.get_raw_files();
77             let face_type = (*self.native.get()).GetType();
78             let face_index = (*self.native.get()).GetIndex();
79             let mut face: *mut IDWriteFontFace = ptr::null_mut();
80             let hr = (*DWriteFactory()).CreateFontFace(
81                 face_type,
82                 file_ptrs.len() as u32,
83                 file_ptrs.as_ptr(),
84                 face_index,
85                 simulations,
86                 &mut face,
87             );
88             for p in file_ptrs {
89                 let _ = ComPtr::<IDWriteFontFile>::from_raw(p);
90             }
91             assert!(hr == 0);
92             FontFace::take(ComPtr::from_raw(face))
93         }
94     }
95 
get_glyph_count(&self) -> u1696     pub fn get_glyph_count(&self) -> u16 {
97         unsafe { (*self.native.get()).GetGlyphCount() }
98     }
99 
metrics(&self) -> FontMetrics100     pub fn metrics(&self) -> FontMetrics {
101         unsafe {
102             let font_1: Option<ComPtr<IDWriteFontFace1>> = (*self.native.get()).cast().ok();
103             match font_1 {
104                 None => {
105                     let mut metrics = mem::zeroed();
106                     (*self.native.get()).GetMetrics(&mut metrics);
107                     FontMetrics::Metrics0(metrics)
108                 }
109                 Some(font_1) => {
110                     let mut metrics_1 = mem::zeroed();
111                     font_1.GetMetrics(&mut metrics_1);
112                     FontMetrics::Metrics1(metrics_1)
113                 }
114             }
115         }
116     }
117 
get_glyph_indices(&self, code_points: &[u32]) -> Vec<u16>118     pub fn get_glyph_indices(&self, code_points: &[u32]) -> Vec<u16> {
119         unsafe {
120             let mut glyph_indices: Vec<u16> = vec![0; code_points.len()];
121             let hr = (*self.native.get()).GetGlyphIndices(
122                 code_points.as_ptr(),
123                 code_points.len() as u32,
124                 glyph_indices.as_mut_ptr(),
125             );
126             assert!(hr == 0);
127             glyph_indices
128         }
129     }
130 
get_design_glyph_metrics( &self, glyph_indices: &[u16], is_sideways: bool, ) -> Vec<DWRITE_GLYPH_METRICS>131     pub fn get_design_glyph_metrics(
132         &self,
133         glyph_indices: &[u16],
134         is_sideways: bool,
135     ) -> Vec<DWRITE_GLYPH_METRICS> {
136         unsafe {
137             let mut metrics: Vec<DWRITE_GLYPH_METRICS> = vec![zeroed(); glyph_indices.len()];
138             let hr = (*self.native.get()).GetDesignGlyphMetrics(
139                 glyph_indices.as_ptr(),
140                 glyph_indices.len() as u32,
141                 metrics.as_mut_ptr(),
142                 is_sideways as BOOL,
143             );
144             assert!(hr == 0);
145             metrics
146         }
147     }
148 
get_gdi_compatible_glyph_metrics( &self, em_size: f32, pixels_per_dip: f32, transform: *const DWRITE_MATRIX, use_gdi_natural: bool, glyph_indices: &[u16], is_sideways: bool, ) -> Vec<DWRITE_GLYPH_METRICS>149     pub fn get_gdi_compatible_glyph_metrics(
150         &self,
151         em_size: f32,
152         pixels_per_dip: f32,
153         transform: *const DWRITE_MATRIX,
154         use_gdi_natural: bool,
155         glyph_indices: &[u16],
156         is_sideways: bool,
157     ) -> Vec<DWRITE_GLYPH_METRICS> {
158         unsafe {
159             let mut metrics: Vec<DWRITE_GLYPH_METRICS> = vec![zeroed(); glyph_indices.len()];
160             let hr = (*self.native.get()).GetGdiCompatibleGlyphMetrics(
161                 em_size,
162                 pixels_per_dip,
163                 transform,
164                 use_gdi_natural as BOOL,
165                 glyph_indices.as_ptr(),
166                 glyph_indices.len() as u32,
167                 metrics.as_mut_ptr(),
168                 is_sideways as BOOL,
169             );
170             assert!(hr == 0);
171             metrics
172         }
173     }
174 
175     /// Returns the contents of the OpenType table with the given tag.
176     ///
177     /// NB: The bytes of the tag are reversed! You probably want to use the `u32::swap_bytes()`
178     /// method on the tag value before calling this method.
get_font_table(&self, opentype_table_tag: u32) -> Option<Vec<u8>>179     pub fn get_font_table(&self, opentype_table_tag: u32) -> Option<Vec<u8>> {
180         unsafe {
181             let mut table_data_ptr: *const u8 = ptr::null_mut();
182             let mut table_size: u32 = 0;
183             let mut table_context: *mut c_void = ptr::null_mut();
184             let mut exists: BOOL = FALSE;
185 
186             let hr = (*self.native.get()).TryGetFontTable(
187                 opentype_table_tag,
188                 &mut table_data_ptr as *mut *const _ as *mut *const c_void,
189                 &mut table_size,
190                 &mut table_context,
191                 &mut exists,
192             );
193             assert!(hr == 0);
194 
195             if exists == FALSE {
196                 return None;
197             }
198 
199             let table_bytes = slice::from_raw_parts(table_data_ptr, table_size as usize).to_vec();
200 
201             (*self.native.get()).ReleaseFontTable(table_context);
202 
203             Some(table_bytes)
204         }
205     }
206 
get_recommended_rendering_mode( &self, em_size: f32, pixels_per_dip: f32, measure_mode: DWRITE_MEASURING_MODE, rendering_params: *mut IDWriteRenderingParams, ) -> DWRITE_RENDERING_MODE207     pub fn get_recommended_rendering_mode(
208         &self,
209         em_size: f32,
210         pixels_per_dip: f32,
211         measure_mode: DWRITE_MEASURING_MODE,
212         rendering_params: *mut IDWriteRenderingParams,
213     ) -> DWRITE_RENDERING_MODE {
214         unsafe {
215             let mut render_mode: DWRITE_RENDERING_MODE = DWRITE_RENDERING_MODE_DEFAULT;
216             let hr = (*self.native.get()).GetRecommendedRenderingMode(
217                 em_size,
218                 pixels_per_dip,
219                 measure_mode,
220                 rendering_params,
221                 &mut render_mode,
222             );
223 
224             if hr != 0 {
225                 return DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC;
226             }
227 
228             render_mode
229         }
230     }
231 
get_recommended_rendering_mode_default_params( &self, em_size: f32, pixels_per_dip: f32, measure_mode: DWRITE_MEASURING_MODE, ) -> DWRITE_RENDERING_MODE232     pub fn get_recommended_rendering_mode_default_params(
233         &self,
234         em_size: f32,
235         pixels_per_dip: f32,
236         measure_mode: DWRITE_MEASURING_MODE,
237     ) -> DWRITE_RENDERING_MODE {
238         self.get_recommended_rendering_mode(
239             em_size,
240             pixels_per_dip,
241             measure_mode,
242             DefaultDWriteRenderParams(),
243         )
244     }
245 
get_glyph_run_outline( &self, em_size: f32, glyph_indices: &[u16], glyph_advances: Option<&[f32]>, glyph_offsets: Option<&[DWRITE_GLYPH_OFFSET]>, is_sideways: bool, is_right_to_left: bool, outline_builder: Box<dyn OutlineBuilder>, )246     pub fn get_glyph_run_outline(
247         &self,
248         em_size: f32,
249         glyph_indices: &[u16],
250         glyph_advances: Option<&[f32]>,
251         glyph_offsets: Option<&[DWRITE_GLYPH_OFFSET]>,
252         is_sideways: bool,
253         is_right_to_left: bool,
254         outline_builder: Box<dyn OutlineBuilder>,
255     ) {
256         unsafe {
257             let glyph_advances = match glyph_advances {
258                 None => ptr::null(),
259                 Some(glyph_advances) => {
260                     assert_eq!(glyph_advances.len(), glyph_indices.len());
261                     glyph_advances.as_ptr()
262                 }
263             };
264             let glyph_offsets = match glyph_offsets {
265                 None => ptr::null(),
266                 Some(glyph_offsets) => {
267                     assert_eq!(glyph_offsets.len(), glyph_indices.len());
268                     glyph_offsets.as_ptr()
269                 }
270             };
271             let is_sideways = if is_sideways { TRUE } else { FALSE };
272             let is_right_to_left = if is_right_to_left { TRUE } else { FALSE };
273             let geometry_sink = GeometrySinkImpl::new(outline_builder);
274             let geometry_sink = geometry_sink.into_interface();
275             let hr = (*self.native.get()).GetGlyphRunOutline(
276                 em_size,
277                 glyph_indices.as_ptr(),
278                 glyph_advances,
279                 glyph_offsets,
280                 glyph_indices.len() as u32,
281                 is_sideways,
282                 is_right_to_left,
283                 geometry_sink,
284             );
285             assert_eq!(hr, S_OK);
286         }
287     }
288 
289     #[inline]
get_type(&self) -> FontFaceType290     pub fn get_type(&self) -> FontFaceType {
291         unsafe {
292             match (*self.native.get()).GetType() {
293                 DWRITE_FONT_FACE_TYPE_CFF => FontFaceType::Cff,
294                 DWRITE_FONT_FACE_TYPE_RAW_CFF => FontFaceType::RawCff,
295                 DWRITE_FONT_FACE_TYPE_TRUETYPE => FontFaceType::TrueType,
296                 DWRITE_FONT_FACE_TYPE_TRUETYPE_COLLECTION => FontFaceType::TrueTypeCollection,
297                 DWRITE_FONT_FACE_TYPE_TYPE1 => FontFaceType::Type1,
298                 DWRITE_FONT_FACE_TYPE_VECTOR => FontFaceType::Vector,
299                 DWRITE_FONT_FACE_TYPE_BITMAP => FontFaceType::Bitmap,
300                 _ => FontFaceType::Unknown,
301             }
302         }
303     }
304 
305     #[inline]
get_index(&self) -> u32306     pub fn get_index(&self) -> u32 {
307         unsafe { (*self.native.get()).GetIndex() }
308     }
309 
310     #[inline]
get_face5(&self) -> Option<ComPtr<IDWriteFontFace5>>311     unsafe fn get_face5(&self) -> Option<ComPtr<IDWriteFontFace5>> {
312         if (*self.face5.get()).is_none() {
313             *self.face5.get() = (*self.native.get()).cast().ok()
314         }
315         (*self.face5.get()).clone()
316     }
317 
has_variations(&self) -> bool318     pub fn has_variations(&self) -> bool {
319         unsafe {
320             match self.get_face5() {
321                 Some(face5) => face5.HasVariations() == TRUE,
322                 None => false,
323             }
324         }
325     }
326 
create_font_face_with_variations( &self, simulations: DWRITE_FONT_SIMULATIONS, axis_values: &[DWRITE_FONT_AXIS_VALUE], ) -> Option<FontFace>327     pub fn create_font_face_with_variations(
328         &self,
329         simulations: DWRITE_FONT_SIMULATIONS,
330         axis_values: &[DWRITE_FONT_AXIS_VALUE],
331     ) -> Option<FontFace> {
332         unsafe {
333             if let Some(face5) = self.get_face5() {
334                 let mut resource: *mut IDWriteFontResource = ptr::null_mut();
335                 let hr = face5.GetFontResource(&mut resource);
336                 if hr == S_OK && !resource.is_null() {
337                     let resource = ComPtr::from_raw(resource);
338                     let mut var_face: *mut IDWriteFontFace5 = ptr::null_mut();
339                     let hr = resource.CreateFontFace(
340                         simulations,
341                         axis_values.as_ptr(),
342                         axis_values.len() as u32,
343                         &mut var_face,
344                     );
345                     if hr == S_OK && !var_face.is_null() {
346                         let var_face = ComPtr::from_raw(var_face).cast().unwrap();
347                         return Some(FontFace::take(var_face));
348                     }
349                 }
350             }
351             None
352         }
353     }
354 }
355 
356 impl Clone for FontFace {
clone(&self) -> FontFace357     fn clone(&self) -> FontFace {
358         unsafe {
359             FontFace {
360                 native: UnsafeCell::new((*self.native.get()).clone()),
361                 face5: UnsafeCell::new(None),
362             }
363         }
364     }
365 }
366 
367 #[derive(Clone, Copy, Debug, PartialEq)]
368 pub enum FontFaceType {
369     Unknown,
370     Cff,
371     RawCff,
372     TrueType,
373     TrueTypeCollection,
374     Type1,
375     Vector,
376     Bitmap,
377 }
378