Skip to content

Commit 4d82899

Browse files
authored
Add fallible versions of FontFace methods (#66)
* Add fallible versions of FontFace methods * fix unsafe fn raw_files * fix create_font_face_with_simulations
1 parent 8921f0b commit 4d82899

File tree

1 file changed

+167
-49
lines changed

1 file changed

+167
-49
lines changed

src/font_face.rs

Lines changed: 167 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44

55
use std::cell::UnsafeCell;
66
use std::mem::{self, zeroed};
7-
use std::ptr;
87
use std::slice;
8+
use std::{error, fmt, ptr};
99
use winapi::ctypes::c_void;
1010
use winapi::shared::minwindef::{BOOL, FALSE, TRUE};
1111
use winapi::shared::winerror::S_OK;
@@ -21,6 +21,7 @@ use winapi::um::dwrite::{DWRITE_GLYPH_OFFSET, DWRITE_MATRIX, DWRITE_RENDERING_MO
2121
use winapi::um::dwrite::{DWRITE_RENDERING_MODE_DEFAULT, DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC};
2222
use winapi::um::dwrite_1::IDWriteFontFace1;
2323
use winapi::um::dwrite_3::{IDWriteFontFace5, IDWriteFontResource, DWRITE_FONT_AXIS_VALUE};
24+
use winapi::um::winnt::HRESULT;
2425
use winapi::Interface;
2526
use wio::com::ComPtr;
2627

@@ -49,25 +50,35 @@ impl FontFace {
4950
(*self.native.get()).as_raw()
5051
}
5152

52-
unsafe fn get_raw_files(&self) -> Vec<*mut IDWriteFontFile> {
53+
unsafe fn raw_files(&self) -> Result<Vec<*mut IDWriteFontFile>, HRESULT> {
5354
let mut number_of_files: u32 = 0;
5455
let hr = (*self.native.get()).GetFiles(&mut number_of_files, ptr::null_mut());
55-
assert!(hr == 0);
56+
if hr != S_OK {
57+
return Err(hr);
58+
}
5659

5760
let mut file_ptrs: Vec<*mut IDWriteFontFile> =
5861
vec![ptr::null_mut(); number_of_files as usize];
5962
let hr = (*self.native.get()).GetFiles(&mut number_of_files, file_ptrs.as_mut_ptr());
60-
assert!(hr == 0);
61-
file_ptrs
63+
if hr != S_OK {
64+
return Err(hr);
65+
}
66+
Ok(file_ptrs)
6267
}
6368

69+
#[deprecated(note = "Use `files` instead.")]
6470
pub fn get_files(&self) -> Vec<FontFile> {
71+
self.files().unwrap()
72+
}
73+
74+
pub fn files(&self) -> Result<Vec<FontFile>, HRESULT> {
6575
unsafe {
66-
let file_ptrs = self.get_raw_files();
67-
file_ptrs
68-
.iter()
69-
.map(|p| FontFile::take(ComPtr::from_raw(*p)))
70-
.collect()
76+
self.raw_files().map(|file_ptrs| {
77+
file_ptrs
78+
.iter()
79+
.map(|p| FontFile::take(ComPtr::from_raw(*p)))
80+
.collect()
81+
})
7182
}
7283
}
7384

@@ -76,7 +87,7 @@ impl FontFace {
7687
simulations: DWRITE_FONT_SIMULATIONS,
7788
) -> FontFace {
7889
unsafe {
79-
let file_ptrs = self.get_raw_files();
90+
let file_ptrs = self.raw_files().unwrap();
8091
let face_type = (*self.native.get()).GetType();
8192
let face_index = (*self.native.get()).GetIndex();
8293
let mut face: *mut IDWriteFontFace = ptr::null_mut();
@@ -118,24 +129,41 @@ impl FontFace {
118129
}
119130
}
120131

132+
#[deprecated(note = "Use `glyph_indices` instead.")]
121133
pub fn get_glyph_indices(&self, code_points: &[u32]) -> Vec<u16> {
134+
self.glyph_indices(code_points).unwrap()
135+
}
136+
137+
pub fn glyph_indices(&self, code_points: &[u32]) -> Result<Vec<u16>, HRESULT> {
138+
let mut glyph_indices: Vec<u16> = vec![0; code_points.len()];
122139
unsafe {
123-
let mut glyph_indices: Vec<u16> = vec![0; code_points.len()];
124140
let hr = (*self.native.get()).GetGlyphIndices(
125141
code_points.as_ptr(),
126142
code_points.len() as u32,
127143
glyph_indices.as_mut_ptr(),
128144
);
129-
assert!(hr == 0);
130-
glyph_indices
145+
if hr != S_OK {
146+
return Err(hr);
147+
}
148+
Ok(glyph_indices)
131149
}
132150
}
133151

152+
#[deprecated(note = "Use `design_glyph_metrics` instead.")]
134153
pub fn get_design_glyph_metrics(
135154
&self,
136155
glyph_indices: &[u16],
137156
is_sideways: bool,
138157
) -> Vec<DWRITE_GLYPH_METRICS> {
158+
self.design_glyph_metrics(glyph_indices, is_sideways)
159+
.unwrap()
160+
}
161+
162+
pub fn design_glyph_metrics(
163+
&self,
164+
glyph_indices: &[u16],
165+
is_sideways: bool,
166+
) -> Result<Vec<DWRITE_GLYPH_METRICS>, HRESULT> {
139167
unsafe {
140168
let mut metrics: Vec<DWRITE_GLYPH_METRICS> = vec![zeroed(); glyph_indices.len()];
141169
let hr = (*self.native.get()).GetDesignGlyphMetrics(
@@ -144,11 +172,14 @@ impl FontFace {
144172
metrics.as_mut_ptr(),
145173
is_sideways as BOOL,
146174
);
147-
assert!(hr == 0);
148-
metrics
175+
if hr != S_OK {
176+
return Err(hr);
177+
}
178+
Ok(metrics)
149179
}
150180
}
151181

182+
#[deprecated(note = "Use `gdi_compatible_glyph_metrics` instead.")]
152183
pub fn get_gdi_compatible_glyph_metrics(
153184
&self,
154185
em_size: f32,
@@ -158,6 +189,26 @@ impl FontFace {
158189
glyph_indices: &[u16],
159190
is_sideways: bool,
160191
) -> Vec<DWRITE_GLYPH_METRICS> {
192+
self.gdi_compatible_glyph_metrics(
193+
em_size,
194+
pixels_per_dip,
195+
transform,
196+
use_gdi_natural,
197+
glyph_indices,
198+
is_sideways,
199+
)
200+
.unwrap()
201+
}
202+
203+
pub fn gdi_compatible_glyph_metrics(
204+
&self,
205+
em_size: f32,
206+
pixels_per_dip: f32,
207+
transform: *const DWRITE_MATRIX,
208+
use_gdi_natural: bool,
209+
glyph_indices: &[u16],
210+
is_sideways: bool,
211+
) -> Result<Vec<DWRITE_GLYPH_METRICS>, HRESULT> {
161212
unsafe {
162213
let mut metrics: Vec<DWRITE_GLYPH_METRICS> = vec![zeroed(); glyph_indices.len()];
163214
let hr = (*self.native.get()).GetGdiCompatibleGlyphMetrics(
@@ -170,40 +221,48 @@ impl FontFace {
170221
metrics.as_mut_ptr(),
171222
is_sideways as BOOL,
172223
);
173-
assert!(hr == 0);
174-
metrics
224+
if hr != S_OK {
225+
return Err(hr);
226+
}
227+
Ok(metrics)
175228
}
176229
}
177230

231+
#[deprecated(note = "Use `font_table` instead.")]
232+
pub fn get_font_table(&self, opentype_table_tag: u32) -> Option<Vec<u8>> {
233+
self.font_table(opentype_table_tag).unwrap()
234+
}
235+
178236
/// Returns the contents of the OpenType table with the given tag.
179237
///
180238
/// NB: The bytes of the tag are reversed! You probably want to use the `u32::swap_bytes()`
181239
/// method on the tag value before calling this method.
182-
pub fn get_font_table(&self, opentype_table_tag: u32) -> Option<Vec<u8>> {
240+
pub fn font_table(&self, opentype_table_tag: u32) -> Result<Option<Vec<u8>>, HRESULT> {
241+
let mut table_data_ptr: *const u8 = ptr::null_mut();
242+
let mut table_size: u32 = 0;
243+
let mut table_context: *mut c_void = ptr::null_mut();
244+
let mut exists: BOOL = FALSE;
183245
unsafe {
184-
let mut table_data_ptr: *const u8 = ptr::null_mut();
185-
let mut table_size: u32 = 0;
186-
let mut table_context: *mut c_void = ptr::null_mut();
187-
let mut exists: BOOL = FALSE;
188-
189246
let hr = (*self.native.get()).TryGetFontTable(
190247
opentype_table_tag,
191248
&mut table_data_ptr as *mut *const _ as *mut *const c_void,
192249
&mut table_size,
193250
&mut table_context,
194251
&mut exists,
195252
);
196-
assert!(hr == 0);
253+
if hr != S_OK {
254+
return Err(hr);
255+
}
197256

198257
if exists == FALSE {
199-
return None;
258+
return Ok(None);
200259
}
201260

202261
let table_bytes = slice::from_raw_parts(table_data_ptr, table_size as usize).to_vec();
203262

204263
(*self.native.get()).ReleaseFontTable(table_context);
205264

206-
Some(table_bytes)
265+
Ok(Some(table_bytes))
207266
}
208267
}
209268

@@ -224,7 +283,7 @@ impl FontFace {
224283
&mut render_mode,
225284
);
226285

227-
if hr != 0 {
286+
if hr != S_OK {
228287
return DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC;
229288
}
230289

@@ -246,6 +305,7 @@ impl FontFace {
246305
)
247306
}
248307

308+
#[deprecated(note = "Use `glyph_run_outline` instead.")]
249309
pub fn get_glyph_run_outline(
250310
&self,
251311
em_size: f32,
@@ -256,25 +316,51 @@ impl FontFace {
256316
is_right_to_left: bool,
257317
outline_builder: Box<dyn OutlineBuilder>,
258318
) {
259-
unsafe {
260-
let glyph_advances = match glyph_advances {
261-
None => ptr::null(),
262-
Some(glyph_advances) => {
263-
assert_eq!(glyph_advances.len(), glyph_indices.len());
264-
glyph_advances.as_ptr()
319+
self.glyph_run_outline(
320+
em_size,
321+
glyph_indices,
322+
glyph_advances,
323+
glyph_offsets,
324+
is_sideways,
325+
is_right_to_left,
326+
outline_builder,
327+
)
328+
.unwrap()
329+
}
330+
331+
pub fn glyph_run_outline(
332+
&self,
333+
em_size: f32,
334+
glyph_indices: &[u16],
335+
glyph_advances: Option<&[f32]>,
336+
glyph_offsets: Option<&[DWRITE_GLYPH_OFFSET]>,
337+
is_sideways: bool,
338+
is_right_to_left: bool,
339+
outline_builder: Box<dyn OutlineBuilder>,
340+
) -> Result<(), GlyphRunOutlineError> {
341+
let glyph_advances = match glyph_advances {
342+
None => ptr::null(),
343+
Some(glyph_advances) => {
344+
if glyph_advances.len() != glyph_indices.len() {
345+
return Err(GlyphRunOutlineError::InvalidInput);
265346
}
266-
};
267-
let glyph_offsets = match glyph_offsets {
268-
None => ptr::null(),
269-
Some(glyph_offsets) => {
270-
assert_eq!(glyph_offsets.len(), glyph_indices.len());
271-
glyph_offsets.as_ptr()
347+
glyph_advances.as_ptr()
348+
}
349+
};
350+
let glyph_offsets = match glyph_offsets {
351+
None => ptr::null(),
352+
Some(glyph_offsets) => {
353+
if glyph_offsets.len() != glyph_indices.len() {
354+
return Err(GlyphRunOutlineError::InvalidInput);
272355
}
273-
};
274-
let is_sideways = if is_sideways { TRUE } else { FALSE };
275-
let is_right_to_left = if is_right_to_left { TRUE } else { FALSE };
276-
let geometry_sink = GeometrySinkImpl::new(outline_builder);
277-
let geometry_sink = geometry_sink.into_interface();
356+
glyph_offsets.as_ptr()
357+
}
358+
};
359+
let is_sideways = if is_sideways { TRUE } else { FALSE };
360+
let is_right_to_left = if is_right_to_left { TRUE } else { FALSE };
361+
let geometry_sink = GeometrySinkImpl::new(outline_builder);
362+
let geometry_sink = geometry_sink.into_interface();
363+
unsafe {
278364
let hr = (*self.native.get()).GetGlyphRunOutline(
279365
em_size,
280366
glyph_indices.as_ptr(),
@@ -285,8 +371,11 @@ impl FontFace {
285371
is_right_to_left,
286372
geometry_sink,
287373
);
288-
assert_eq!(hr, S_OK);
374+
if hr != S_OK {
375+
return Err(GlyphRunOutlineError::Win32Error(hr));
376+
}
289377
}
378+
Ok(())
290379
}
291380

292381
pub fn has_kerning_pairs(&self) -> bool {
@@ -298,7 +387,17 @@ impl FontFace {
298387
}
299388
}
300389

390+
#[deprecated(note = "Use `glyph_pair_kerning_adjustment` instead.")]
301391
pub fn get_glyph_pair_kerning_adjustment(&self, first_glyph: u16, second_glyph: u16) -> i32 {
392+
self.glyph_pair_kerning_adjustment(first_glyph, second_glyph)
393+
.unwrap()
394+
}
395+
396+
pub fn glyph_pair_kerning_adjustment(
397+
&self,
398+
first_glyph: u16,
399+
second_glyph: u16,
400+
) -> Result<i32, HRESULT> {
302401
unsafe {
303402
match self.get_face1() {
304403
Some(face1) => {
@@ -308,11 +407,13 @@ impl FontFace {
308407
[first_glyph, second_glyph].as_ptr(),
309408
adjustments.as_mut_ptr(),
310409
);
311-
assert_eq!(hr, S_OK);
410+
if hr != S_OK {
411+
return Err(hr);
412+
}
312413

313-
adjustments[0]
414+
Ok(adjustments[0])
314415
}
315-
None => 0,
416+
None => Ok(0),
316417
}
317418
}
318419
}
@@ -420,3 +521,20 @@ pub enum FontFaceType {
420521
Vector,
421522
Bitmap,
422523
}
524+
525+
#[derive(Debug)]
526+
pub enum GlyphRunOutlineError {
527+
InvalidInput,
528+
Win32Error(HRESULT),
529+
}
530+
531+
impl fmt::Display for GlyphRunOutlineError {
532+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
533+
match self {
534+
Self::InvalidInput => write!(f, "Invalid input"),
535+
Self::Win32Error(code) => write!(f, "{:#x}", code),
536+
}
537+
}
538+
}
539+
540+
impl error::Error for GlyphRunOutlineError {}

0 commit comments

Comments
 (0)