Skip to content

Commit

Permalink
Auto merge of vvuk#9 - pcwalton:additions, r=mbrubeck
Browse files Browse the repository at this point in the history
Expose many additional bindings

Includes bindings to the following:

* Simulations

* Informational strings

* Metrics

* Outlines

* Fetching the font corresponding to a face

r? anyone (I'm not sure who maintains this repo)
  • Loading branch information
bors-servo authored Aug 1, 2018
2 parents c1f8791 + e69c5c0 commit fc56316
Show file tree
Hide file tree
Showing 14 changed files with 553 additions and 37 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name = "dwrote"
description = "Lightweight binding to DirectWrite."
repository = "https://github.com/servo/dwrote-rs"
license = "MPL-2.0"
version = "0.4.2"
version = "0.5.0"
authors = ["Vladimir Vukicevic <[email protected]>"]

[lib]
Expand Down
4 changes: 2 additions & 2 deletions src/com_helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ macro_rules! implement_iunknown {
let this = $typ::from_interface(This);
let count = this.refcount.fetch_sub(1, atomic::Ordering::Release) - 1;
if count == 0 {
FontFileStream::destroy(This);
<$typ as Com<$interface>>::destroy(This as *mut $interface);
}
count as ULONG
}
Expand All @@ -61,7 +61,7 @@ macro_rules! implement_iunknown {
QueryInterface: {
unsafe extern "system" fn QueryInterface(This: *mut IUnknown,
riid: REFIID,
ppvObject: *mut *mut c_void) -> HRESULT {
ppvObject: *mut *mut $crate::winapi::ctypes::c_void) -> HRESULT {
let this = if guid_equals!(*riid, $iuud) {
mem::transmute(This)
} else if guid_equals!(*riid, UuidOfIUnknown) {
Expand Down
16 changes: 8 additions & 8 deletions src/comptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@ impl<T> ComPtr<T> {
ComPtr { ptr: ptr }
}

pub fn already_addrefed(ptr: *mut T) -> Self {
pub unsafe fn already_addrefed(ptr: *mut T) -> Self {
ComPtr { ptr: ptr }
}

pub fn getter_addrefs<Q>(&mut self) -> *mut *mut Q {
pub unsafe fn getter_addrefs<Q>(&mut self) -> *mut *mut Q {
self.release();
return &mut self.ptr as *mut *mut _ as *mut *mut Q;
}
Expand Down Expand Up @@ -63,11 +63,9 @@ impl<T> ComPtr<T> {
}
}

pub fn release(&self) {
unsafe {
if !self.ptr.is_null() {
(*(self.ptr as *mut IUnknown)).Release();
}
pub unsafe fn release(&self) {
if !self.ptr.is_null() {
(*(self.ptr as *mut IUnknown)).Release();
}
}

Expand Down Expand Up @@ -110,7 +108,9 @@ impl<T> PartialEq for ComPtr<T> {

impl<T> Drop for ComPtr<T> {
fn drop(&mut self) {
self.release();
unsafe {
self.release();
}
}
}

Expand Down
57 changes: 55 additions & 2 deletions src/font.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,12 @@
use std::cell::UnsafeCell;

use comptr::ComPtr;
use winapi::um::dwrite::{IDWriteFontFace, IDWriteLocalizedStrings, IDWriteFont};
use winapi::um::dwrite::IDWriteFontFamily;
use winapi::shared::minwindef::{BOOL, FALSE, TRUE};
use winapi::shared::winerror::S_OK;
use winapi::um::dwrite::{DWRITE_FONT_METRICS, DWRITE_INFORMATIONAL_STRING_FULL_NAME, DWRITE_INFORMATIONAL_STRING_ID};
use winapi::um::dwrite::{DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_CID_NAME};
use winapi::um::dwrite::{DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_NAME, IDWriteFontFace};
use winapi::um::dwrite::{IDWriteLocalizedStrings, IDWriteFont, IDWriteFontFamily};
use std::mem;

use super::*;
Expand Down Expand Up @@ -54,6 +58,12 @@ impl Font {
}
}

pub fn simulations(&self) -> FontSimulations {
unsafe {
mem::transmute::<u32, FontSimulations>((*self.native.get()).GetSimulations())
}
}

pub fn family_name(&self) -> String {
unsafe {
let mut family: ComPtr<IDWriteFontFamily> = ComPtr::new();
Expand All @@ -74,6 +84,23 @@ impl Font {
}
}

pub fn informational_string(&self, id: InformationalStringId) -> Option<String> {
unsafe {
let mut names: ComPtr<IDWriteLocalizedStrings> = ComPtr::new();
let mut exists = FALSE;
let id = id as DWRITE_INFORMATIONAL_STRING_ID;
let hr = (*self.native.get()).GetInformationalStrings(id,
names.getter_addrefs(),
&mut exists);
assert!(hr == S_OK);
if exists == TRUE {
Some(get_locale_string(&mut 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
Expand All @@ -84,4 +111,30 @@ impl Font {
FontFace::take(face)
}
}

pub fn metrics(&self) -> DWRITE_FONT_METRICS {
unsafe {
let mut metrics = mem::zeroed();
(*self.native.get()).GetMetrics(&mut metrics);
metrics
}
}
}

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,
}
28 changes: 27 additions & 1 deletion src/font_collection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,20 @@

use comptr::ComPtr;
use winapi::um::dwrite::{IDWriteFontFamily, IDWriteFont, IDWriteFontCollection};
use winapi::um::dwrite::{IDWriteFontCollectionLoader};
use winapi::shared::minwindef::{BOOL, FALSE};
use winapi::shared::winerror::S_OK;
use std::cell::UnsafeCell;
use std::mem;
use std::ptr;
use std::sync::atomic::{ATOMIC_USIZE_INIT, AtomicUsize, Ordering};

use super::{DWriteFactory, FontFamily, Font, FontFace, FontDescriptor};
use super::{CustomFontCollectionLoaderImpl, DWriteFactory, FontFamily, Font};
use super::{FontFace, FontDescriptor};
use helpers::*;
use com_helpers::Com;

static NEXT_ID: AtomicUsize = ATOMIC_USIZE_INIT;

pub struct FontCollectionFamilyIterator {
collection: ComPtr<IDWriteFontCollection>,
Expand Down Expand Up @@ -56,6 +65,23 @@ impl FontCollection {
}
}

pub fn from_loader(collection_loader: ComPtr<IDWriteFontCollectionLoader>) -> FontCollection {
unsafe {
let factory = DWriteFactory();
assert_eq!((*factory).RegisterFontCollectionLoader(collection_loader.clone().forget()),
S_OK);
let mut collection: ComPtr<IDWriteFontCollection> = ComPtr::new();
let id = NEXT_ID.fetch_add(1, Ordering::SeqCst);
assert_eq!((*factory).CreateCustomFontCollection(
collection_loader.clone().forget(),
&id as *const usize as *const _,
mem::size_of::<AtomicUsize>() as u32,
collection.getter_addrefs()),
S_OK);
FontCollection::take(collection)
}
}

pub unsafe fn as_ptr(&self) -> *mut IDWriteFontCollection {
(*self.native.get()).as_ptr()
}
Expand Down
156 changes: 156 additions & 0 deletions src/font_collection_impl.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
/* 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/. */

// A temporary custom font collection that exists solely for the face-to-font mapping to work.

use std::mem;
use std::sync::atomic::AtomicUsize;
use winapi::ctypes::c_void;
use winapi::shared::guiddef::REFIID;
use winapi::shared::minwindef::{BOOL, FALSE, TRUE, ULONG};
use winapi::shared::winerror::{E_INVALIDARG, S_OK};
use winapi::um::dwrite::{IDWriteFactory, IDWriteFontCollectionLoader};
use winapi::um::dwrite::{IDWriteFontCollectionLoaderVtbl, IDWriteFontFile, IDWriteFontFileEnumerator};
use winapi::um::dwrite::{IDWriteFontFileEnumeratorVtbl};
use winapi::um::unknwnbase::{IUnknown, IUnknownVtbl};
use winapi::um::winnt::HRESULT;

use com_helpers::{Com, UuidOfIUnknown};
use comptr::ComPtr;
use FontFile;

DEFINE_GUID! {
DWRITE_FONT_COLLECTION_LOADER_UUID,
0x12345678, 0x1234, 0x5678, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0
}
DEFINE_GUID! {
DWRITE_FONT_FILE_ENUMERATOR_UUID,
0x12345678, 0x1234, 0x5678, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0
}

static FONT_COLLECTION_LOADER_VTBL: IDWriteFontCollectionLoaderVtbl =
IDWriteFontCollectionLoaderVtbl {
parent: implement_iunknown!(static IDWriteFontCollectionLoader,
DWRITE_FONT_COLLECTION_LOADER_UUID,
CustomFontCollectionLoaderImpl),
CreateEnumeratorFromKey: CustomFontCollectionLoaderImpl_CreateEnumeratorFromKey,
};

pub struct CustomFontCollectionLoaderImpl {
refcount: AtomicUsize,
font_files: Vec<ComPtr<IDWriteFontFile>>,
}

impl Com<IDWriteFontCollectionLoader> for CustomFontCollectionLoaderImpl {
type Vtbl = IDWriteFontCollectionLoaderVtbl;
#[inline]
fn vtbl() -> &'static IDWriteFontCollectionLoaderVtbl {
&FONT_COLLECTION_LOADER_VTBL
}
}

impl Com<IUnknown> for CustomFontCollectionLoaderImpl {
type Vtbl = IUnknownVtbl;
#[inline]
fn vtbl() -> &'static IUnknownVtbl {
&FONT_COLLECTION_LOADER_VTBL.parent
}
}

impl CustomFontCollectionLoaderImpl {
pub fn new(font_files: &[FontFile]) -> ComPtr<IDWriteFontCollectionLoader> {
unsafe {
ComPtr::already_addrefed(CustomFontCollectionLoaderImpl {
refcount: AtomicUsize::new(1),
font_files: font_files.iter().map(|file| file.as_com_ptr()).collect(),
}.into_interface())
}
}
}

unsafe extern "system" fn CustomFontCollectionLoaderImpl_CreateEnumeratorFromKey(
this: *mut IDWriteFontCollectionLoader,
_: *mut IDWriteFactory,
_: *const c_void,
_: u32,
out_enumerator: *mut *mut IDWriteFontFileEnumerator)
-> HRESULT {
let this = CustomFontCollectionLoaderImpl::from_interface(this);
let enumerator = CustomFontFileEnumeratorImpl::new((*this).font_files.clone());
let enumerator = ComPtr::<IDWriteFontFileEnumerator>::from_ptr(enumerator.into_interface());
*out_enumerator = enumerator.as_ptr();
mem::forget(enumerator);
S_OK
}

struct CustomFontFileEnumeratorImpl {
refcount: AtomicUsize,
font_files: Vec<ComPtr<IDWriteFontFile>>,
index: isize,
}

impl Com<IDWriteFontFileEnumerator> for CustomFontFileEnumeratorImpl {
type Vtbl = IDWriteFontFileEnumeratorVtbl;
#[inline]
fn vtbl() -> &'static IDWriteFontFileEnumeratorVtbl {
&FONT_FILE_ENUMERATOR_VTBL
}
}

impl Com<IUnknown> for CustomFontFileEnumeratorImpl {
type Vtbl = IUnknownVtbl;
#[inline]
fn vtbl() -> &'static IUnknownVtbl {
&FONT_FILE_ENUMERATOR_VTBL.parent
}
}

static FONT_FILE_ENUMERATOR_VTBL: IDWriteFontFileEnumeratorVtbl = IDWriteFontFileEnumeratorVtbl {
parent: implement_iunknown!(static IDWriteFontFileEnumerator,
DWRITE_FONT_FILE_ENUMERATOR_UUID,
CustomFontFileEnumeratorImpl),
GetCurrentFontFile: CustomFontFileEnumeratorImpl_GetCurrentFontFile,
MoveNext: CustomFontFileEnumeratorImpl_MoveNext,
};

impl CustomFontFileEnumeratorImpl {
pub fn new(font_files: Vec<ComPtr<IDWriteFontFile>>) -> CustomFontFileEnumeratorImpl {
CustomFontFileEnumeratorImpl {
refcount: AtomicUsize::new(1),
font_files,
index: -1,
}
}
}

unsafe extern "system" fn CustomFontFileEnumeratorImpl_GetCurrentFontFile(
this: *mut IDWriteFontFileEnumerator,
out_font_file: *mut *mut IDWriteFontFile)
-> HRESULT {
let this = CustomFontFileEnumeratorImpl::from_interface(this);
if (*this).index < 0 || (*this).index >= (*this).font_files.len() as isize {
return E_INVALIDARG
}
let new_font_file = (*this).font_files[(*this).index as usize].clone();
*out_font_file = new_font_file.as_ptr();
mem::forget(new_font_file);
S_OK
}

unsafe extern "system" fn CustomFontFileEnumeratorImpl_MoveNext(
this: *mut IDWriteFontFileEnumerator,
has_current_file: *mut BOOL)
-> HRESULT {
let this = CustomFontFileEnumeratorImpl::from_interface(this);
let font_file_count = (*this).font_files.len() as isize;
if (*this).index < font_file_count {
(*this).index += 1
}
*has_current_file = if (*this).index >= 0 && (*this).index < font_file_count {
TRUE
} else {
FALSE
};
S_OK
}
Loading

0 comments on commit fc56316

Please sign in to comment.