Skip to content

Commit 1b19b79

Browse files
committed
Expose bindings to the following:
* Simulations * Informational strings * Metrics * Outlines * Fetching the font corresponding to a face
1 parent 2d2b4c8 commit 1b19b79

11 files changed

+437
-13
lines changed

Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ name = "dwrote"
33
description = "Lightweight binding to DirectWrite."
44
repository = "https://github.com/servo/dwrote-rs"
55
license = "MPL-2.0"
6-
version = "0.4.2"
6+
version = "0.4.3"
77
authors = ["Vladimir Vukicevic <[email protected]>"]
88

99
[lib]

src/com_helpers.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ macro_rules! implement_iunknown {
6161
QueryInterface: {
6262
unsafe extern "system" fn QueryInterface(This: *mut IUnknown,
6363
riid: REFIID,
64-
ppvObject: *mut *mut c_void) -> HRESULT {
64+
ppvObject: *mut *mut $crate::winapi::ctypes::c_void) -> HRESULT {
6565
let this = if guid_equals!(*riid, $iuud) {
6666
mem::transmute(This)
6767
} else if guid_equals!(*riid, UuidOfIUnknown) {

src/font.rs

+45-2
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,12 @@
55
use std::cell::UnsafeCell;
66

77
use comptr::ComPtr;
8-
use winapi::um::dwrite::{IDWriteFontFace, IDWriteLocalizedStrings, IDWriteFont};
9-
use winapi::um::dwrite::IDWriteFontFamily;
8+
use winapi::shared::minwindef::{BOOL, FALSE, TRUE};
9+
use winapi::shared::winerror::S_OK;
10+
use winapi::um::dwrite::{DWRITE_FONT_METRICS, DWRITE_INFORMATIONAL_STRING_FULL_NAME, DWRITE_INFORMATIONAL_STRING_ID};
11+
use winapi::um::dwrite::{DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_CID_NAME};
12+
use winapi::um::dwrite::{DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_NAME, IDWriteFontFace};
13+
use winapi::um::dwrite::{IDWriteLocalizedStrings, IDWriteFont, IDWriteFontFamily};
1014
use std::mem;
1115

1216
use super::*;
@@ -54,6 +58,12 @@ impl Font {
5458
}
5559
}
5660

61+
pub fn simulations(&self) -> FontSimulations {
62+
unsafe {
63+
mem::transmute::<u32, FontSimulations>((*self.native.get()).GetSimulations())
64+
}
65+
}
66+
5767
pub fn family_name(&self) -> String {
5868
unsafe {
5969
let mut family: ComPtr<IDWriteFontFamily> = ComPtr::new();
@@ -74,6 +84,23 @@ impl Font {
7484
}
7585
}
7686

87+
pub fn informational_string(&self, id: InformationalStringId) -> Option<String> {
88+
unsafe {
89+
let mut names: ComPtr<IDWriteLocalizedStrings> = ComPtr::new();
90+
let mut exists = FALSE;
91+
let id = id as DWRITE_INFORMATIONAL_STRING_ID;
92+
let hr = (*self.native.get()).GetInformationalStrings(id,
93+
names.getter_addrefs(),
94+
&mut exists);
95+
assert!(hr == S_OK);
96+
if exists == TRUE {
97+
Some(get_locale_string(&mut names))
98+
} else {
99+
None
100+
}
101+
}
102+
}
103+
77104
pub fn create_font_face(&self) -> FontFace {
78105
// FIXME create_font_face should cache the FontFace and return it,
79106
// there's a 1:1 relationship
@@ -84,4 +111,20 @@ impl Font {
84111
FontFace::take(face)
85112
}
86113
}
114+
115+
pub fn metrics(&self) -> DWRITE_FONT_METRICS {
116+
unsafe {
117+
let mut metrics = mem::zeroed();
118+
(*self.native.get()).GetMetrics(&mut metrics);
119+
metrics
120+
}
121+
}
122+
}
123+
124+
#[repr(u32)]
125+
#[derive(Clone, Copy, Debug, PartialEq)]
126+
pub enum InformationalStringId {
127+
FullName = DWRITE_INFORMATIONAL_STRING_FULL_NAME,
128+
PostscriptName = DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_NAME,
129+
PostscriptCidName = DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_CID_NAME,
87130
}

src/font_collection_impl.rs

+157
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
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+
// A temporary custom font collection that exists solely for the face-to-font mapping to work.
6+
7+
use std::mem;
8+
use std::sync::atomic::AtomicUsize;
9+
use winapi::ctypes::c_void;
10+
use winapi::shared::guiddef::REFIID;
11+
use winapi::shared::minwindef::{BOOL, FALSE, TRUE, ULONG};
12+
use winapi::shared::winerror::S_OK;
13+
use winapi::um::dwrite::{IDWriteFactory, IDWriteFontCollectionLoader};
14+
use winapi::um::dwrite::{IDWriteFontCollectionLoaderVtbl, IDWriteFontFile, IDWriteFontFileEnumerator};
15+
use winapi::um::dwrite::{IDWriteFontFileEnumeratorVtbl};
16+
use winapi::um::unknwnbase::{IUnknown, IUnknownVtbl};
17+
use winapi::um::winnt::HRESULT;
18+
19+
use com_helpers::{Com, UuidOfIUnknown};
20+
use comptr::ComPtr;
21+
22+
DEFINE_GUID! {
23+
DWRITE_FONT_COLLECTION_LOADER_UUID,
24+
0x12345678, 0x1234, 0x5678, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0
25+
}
26+
DEFINE_GUID! {
27+
DWRITE_FONT_FILE_ENUMERATOR_UUID,
28+
0x12345678, 0x1234, 0x5678, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0
29+
}
30+
31+
static FONT_COLLECTION_LOADER_VTBL: IDWriteFontCollectionLoaderVtbl =
32+
IDWriteFontCollectionLoaderVtbl {
33+
parent: implement_iunknown!(static IDWriteFontCollectionLoader,
34+
DWRITE_FONT_COLLECTION_LOADER_UUID,
35+
FontCollectionLoaderImpl),
36+
CreateEnumeratorFromKey: FontCollectionLoaderImpl_CreateEnumeratorFromKey,
37+
};
38+
39+
pub struct FontCollectionLoaderImpl {
40+
refcount: AtomicUsize,
41+
font_file: ComPtr<IDWriteFontFile>,
42+
}
43+
44+
impl Com<IDWriteFontCollectionLoader> for FontCollectionLoaderImpl {
45+
type Vtbl = IDWriteFontCollectionLoaderVtbl;
46+
#[inline]
47+
fn vtbl() -> &'static IDWriteFontCollectionLoaderVtbl {
48+
&FONT_COLLECTION_LOADER_VTBL
49+
}
50+
}
51+
52+
impl Com<IUnknown> for FontCollectionLoaderImpl {
53+
type Vtbl = IUnknownVtbl;
54+
#[inline]
55+
fn vtbl() -> &'static IUnknownVtbl {
56+
&FONT_COLLECTION_LOADER_VTBL.parent
57+
}
58+
}
59+
60+
impl FontCollectionLoaderImpl {
61+
pub fn new(font_file: ComPtr<IDWriteFontFile>) -> FontCollectionLoaderImpl {
62+
FontCollectionLoaderImpl {
63+
refcount: AtomicUsize::new(1),
64+
font_file,
65+
}
66+
}
67+
}
68+
69+
unsafe extern "system" fn FontCollectionLoaderImpl_CreateEnumeratorFromKey(
70+
this: *mut IDWriteFontCollectionLoader,
71+
_: *mut IDWriteFactory,
72+
_: *const c_void,
73+
_: u32,
74+
out_enumerator: *mut *mut IDWriteFontFileEnumerator)
75+
-> HRESULT {
76+
let this = FontCollectionLoaderImpl::from_interface(this);
77+
let enumerator = FontFileEnumeratorImpl::new((*this).font_file.clone());
78+
let enumerator = ComPtr::<IDWriteFontFileEnumerator>::from_ptr(enumerator.into_interface());
79+
*out_enumerator = enumerator.as_ptr();
80+
S_OK
81+
}
82+
83+
struct FontFileEnumeratorImpl {
84+
refcount: AtomicUsize,
85+
font_file: ComPtr<IDWriteFontFile>,
86+
state: FontFileEnumeratorImplState,
87+
}
88+
89+
impl Com<IDWriteFontFileEnumerator> for FontFileEnumeratorImpl {
90+
type Vtbl = IDWriteFontFileEnumeratorVtbl;
91+
#[inline]
92+
fn vtbl() -> &'static IDWriteFontFileEnumeratorVtbl {
93+
&FONT_FILE_ENUMERATOR_VTBL
94+
}
95+
}
96+
97+
impl Com<IUnknown> for FontFileEnumeratorImpl {
98+
type Vtbl = IUnknownVtbl;
99+
#[inline]
100+
fn vtbl() -> &'static IUnknownVtbl {
101+
&FONT_FILE_ENUMERATOR_VTBL.parent
102+
}
103+
}
104+
105+
static FONT_FILE_ENUMERATOR_VTBL: IDWriteFontFileEnumeratorVtbl = IDWriteFontFileEnumeratorVtbl {
106+
parent: implement_iunknown!(static IDWriteFontFileEnumerator,
107+
DWRITE_FONT_FILE_ENUMERATOR_UUID,
108+
FontFileEnumeratorImpl),
109+
GetCurrentFontFile: FontFileEnumeratorImpl_GetCurrentFontFile,
110+
MoveNext: FontFileEnumeratorImpl_MoveNext,
111+
};
112+
113+
impl FontFileEnumeratorImpl {
114+
pub fn new(font_file: ComPtr<IDWriteFontFile>) -> FontFileEnumeratorImpl {
115+
FontFileEnumeratorImpl {
116+
refcount: AtomicUsize::new(1),
117+
font_file,
118+
state: FontFileEnumeratorImplState::Start,
119+
}
120+
}
121+
}
122+
123+
unsafe extern "system" fn FontFileEnumeratorImpl_GetCurrentFontFile(
124+
this: *mut IDWriteFontFileEnumerator,
125+
out_font_file: *mut *mut IDWriteFontFile)
126+
-> HRESULT {
127+
// Follow Postel's law...
128+
let this = FontFileEnumeratorImpl::from_interface(this);
129+
*out_font_file = (*this).font_file.clone().as_ptr();
130+
S_OK
131+
}
132+
133+
unsafe extern "system" fn FontFileEnumeratorImpl_MoveNext(this: *mut IDWriteFontFileEnumerator,
134+
has_current_file: *mut BOOL)
135+
-> HRESULT {
136+
let this = FontFileEnumeratorImpl::from_interface(this);
137+
match (*this).state {
138+
FontFileEnumeratorImplState::Start => {
139+
(*this).state = FontFileEnumeratorImplState::Running;
140+
(*has_current_file) = TRUE;
141+
}
142+
FontFileEnumeratorImplState::Running => {
143+
(*this).state = FontFileEnumeratorImplState::End;
144+
(*has_current_file) = FALSE;
145+
}
146+
FontFileEnumeratorImplState::End => (*has_current_file) = FALSE,
147+
}
148+
149+
S_OK
150+
}
151+
152+
#[derive(Clone, Copy, Debug)]
153+
enum FontFileEnumeratorImplState {
154+
Start,
155+
Running,
156+
End,
157+
}

src/font_face.rs

+85-6
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,24 @@
55
use std::slice;
66
use std::ptr;
77
use std::cell::UnsafeCell;
8-
use std::mem::zeroed;
8+
use std::mem::{self, zeroed};
99

10+
use com_helpers::Com;
1011
use comptr::ComPtr;
12+
use font::Font;
13+
use font_collection_impl::FontCollectionLoaderImpl;
14+
use geometry_sink_impl::GeometrySinkImpl;
15+
use outline_builder::OutlineBuilder;
1116
use super::{FontMetrics, FontFile, DefaultDWriteRenderParams, DWriteFactory};
1217

13-
use winapi::um::dwrite::{DWRITE_RENDERING_MODE, DWRITE_RENDERING_MODE_DEFAULT};
14-
use winapi::um::dwrite::{DWRITE_FONT_METRICS, DWRITE_FONT_SIMULATIONS, DWRITE_MATRIX};
15-
use winapi::um::dwrite::{DWRITE_GLYPH_METRICS, DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC};
16-
use winapi::um::dwrite::{IDWriteRenderingParams, IDWriteFontFace, IDWriteFontFile};
17-
use winapi::shared::minwindef::{BOOL, FALSE};
1818
use winapi::ctypes::c_void;
19+
use winapi::shared::minwindef::{BOOL, FALSE, TRUE};
20+
use winapi::shared::winerror::S_OK;
1921
use winapi::um::dcommon::DWRITE_MEASURING_MODE;
22+
use winapi::um::dwrite::{DWRITE_GLYPH_OFFSET, DWRITE_RENDERING_MODE, DWRITE_RENDERING_MODE_DEFAULT};
23+
use winapi::um::dwrite::{DWRITE_FONT_METRICS, DWRITE_FONT_SIMULATIONS, DWRITE_MATRIX};
24+
use winapi::um::dwrite::{DWRITE_GLYPH_METRICS, DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC};
25+
use winapi::um::dwrite::{IDWriteFont, IDWriteFontFace, IDWriteFontFile, IDWriteRenderingParams};
2026

2127
pub struct FontFace {
2228
native: UnsafeCell<ComPtr<IDWriteFontFace>>,
@@ -198,4 +204,77 @@ impl FontFace {
198204
measure_mode,
199205
DefaultDWriteRenderParams())
200206
}
207+
208+
// A convenience method to get the `IDWriteFont` object corresponding to this
209+
// `IDWriteFontFace`.
210+
pub fn get_font(&self) -> Font {
211+
unsafe {
212+
// TODO(pcwalton): Support multiple files.
213+
let factory = DWriteFactory();
214+
let font_files = self.get_files();
215+
let collection_loader = FontCollectionLoaderImpl::new(font_files[0].as_com_ptr());
216+
let collection_loader = collection_loader.into_interface();
217+
assert_eq!((*factory).RegisterFontCollectionLoader(collection_loader.clone()), S_OK);
218+
let mut collection = ptr::null_mut();
219+
assert_eq!((*factory).CreateCustomFontCollection(collection_loader,
220+
ptr::null(),
221+
0,
222+
&mut collection),
223+
S_OK);
224+
let mut font: ComPtr<IDWriteFont> = ComPtr::new();
225+
assert_eq!((*collection).GetFontFromFontFace(self.as_ptr(), font.getter_addrefs()),
226+
S_OK);
227+
Font::take(font)
228+
}
229+
}
230+
231+
pub fn get_glyph_run_outline(&self,
232+
em_size: f32,
233+
glyph_indices: &[u16],
234+
glyph_advances: Option<&[f32]>,
235+
glyph_offsets: Option<&[DWRITE_GLYPH_OFFSET]>,
236+
is_sideways: bool,
237+
is_right_to_left: bool,
238+
outline_builder: Box<OutlineBuilder>) {
239+
unsafe {
240+
let glyph_advances = match glyph_advances {
241+
None => ptr::null(),
242+
Some(glyph_advances) => {
243+
assert_eq!(glyph_advances.len(), glyph_indices.len());
244+
glyph_advances.as_ptr()
245+
}
246+
};
247+
let glyph_offsets = match glyph_offsets {
248+
None => ptr::null(),
249+
Some(glyph_offsets) => {
250+
assert_eq!(glyph_offsets.len(), glyph_indices.len());
251+
glyph_offsets.as_ptr()
252+
}
253+
};
254+
let is_sideways = if is_sideways { TRUE } else { FALSE };
255+
let is_right_to_left = if is_right_to_left { TRUE } else { FALSE };
256+
let geometry_sink = GeometrySinkImpl::new(outline_builder);
257+
let geometry_sink = geometry_sink.into_interface();
258+
let hr = (*self.native.get()).GetGlyphRunOutline(em_size,
259+
glyph_indices.as_ptr(),
260+
glyph_advances,
261+
glyph_offsets,
262+
glyph_indices.len() as u32,
263+
is_sideways,
264+
is_right_to_left,
265+
geometry_sink);
266+
assert_eq!(hr, S_OK);
267+
}
268+
}
269+
}
270+
271+
impl Clone for FontFace {
272+
fn clone(&self) -> FontFace {
273+
unsafe {
274+
FontFace {
275+
native: UnsafeCell::new((*self.native.get()).clone()),
276+
metrics: self.metrics,
277+
}
278+
}
279+
}
201280
}

src/font_file.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,12 @@ impl FontFile {
7676
}
7777
}
7878

79+
pub(crate) unsafe fn as_com_ptr(&self) -> ComPtr<IDWriteFontFile> {
80+
(*self.native.get()).clone()
81+
}
82+
7983
pub unsafe fn as_ptr(&self) -> *mut IDWriteFontFile {
80-
(*self.native.get()).as_ptr()
84+
self.as_com_ptr().as_ptr()
8185
}
8286

8387
// This is a helper to read the contents of this FontFile,

src/font_file_loader_impl.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
use std::{mem, ptr};
44
use std::collections::HashMap;
5+
use std::sync::atomic::AtomicUsize;
56
use std::sync::{Mutex, atomic};
67
use std::marker::Send;
78
use winapi::ctypes::c_void;
@@ -133,7 +134,7 @@ const FontFileStreamVtbl: &'static IDWriteFontFileStreamVtbl = &IDWriteFontFileS
133134
impl FontFileStream {
134135
pub fn new(data: &[u8]) -> FontFileStream {
135136
FontFileStream {
136-
refcount: atomic::ATOMIC_USIZE_INIT,
137+
refcount: AtomicUsize::new(1),
137138
data: data.to_vec(),
138139
}
139140
}

0 commit comments

Comments
 (0)