forked from mirrors/gecko-dev
237 lines
7.3 KiB
Rust
237 lines
7.3 KiB
Rust
#![allow(non_snake_case, non_upper_case_globals)]
|
|
|
|
use std::collections::HashMap;
|
|
use std::marker::Send;
|
|
use std::sync::atomic::AtomicUsize;
|
|
use std::sync::{atomic, Arc, Mutex};
|
|
use std::{mem, ptr};
|
|
use winapi::ctypes::c_void;
|
|
use winapi::shared::basetsd::{UINT32, UINT64};
|
|
use winapi::shared::guiddef::REFIID;
|
|
use winapi::shared::minwindef::ULONG;
|
|
use winapi::shared::winerror::{E_FAIL, E_INVALIDARG, E_NOTIMPL, S_OK};
|
|
use winapi::um::dwrite::IDWriteFontFile;
|
|
use winapi::um::dwrite::{IDWriteFontFileLoader, IDWriteFontFileLoaderVtbl};
|
|
use winapi::um::dwrite::{IDWriteFontFileStream, IDWriteFontFileStreamVtbl};
|
|
use winapi::um::unknwnbase::{IUnknown, IUnknownVtbl};
|
|
use winapi::um::winnt::HRESULT;
|
|
use wio::com::ComPtr;
|
|
|
|
use super::DWriteFactory;
|
|
use crate::com_helpers::*;
|
|
|
|
struct FontFileLoader;
|
|
|
|
const FontFileLoaderVtbl: &'static IDWriteFontFileLoaderVtbl = &IDWriteFontFileLoaderVtbl {
|
|
parent: implement_iunknown!(static IDWriteFontFileLoader, FontFileLoader),
|
|
CreateStreamFromKey: {
|
|
unsafe extern "system" fn CreateStreamFromKey(
|
|
_This: *mut IDWriteFontFileLoader,
|
|
fontFileReferenceKey: *const c_void,
|
|
fontFileReferenceKeySize: UINT32,
|
|
fontFileStream: *mut *mut IDWriteFontFileStream,
|
|
) -> HRESULT {
|
|
if fontFileReferenceKey.is_null() || fontFileStream.is_null() {
|
|
return E_INVALIDARG;
|
|
}
|
|
assert!(fontFileReferenceKeySize == mem::size_of::<usize>() as UINT32);
|
|
let key = *(fontFileReferenceKey as *const usize);
|
|
let stream = match FONT_FILE_STREAM_MAP.lock().unwrap().get(&key) {
|
|
None => {
|
|
*fontFileStream = ptr::null_mut();
|
|
return E_FAIL;
|
|
}
|
|
Some(&FontFileStreamPtr(file_stream)) => file_stream,
|
|
};
|
|
|
|
// This is an addref getter, so make sure to do that!
|
|
(*stream).AddRef();
|
|
|
|
*fontFileStream = stream;
|
|
S_OK
|
|
}
|
|
CreateStreamFromKey
|
|
},
|
|
};
|
|
|
|
impl Com<IDWriteFontFileLoader> for FontFileLoader {
|
|
type Vtbl = IDWriteFontFileLoaderVtbl;
|
|
fn vtbl() -> &'static IDWriteFontFileLoaderVtbl {
|
|
FontFileLoaderVtbl
|
|
}
|
|
}
|
|
|
|
impl Com<IUnknown> for FontFileLoader {
|
|
type Vtbl = IUnknownVtbl;
|
|
fn vtbl() -> &'static IUnknownVtbl {
|
|
&FontFileLoaderVtbl.parent
|
|
}
|
|
}
|
|
|
|
impl FontFileLoader {
|
|
pub fn new() -> FontFileLoader {
|
|
FontFileLoader
|
|
}
|
|
}
|
|
|
|
unsafe impl Send for FontFileLoader {}
|
|
unsafe impl Sync for FontFileLoader {}
|
|
|
|
struct FontFileStream {
|
|
refcount: atomic::AtomicUsize,
|
|
key: usize,
|
|
data: Arc<Vec<u8>>,
|
|
}
|
|
|
|
const FontFileStreamVtbl: &'static IDWriteFontFileStreamVtbl = &IDWriteFontFileStreamVtbl {
|
|
parent: implement_iunknown!(IDWriteFontFileStream, FontFileStream),
|
|
ReadFileFragment: {
|
|
unsafe extern "system" fn ReadFileFragment(
|
|
This: *mut IDWriteFontFileStream,
|
|
fragmentStart: *mut *const c_void,
|
|
fileOffset: UINT64,
|
|
fragmentSize: UINT64,
|
|
fragmentContext: *mut *mut c_void,
|
|
) -> HRESULT {
|
|
let this = FontFileStream::from_interface(This);
|
|
*fragmentContext = ptr::null_mut();
|
|
if (fileOffset + fragmentSize) as usize > this.data.len() {
|
|
return E_INVALIDARG;
|
|
}
|
|
let index = fileOffset as usize;
|
|
*fragmentStart = this.data[index..].as_ptr() as *const c_void;
|
|
S_OK
|
|
}
|
|
ReadFileFragment
|
|
},
|
|
ReleaseFileFragment: {
|
|
unsafe extern "system" fn ReleaseFileFragment(
|
|
_This: *mut IDWriteFontFileStream,
|
|
_fragmentContext: *mut c_void,
|
|
) {
|
|
}
|
|
ReleaseFileFragment
|
|
},
|
|
GetFileSize: {
|
|
unsafe extern "system" fn GetFileSize(
|
|
This: *mut IDWriteFontFileStream,
|
|
fileSize: *mut UINT64,
|
|
) -> HRESULT {
|
|
let this = FontFileStream::from_interface(This);
|
|
*fileSize = this.data.len() as UINT64;
|
|
S_OK
|
|
}
|
|
GetFileSize
|
|
},
|
|
GetLastWriteTime: {
|
|
unsafe extern "system" fn GetLastWriteTime(
|
|
_This: *mut IDWriteFontFileStream,
|
|
_lastWriteTime: *mut UINT64,
|
|
) -> HRESULT {
|
|
E_NOTIMPL
|
|
}
|
|
GetLastWriteTime
|
|
},
|
|
};
|
|
|
|
impl FontFileStream {
|
|
pub fn new(key: usize, data: Arc<Vec<u8>>) -> FontFileStream {
|
|
FontFileStream {
|
|
refcount: AtomicUsize::new(1),
|
|
key,
|
|
data,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Drop for FontFileStream {
|
|
fn drop(&mut self) {
|
|
DataFontHelper::unregister_font_data(self.key);
|
|
}
|
|
}
|
|
|
|
impl Com<IDWriteFontFileStream> for FontFileStream {
|
|
type Vtbl = IDWriteFontFileStreamVtbl;
|
|
fn vtbl() -> &'static IDWriteFontFileStreamVtbl {
|
|
FontFileStreamVtbl
|
|
}
|
|
}
|
|
|
|
impl Com<IUnknown> for FontFileStream {
|
|
type Vtbl = IUnknownVtbl;
|
|
fn vtbl() -> &'static IUnknownVtbl {
|
|
&FontFileStreamVtbl.parent
|
|
}
|
|
}
|
|
|
|
struct FontFileStreamPtr(*mut IDWriteFontFileStream);
|
|
|
|
unsafe impl Send for FontFileStreamPtr {}
|
|
|
|
static mut FONT_FILE_KEY: atomic::AtomicUsize = AtomicUsize::new(0);
|
|
|
|
#[derive(Clone)]
|
|
struct FontFileLoaderWrapper(ComPtr<IDWriteFontFileLoader>);
|
|
|
|
unsafe impl Send for FontFileLoaderWrapper {}
|
|
unsafe impl Sync for FontFileLoaderWrapper {}
|
|
|
|
lazy_static! {
|
|
static ref FONT_FILE_STREAM_MAP: Mutex<HashMap<usize, FontFileStreamPtr>> =
|
|
{ Mutex::new(HashMap::new()) };
|
|
static ref FONT_FILE_LOADER: Mutex<FontFileLoaderWrapper> = {
|
|
unsafe {
|
|
let ffl_native = FontFileLoader::new();
|
|
let ffl = ComPtr::<IDWriteFontFileLoader>::from_raw(ffl_native.into_interface());
|
|
let hr = (*DWriteFactory()).RegisterFontFileLoader(ffl.as_raw());
|
|
assert!(hr == 0);
|
|
Mutex::new(FontFileLoaderWrapper(ffl))
|
|
}
|
|
};
|
|
}
|
|
|
|
pub struct DataFontHelper;
|
|
|
|
impl DataFontHelper {
|
|
pub fn register_font_data(
|
|
font_data: Arc<Vec<u8>>,
|
|
) -> (
|
|
ComPtr<IDWriteFontFile>,
|
|
ComPtr<IDWriteFontFileStream>,
|
|
usize,
|
|
) {
|
|
unsafe {
|
|
let key = FONT_FILE_KEY.fetch_add(1, atomic::Ordering::Relaxed);
|
|
let font_file_stream_native = FontFileStream::new(key, font_data);
|
|
let font_file_stream: ComPtr<IDWriteFontFileStream> =
|
|
ComPtr::from_raw(font_file_stream_native.into_interface());
|
|
|
|
{
|
|
let mut map = FONT_FILE_STREAM_MAP.lock().unwrap();
|
|
map.insert(key, FontFileStreamPtr(font_file_stream.as_raw()));
|
|
}
|
|
|
|
let mut font_file: *mut IDWriteFontFile = ptr::null_mut();
|
|
{
|
|
let loader = FONT_FILE_LOADER.lock().unwrap();
|
|
let hr = (*DWriteFactory()).CreateCustomFontFileReference(
|
|
mem::transmute(&key),
|
|
mem::size_of::<usize>() as UINT32,
|
|
loader.0.as_raw(),
|
|
&mut font_file,
|
|
);
|
|
assert!(hr == S_OK);
|
|
}
|
|
let font_file = ComPtr::from_raw(font_file);
|
|
|
|
(font_file, font_file_stream, key)
|
|
}
|
|
}
|
|
|
|
fn unregister_font_data(key: usize) {
|
|
let mut map = FONT_FILE_STREAM_MAP.lock().unwrap();
|
|
if map.remove(&key).is_none() {
|
|
panic!("unregister_font_data: trying to unregister key that is no longer registered");
|
|
}
|
|
}
|
|
}
|