Skip to content

Expose many additional bindings #9

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Aug 1, 2018
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 <vladimir@pobox.com>"]

[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