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;
7 use std::ptr;
8 use winapi::shared::minwindef::{FALSE, TRUE};
9 use winapi::shared::winerror::S_OK;
10 use winapi::um::dwrite::IDWriteFont;
11 use winapi::um::dwrite::IDWriteFontFace;
12 use winapi::um::dwrite::IDWriteFontFamily;
13 use winapi::um::dwrite::IDWriteLocalizedStrings;
14 use winapi::um::dwrite::DWRITE_FONT_METRICS;
15 use winapi::um::dwrite::DWRITE_INFORMATIONAL_STRING_FULL_NAME;
16 use winapi::um::dwrite::DWRITE_INFORMATIONAL_STRING_ID;
17 use winapi::um::dwrite::DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_CID_NAME;
18 use winapi::um::dwrite::DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_NAME;
19 use winapi::um::dwrite_1::{IDWriteFont1, DWRITE_FONT_METRICS1};
20 use wio::com::ComPtr;
21 
22 use super::*;
23 use helpers::*;
24 
25 pub struct Font {
26     native: UnsafeCell<ComPtr<IDWriteFont>>,
27 }
28 
29 impl Font {
take(native: ComPtr<IDWriteFont>) -> Font30     pub fn take(native: ComPtr<IDWriteFont>) -> Font {
31         Font {
32             native: UnsafeCell::new(native),
33         }
34     }
35 
as_ptr(&self) -> *mut IDWriteFont36     pub unsafe fn as_ptr(&self) -> *mut IDWriteFont {
37         (*self.native.get()).as_raw()
38     }
39 
to_descriptor(&self) -> FontDescriptor40     pub fn to_descriptor(&self) -> FontDescriptor {
41         FontDescriptor {
42             family_name: self.family_name(),
43             stretch: self.stretch(),
44             style: self.style(),
45             weight: self.weight(),
46         }
47     }
48 
stretch(&self) -> FontStretch49     pub fn stretch(&self) -> FontStretch {
50         unsafe { mem::transmute::<u32, FontStretch>((*self.native.get()).GetStretch()) }
51     }
52 
style(&self) -> FontStyle53     pub fn style(&self) -> FontStyle {
54         unsafe { mem::transmute::<u32, FontStyle>((*self.native.get()).GetStyle()) }
55     }
56 
weight(&self) -> FontWeight57     pub fn weight(&self) -> FontWeight {
58         unsafe { FontWeight::from_u32((*self.native.get()).GetWeight()) }
59     }
60 
is_monospace(&self) -> Option<bool>61     pub fn is_monospace(&self) -> Option<bool> {
62         unsafe {
63             let font1: Option<ComPtr<IDWriteFont1>> = (*self.native.get()).cast().ok();
64             font1.map(|font| font.IsMonospacedFont() == TRUE)
65         }
66     }
67 
simulations(&self) -> FontSimulations68     pub fn simulations(&self) -> FontSimulations {
69         unsafe { mem::transmute::<u32, FontSimulations>((*self.native.get()).GetSimulations()) }
70     }
71 
family_name(&self) -> String72     pub fn family_name(&self) -> String {
73         unsafe {
74             let mut family: *mut IDWriteFontFamily = ptr::null_mut();
75             let hr = (*self.native.get()).GetFontFamily(&mut family);
76             assert!(hr == 0);
77 
78             FontFamily::take(ComPtr::from_raw(family)).name()
79         }
80     }
81 
face_name(&self) -> String82     pub fn face_name(&self) -> String {
83         unsafe {
84             let mut names: *mut IDWriteLocalizedStrings = ptr::null_mut();
85             let hr = (*self.native.get()).GetFaceNames(&mut names);
86             assert!(hr == 0);
87 
88             get_locale_string(&mut ComPtr::from_raw(names))
89         }
90     }
91 
informational_string(&self, id: InformationalStringId) -> Option<String>92     pub fn informational_string(&self, id: InformationalStringId) -> Option<String> {
93         unsafe {
94             let mut names: *mut IDWriteLocalizedStrings = ptr::null_mut();
95             let mut exists = FALSE;
96             let id = id as DWRITE_INFORMATIONAL_STRING_ID;
97             let hr = (*self.native.get()).GetInformationalStrings(id, &mut names, &mut exists);
98             assert!(hr == S_OK);
99             if exists == TRUE {
100                 Some(get_locale_string(&mut ComPtr::from_raw(names)))
101             } else {
102                 None
103             }
104         }
105     }
106 
create_font_face(&self) -> FontFace107     pub fn create_font_face(&self) -> FontFace {
108         // FIXME create_font_face should cache the FontFace and return it,
109         // there's a 1:1 relationship
110         unsafe {
111             let mut face: *mut IDWriteFontFace = ptr::null_mut();
112             let hr = (*self.native.get()).CreateFontFace(&mut face);
113             assert!(hr == 0);
114             FontFace::take(ComPtr::from_raw(face))
115         }
116     }
117 
metrics(&self) -> FontMetrics118     pub fn metrics(&self) -> FontMetrics {
119         unsafe {
120             let font_1: Option<ComPtr<IDWriteFont1>> = (*self.native.get()).cast().ok();
121             match font_1 {
122                 None => {
123                     let mut metrics = mem::zeroed();
124                     (*self.native.get()).GetMetrics(&mut metrics);
125                     FontMetrics::Metrics0(metrics)
126                 }
127                 Some(font_1) => {
128                     let mut metrics_1 = mem::zeroed();
129                     font_1.GetMetrics(&mut metrics_1);
130                     FontMetrics::Metrics1(metrics_1)
131                 }
132             }
133         }
134     }
135 }
136 
137 impl Clone for Font {
clone(&self) -> Font138     fn clone(&self) -> Font {
139         unsafe {
140             Font {
141                 native: UnsafeCell::new((*self.native.get()).clone()),
142             }
143         }
144     }
145 }
146 
147 #[repr(u32)]
148 #[derive(Clone, Copy, Debug, PartialEq)]
149 pub enum InformationalStringId {
150     FullName = DWRITE_INFORMATIONAL_STRING_FULL_NAME,
151     PostscriptName = DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_NAME,
152     PostscriptCidName = DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_CID_NAME,
153 }
154 
155 /// A wrapper around the `DWRITE_FONT_METRICS` and `DWRITE_FONT_METRICS1` types.
156 pub enum FontMetrics {
157     /// Windows 7.
158     Metrics0(DWRITE_FONT_METRICS),
159     /// Windows 8 and up.
160     Metrics1(DWRITE_FONT_METRICS1),
161 }
162 
163 impl FontMetrics {
164     /// Convert self to the Metrics0 arm (throwing away additional information)
metrics0(self) -> DWRITE_FONT_METRICS165     pub fn metrics0(self) -> DWRITE_FONT_METRICS {
166         match self {
167             FontMetrics::Metrics0(metrics) => metrics,
168             FontMetrics::Metrics1(metrics) => DWRITE_FONT_METRICS {
169                 designUnitsPerEm: metrics.designUnitsPerEm,
170                 ascent: metrics.ascent,
171                 descent: metrics.descent,
172                 lineGap: metrics.lineGap,
173                 capHeight: metrics.capHeight,
174                 xHeight: metrics.xHeight,
175                 underlinePosition: metrics.underlinePosition,
176                 underlineThickness: metrics.underlineThickness,
177                 strikethroughPosition: metrics.strikethroughPosition,
178                 strikethroughThickness: metrics.strikethroughThickness,
179             }
180         }
181     }
182 }
183