use std::slice;
use std::ptr;
use std::cell::UnsafeCell;
use std::mem::zeroed;
use comptr::ComPtr;
use super::{FontMetrics, FontFile, DefaultDWriteRenderParams};
use winapi;
#[derive(Debug)]
pub struct FontFace {
native: UnsafeCell<ComPtr<winapi::IDWriteFontFace>>,
metrics: FontMetrics,
}
impl FontFace {
pub fn take(native: ComPtr<winapi::IDWriteFontFace>) -> FontFace {
unsafe {
let mut metrics: FontMetrics = zeroed();
let cell = UnsafeCell::new(native);
(*cell.get()).GetMetrics(&mut metrics);
FontFace {
native: cell,
metrics: metrics,
}
}
}
pub unsafe fn as_ptr(&self) -> *mut winapi::IDWriteFontFace {
(*self.native.get()).as_ptr()
}
pub fn get_files(&self) -> Vec<FontFile> {
unsafe {
let mut number_of_files: u32 = 0;
let hr = (*self.native.get()).GetFiles(&mut number_of_files, ptr::null_mut());
assert!(hr == 0);
let mut file_ptrs: Vec<*mut winapi::IDWriteFontFile> =
vec![ptr::null_mut(); number_of_files as usize];
let hr = (*self.native.get()).GetFiles(&mut number_of_files, file_ptrs.as_mut_ptr());
assert!(hr == 0);
file_ptrs.iter().map(|p| FontFile::take(ComPtr::already_addrefed(*p))).collect()
}
}
pub fn get_glyph_count(&self) -> u16 {
unsafe {
(*self.native.get()).GetGlyphCount()
}
}
pub fn metrics(&self) -> &FontMetrics {
&self.metrics
}
pub fn get_metrics(&self) -> FontMetrics {
unsafe {
let mut metrics: winapi::DWRITE_FONT_METRICS = zeroed();
(*self.native.get()).GetMetrics(&mut metrics);
metrics
}
}
pub fn get_glyph_indices(&self, code_points: &[u32]) -> Vec<u16> {
unsafe {
let mut glyph_indices: Vec<u16> = vec![0; code_points.len()];
let hr = (*self.native.get()).GetGlyphIndices(code_points.as_ptr(),
code_points.len() as u32,
glyph_indices.as_mut_ptr());
assert!(hr == 0);
glyph_indices
}
}
pub fn get_design_glyph_metrics(&self, glyph_indices: &[u16], is_sideways: bool) -> Vec<winapi::DWRITE_GLYPH_METRICS> {
unsafe {
let mut metrics: Vec<winapi::DWRITE_GLYPH_METRICS> = vec![zeroed(); glyph_indices.len()];
let hr = (*self.native.get()).GetDesignGlyphMetrics(glyph_indices.as_ptr(),
glyph_indices.len() as u32,
metrics.as_mut_ptr(),
is_sideways as winapi::BOOL);
assert!(hr == 0);
metrics
}
}
pub fn get_gdi_compatible_glyph_metrics(&self, em_size: f32, pixels_per_dip: f32, transform: *const winapi::DWRITE_MATRIX,
use_gdi_natural: bool, glyph_indices: &[u16], is_sideways: bool)
-> Vec<winapi::DWRITE_GLYPH_METRICS>
{
unsafe {
let mut metrics: Vec<winapi::DWRITE_GLYPH_METRICS> = vec![zeroed(); glyph_indices.len()];
let hr = (*self.native.get()).GetGdiCompatibleGlyphMetrics(em_size, pixels_per_dip,
transform,
use_gdi_natural as winapi::BOOL,
glyph_indices.as_ptr(),
glyph_indices.len() as u32,
metrics.as_mut_ptr(),
is_sideways as winapi::BOOL);
assert!(hr == 0);
metrics
}
}
pub fn get_font_table(&self, opentype_table_tag: u32) -> Option<Vec<u8>> {
unsafe {
let mut table_data_ptr: *const u8 = ptr::null_mut();
let mut table_size: u32 = 0;
let mut table_context: *mut winapi::c_void = ptr::null_mut();
let mut exists: winapi::BOOL = winapi::FALSE;
let hr = (*self.native.get()).TryGetFontTable(opentype_table_tag,
&mut table_data_ptr as *mut *const _ as *mut *const winapi::c_void,
&mut table_size,
&mut table_context,
&mut exists);
assert!(hr == 0);
if exists == winapi::FALSE {
return None;
}
let table_bytes = slice::from_raw_parts(table_data_ptr, table_size as usize).to_vec();
(*self.native.get()).ReleaseFontTable(table_context);
Some(table_bytes)
}
}
pub fn get_recommended_rendering_mode(&self,
em_size: f32,
pixels_per_dip: f32,
measure_mode: winapi::DWRITE_MEASURING_MODE,
rendering_params: *mut winapi::IDWriteRenderingParams) ->
winapi::DWRITE_RENDERING_MODE {
unsafe {
let mut render_mode : winapi::DWRITE_RENDERING_MODE = winapi::DWRITE_RENDERING_MODE_DEFAULT;
let hr = (*self.native.get()).GetRecommendedRenderingMode(em_size,
pixels_per_dip,
measure_mode,
rendering_params,
&mut render_mode);
if !(hr != 0) {
return winapi::DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC;
}
render_mode
}
}
pub fn get_recommended_rendering_mode_default_params(&self,
em_size: f32,
pixels_per_dip: f32,
measure_mode: winapi::DWRITE_MEASURING_MODE) ->
winapi::DWRITE_RENDERING_MODE {
self.get_recommended_rendering_mode(em_size,
pixels_per_dip,
measure_mode,
DefaultDWriteRenderParams())
}
}