Source code

Revision control

Copy as Markdown

Other Tools

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use std::cell::UnsafeCell;
use std::mem;
use std::ptr;
use winapi::shared::minwindef::{FALSE, TRUE};
use winapi::shared::winerror::S_OK;
use winapi::um::dwrite::IDWriteFont;
use winapi::um::dwrite::IDWriteFontFace;
use winapi::um::dwrite::IDWriteFontFamily;
use winapi::um::dwrite::IDWriteLocalizedStrings;
use winapi::um::dwrite::DWRITE_FONT_METRICS;
use winapi::um::dwrite::DWRITE_INFORMATIONAL_STRING_FULL_NAME;
use winapi::um::dwrite::DWRITE_INFORMATIONAL_STRING_ID;
use winapi::um::dwrite::DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_CID_NAME;
use winapi::um::dwrite::DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_NAME;
use winapi::um::dwrite_1::{IDWriteFont1, DWRITE_FONT_METRICS1};
use wio::com::ComPtr;
use super::*;
use helpers::*;
pub struct Font {
native: UnsafeCell<ComPtr<IDWriteFont>>,
}
impl Font {
pub fn take(native: ComPtr<IDWriteFont>) -> Font {
Font {
native: UnsafeCell::new(native),
}
}
pub unsafe fn as_ptr(&self) -> *mut IDWriteFont {
(*self.native.get()).as_raw()
}
pub fn to_descriptor(&self) -> FontDescriptor {
FontDescriptor {
family_name: self.family_name(),
stretch: self.stretch(),
style: self.style(),
weight: self.weight(),
}
}
pub fn stretch(&self) -> FontStretch {
unsafe { mem::transmute::<u32, FontStretch>((*self.native.get()).GetStretch()) }
}
pub fn style(&self) -> FontStyle {
unsafe { mem::transmute::<u32, FontStyle>((*self.native.get()).GetStyle()) }
}
pub fn weight(&self) -> FontWeight {
unsafe { FontWeight::from_u32((*self.native.get()).GetWeight()) }
}
pub fn is_monospace(&self) -> Option<bool> {
unsafe {
let font1: Option<ComPtr<IDWriteFont1>> = (*self.native.get()).cast().ok();
font1.map(|font| font.IsMonospacedFont() == TRUE)
}
}
pub fn simulations(&self) -> FontSimulations {
unsafe { mem::transmute::<u32, FontSimulations>((*self.native.get()).GetSimulations()) }
}
pub fn family_name(&self) -> String {
unsafe {
let mut family: *mut IDWriteFontFamily = ptr::null_mut();
let hr = (*self.native.get()).GetFontFamily(&mut family);
assert!(hr == 0);
FontFamily::take(ComPtr::from_raw(family)).name()
}
}
pub fn face_name(&self) -> String {
unsafe {
let mut names: *mut IDWriteLocalizedStrings = ptr::null_mut();
let hr = (*self.native.get()).GetFaceNames(&mut names);
assert!(hr == 0);
get_locale_string(&mut ComPtr::from_raw(names))
}
}
pub fn informational_string(&self, id: InformationalStringId) -> Option<String> {
unsafe {
let mut names: *mut IDWriteLocalizedStrings = ptr::null_mut();
let mut exists = FALSE;
let id = id as DWRITE_INFORMATIONAL_STRING_ID;
let hr = (*self.native.get()).GetInformationalStrings(id, &mut names, &mut exists);
assert!(hr == S_OK);
if exists == TRUE {
Some(get_locale_string(&mut ComPtr::from_raw(names)))
} else {
None
}
}
}
pub fn create_font_face(&self) -> FontFace {
// FIXME create_font_face should cache the FontFace and return it,
// there's a 1:1 relationship
unsafe {
let mut face: *mut IDWriteFontFace = ptr::null_mut();
let hr = (*self.native.get()).CreateFontFace(&mut face);
assert!(hr == 0);
FontFace::take(ComPtr::from_raw(face))
}
}
pub fn metrics(&self) -> FontMetrics {
unsafe {
let font_1: Option<ComPtr<IDWriteFont1>> = (*self.native.get()).cast().ok();
match font_1 {
None => {
let mut metrics = mem::zeroed();
(*self.native.get()).GetMetrics(&mut metrics);
FontMetrics::Metrics0(metrics)
}
Some(font_1) => {
let mut metrics_1 = mem::zeroed();
font_1.GetMetrics(&mut metrics_1);
FontMetrics::Metrics1(metrics_1)
}
}
}
}
}
impl Clone for Font {
fn clone(&self) -> Font {
unsafe {
Font {
native: UnsafeCell::new((*self.native.get()).clone()),
}
}
}
}
#[repr(u32)]
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum InformationalStringId {
FullName = DWRITE_INFORMATIONAL_STRING_FULL_NAME,
PostscriptName = DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_NAME,
PostscriptCidName = DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_CID_NAME,
}
/// A wrapper around the `DWRITE_FONT_METRICS` and `DWRITE_FONT_METRICS1` types.
pub enum FontMetrics {
/// Windows 7.
Metrics0(DWRITE_FONT_METRICS),
/// Windows 8 and up.
Metrics1(DWRITE_FONT_METRICS1),
}
impl FontMetrics {
/// Convert self to the Metrics0 arm (throwing away additional information)
pub fn metrics0(self) -> DWRITE_FONT_METRICS {
match self {
FontMetrics::Metrics0(metrics) => metrics,
FontMetrics::Metrics1(metrics) => DWRITE_FONT_METRICS {
designUnitsPerEm: metrics.designUnitsPerEm,
ascent: metrics.ascent,
descent: metrics.descent,
lineGap: metrics.lineGap,
capHeight: metrics.capHeight,
xHeight: metrics.xHeight,
underlinePosition: metrics.underlinePosition,
underlineThickness: metrics.underlineThickness,
strikethroughPosition: metrics.strikethroughPosition,
strikethroughThickness: metrics.strikethroughThickness,
}
}
}
}