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