summaryrefslogtreecommitdiffstats
path: root/third_party/rust/dwrote/src/font_file.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/dwrote/src/font_file.rs')
-rw-r--r--third_party/rust/dwrote/src/font_file.rs256
1 files changed, 256 insertions, 0 deletions
diff --git a/third_party/rust/dwrote/src/font_file.rs b/third_party/rust/dwrote/src/font_file.rs
new file mode 100644
index 0000000000..04ac7fb0a5
--- /dev/null
+++ b/third_party/rust/dwrote/src/font_file.rs
@@ -0,0 +1,256 @@
+/* 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/. */
+
+use std::cell::UnsafeCell;
+use std::ffi::OsString;
+use std::os::windows::ffi::{OsStrExt, OsStringExt};
+use std::path::Path;
+use std::path::PathBuf;
+use std::ptr;
+use std::slice;
+use std::sync::Arc;
+use winapi::ctypes::c_void;
+use winapi::um::dwrite::{IDWriteFontFace, IDWriteFontFile, IDWriteFontFileStream};
+use winapi::um::dwrite::{IDWriteFontFileLoader, IDWriteLocalFontFileLoader};
+use winapi::um::dwrite::{DWRITE_FONT_FACE_TYPE, DWRITE_FONT_FILE_TYPE_UNKNOWN};
+use winapi::um::dwrite::{DWRITE_FONT_FACE_TYPE_UNKNOWN, DWRITE_FONT_SIMULATIONS};
+use winapi::um::winnt::HRESULT;
+use wio::com::ComPtr;
+
+use super::DWriteFactory;
+use crate::font_face::FontFace;
+use crate::font_file_loader_impl::DataFontHelper;
+
+pub struct FontFile {
+ native: UnsafeCell<ComPtr<IDWriteFontFile>>,
+ stream: UnsafeCell<Option<ComPtr<IDWriteFontFileStream>>>,
+ data_key: usize,
+ face_type: DWRITE_FONT_FACE_TYPE,
+}
+
+impl FontFile {
+ pub fn new_from_path<P>(path: P) -> Option<FontFile>
+ where
+ P: AsRef<Path>,
+ {
+ unsafe {
+ let mut path: Vec<u16> = path.as_ref().as_os_str().encode_wide().collect();
+ path.push(0);
+
+ let mut font_file: *mut IDWriteFontFile = ptr::null_mut();
+ let hr = (*DWriteFactory()).CreateFontFileReference(
+ path.as_ptr(),
+ ptr::null(),
+ &mut font_file,
+ );
+ if hr != 0 || font_file.is_null() {
+ return None;
+ }
+
+ let mut ff = FontFile {
+ native: UnsafeCell::new(ComPtr::from_raw(font_file)),
+ stream: UnsafeCell::new(None),
+ data_key: 0,
+ face_type: DWRITE_FONT_FACE_TYPE_UNKNOWN,
+ };
+
+ if ff.analyze() == 0 {
+ None
+ } else {
+ Some(ff)
+ }
+ }
+ }
+
+ pub fn new_from_data(data: Arc<Vec<u8>>) -> Option<FontFile> {
+ let (font_file, font_file_stream, key) = DataFontHelper::register_font_data(data);
+
+ let mut ff = FontFile {
+ native: UnsafeCell::new(font_file),
+ stream: UnsafeCell::new(Some(font_file_stream)),
+ data_key: key,
+ face_type: DWRITE_FONT_FACE_TYPE_UNKNOWN,
+ };
+
+ if ff.analyze() == 0 {
+ None
+ } else {
+ Some(ff)
+ }
+ }
+
+ pub fn analyze_data(data: Arc<Vec<u8>>) -> u32 {
+ let (font_file, font_file_stream, key) = DataFontHelper::register_font_data(data);
+
+ let mut ff = FontFile {
+ native: UnsafeCell::new(font_file),
+ stream: UnsafeCell::new(Some(font_file_stream)),
+ data_key: key,
+ face_type: DWRITE_FONT_FACE_TYPE_UNKNOWN,
+ };
+
+ ff.analyze()
+ }
+
+ fn analyze(&mut self) -> u32 {
+ let mut face_type = DWRITE_FONT_FACE_TYPE_UNKNOWN;
+ let mut num_faces = 0;
+ unsafe {
+ let mut supported = 0;
+ let mut _file_type = DWRITE_FONT_FILE_TYPE_UNKNOWN;
+
+ let hr = (*self.native.get()).Analyze(
+ &mut supported,
+ &mut _file_type,
+ &mut face_type,
+ &mut num_faces,
+ );
+ if hr != 0 || supported == 0 {
+ return 0;
+ }
+ }
+ self.face_type = face_type;
+ num_faces as u32
+ }
+
+ pub fn take(native: ComPtr<IDWriteFontFile>) -> FontFile {
+ let mut ff = FontFile {
+ native: UnsafeCell::new(native),
+ stream: UnsafeCell::new(None),
+ data_key: 0,
+ face_type: DWRITE_FONT_FACE_TYPE_UNKNOWN,
+ };
+ ff.analyze();
+ ff
+ }
+
+ pub fn data_key(&self) -> Option<usize> {
+ if self.data_key != 0 {
+ Some(self.data_key)
+ } else {
+ None
+ }
+ }
+
+ pub(crate) unsafe fn as_com_ptr(&self) -> ComPtr<IDWriteFontFile> {
+ (*self.native.get()).clone()
+ }
+
+ // This is a helper to read the contents of this FontFile,
+ // without requiring callers to deal with loaders, keys,
+ // or streams.
+ pub fn get_font_file_bytes(&self) -> Vec<u8> {
+ unsafe {
+ let mut ref_key: *const c_void = ptr::null();
+ let mut ref_key_size: u32 = 0;
+ let hr = (*self.native.get()).GetReferenceKey(&mut ref_key, &mut ref_key_size);
+ assert!(hr == 0);
+
+ let mut loader: *mut IDWriteFontFileLoader = ptr::null_mut();
+ let hr = (*self.native.get()).GetLoader(&mut loader);
+ assert!(hr == 0);
+ let loader = ComPtr::from_raw(loader);
+
+ let mut stream: *mut IDWriteFontFileStream = ptr::null_mut();
+ let hr = loader.CreateStreamFromKey(ref_key, ref_key_size, &mut stream);
+ assert!(hr == 0);
+ let stream = ComPtr::from_raw(stream);
+
+ let mut file_size: u64 = 0;
+ let hr = stream.GetFileSize(&mut file_size);
+ assert!(hr == 0);
+
+ let mut fragment_start: *const c_void = ptr::null();
+ let mut fragment_context: *mut c_void = ptr::null_mut();
+ let hr =
+ stream.ReadFileFragment(&mut fragment_start, 0, file_size, &mut fragment_context);
+ assert!(hr == 0);
+
+ let in_ptr = slice::from_raw_parts(fragment_start as *const u8, file_size as usize);
+ let bytes = in_ptr.to_vec();
+
+ stream.ReleaseFileFragment(fragment_context);
+
+ bytes
+ }
+ }
+
+ // This is a helper to get the path of a font file,
+ // without requiring callers to deal with loaders.
+ pub fn get_font_file_path(&self) -> Option<PathBuf> {
+ unsafe {
+ let mut ref_key: *const c_void = ptr::null();
+ let mut ref_key_size: u32 = 0;
+ let hr = (*self.native.get()).GetReferenceKey(&mut ref_key, &mut ref_key_size);
+ assert!(hr == 0);
+
+ let mut loader: *mut IDWriteFontFileLoader = ptr::null_mut();
+ let hr = (*self.native.get()).GetLoader(&mut loader);
+ assert!(hr == 0);
+ let loader = ComPtr::from_raw(loader);
+
+ let local_loader: ComPtr<IDWriteLocalFontFileLoader> = match loader.cast() {
+ Ok(local_loader) => local_loader,
+ Err(_) => return None,
+ };
+
+ let mut file_path_len = 0;
+ let hr =
+ local_loader.GetFilePathLengthFromKey(ref_key, ref_key_size, &mut file_path_len);
+ assert_eq!(hr, 0);
+
+ let mut file_path_buf = vec![0; file_path_len as usize + 1];
+ let hr = local_loader.GetFilePathFromKey(
+ ref_key,
+ ref_key_size,
+ file_path_buf.as_mut_ptr(),
+ file_path_len + 1,
+ );
+ assert_eq!(hr, 0);
+
+ if let Some(&0) = file_path_buf.last() {
+ file_path_buf.pop();
+ }
+
+ Some(PathBuf::from(OsString::from_wide(&file_path_buf)))
+ }
+ }
+
+ pub fn create_face(
+ &self,
+ face_index: u32,
+ simulations: DWRITE_FONT_SIMULATIONS,
+ ) -> Result<FontFace, HRESULT> {
+ unsafe {
+ let mut face: *mut IDWriteFontFace = ptr::null_mut();
+ let ptr = self.as_com_ptr();
+ let hr = (*DWriteFactory()).CreateFontFace(
+ self.face_type,
+ 1,
+ &ptr.as_raw(),
+ face_index,
+ simulations,
+ &mut face,
+ );
+ if hr != 0 {
+ Err(hr)
+ } else {
+ Ok(FontFace::take(ComPtr::from_raw(face)))
+ }
+ }
+ }
+}
+
+impl Clone for FontFile {
+ fn clone(&self) -> FontFile {
+ unsafe {
+ FontFile {
+ native: UnsafeCell::new((*self.native.get()).clone()),
+ stream: UnsafeCell::new((*self.stream.get()).clone()),
+ data_key: self.data_key,
+ face_type: self.face_type,
+ }
+ }
+ }
+}