diff --git a/Cargo.toml b/Cargo.toml index ecd4bd7..55d8838 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,10 +17,27 @@ serde_serialization = ["serde", "serde_derive"] [dependencies] libc = "0.2" lazy_static = "1" -winapi = { version = "0.3.6", features = ["dwrite", "dwrite_1", "dwrite_3", "winnt", "unknwnbase", "libloaderapi", "winnls"] } serde = { version = "1.0", optional = true } serde_derive = { version = "1.0", optional = true } -wio = "0.2" +windows-core = ">=0.59, <=0.62" +windows-numerics = "0.3.1" +windows-sys = { version = ">=0.59, <=0.62", features = [ + "Win32_Graphics_Gdi", + "Win32_System_Com", + "Win32_System_LibraryLoader", + "Win32_System_SystemServices", + "Win32_Globalization" +] } +windows = { version = ">=0.59, <=0.62", features = [ + "Win32_Graphics_DirectWrite", + "Win32_Graphics_Gdi", + "Win32_Graphics_Direct2D", + "Win32_Graphics_Direct2D_Common", + "Win32_System_Com", + "Win32_System_LibraryLoader", + "Win32_System_SystemServices", + "Win32_Globalization" +] } [package.metadata.docs.rs] targets = ["x86_64-pc-windows-msvc"] diff --git a/src/bitmap_render_target.rs b/src/bitmap_render_target.rs index d4753b8..fb069c0 100644 --- a/src/bitmap_render_target.rs +++ b/src/bitmap_render_target.rs @@ -2,43 +2,37 @@ * 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::mem::{size_of, zeroed}; +use std::mem::{ManuallyDrop, MaybeUninit, size_of}; use std::slice; -use winapi::ctypes::c_void; -use winapi::shared::windef::{HDC, RECT}; -use winapi::um::dcommon::DWRITE_MEASURING_MODE; -use winapi::um::dwrite::IDWriteBitmapRenderTarget; -use winapi::um::dwrite::{DWRITE_GLYPH_OFFSET, DWRITE_GLYPH_RUN}; -use winapi::um::wingdi::{GetCurrentObject, GetObjectW, BITMAP, OBJ_BITMAP, RGB}; -use wio::com::ComPtr; + +use windows::Win32::Foundation::{COLORREF, FALSE, RECT}; +use windows::Win32::Graphics::Gdi::{BITMAP, GetCurrentObject, GetObjectW, HDC, OBJ_BITMAP}; +use windows::Win32::Graphics::DirectWrite::{IDWriteBitmapRenderTarget, DWRITE_GLYPH_RUN, DWRITE_MEASURING_MODE, DWRITE_GLYPH_OFFSET}; use super::{FontFace, RenderingParams}; pub struct BitmapRenderTarget { - native: UnsafeCell>, + native: IDWriteBitmapRenderTarget, } impl BitmapRenderTarget { - pub fn take(native: ComPtr) -> BitmapRenderTarget { - BitmapRenderTarget { - native: UnsafeCell::new(native), - } + pub fn take(native: IDWriteBitmapRenderTarget) -> BitmapRenderTarget { + BitmapRenderTarget { native } } - pub unsafe fn as_ptr(&self) -> *mut IDWriteBitmapRenderTarget { - (*self.native.get()).as_raw() + pub fn as_ptr(&self) -> &IDWriteBitmapRenderTarget { + &self.native } // A dip is 1/96th of an inch, so this value is the number of pixels per inch divided by 96. pub fn set_pixels_per_dip(&self, ppd: f32) { unsafe { - (*self.native.get()).SetPixelsPerDip(ppd); + let _ = self.native.SetPixelsPerDip(ppd); } } pub fn get_memory_dc(&self) -> HDC { - unsafe { (*self.native.get()).GetMemoryDC() } + unsafe { self.native.GetMemoryDC() } } pub fn draw_glyph_run( @@ -61,29 +55,30 @@ impl BitmapRenderTarget { let r = (color.0 * 255.0) as u8; let g = (color.1 * 255.0) as u8; let b = (color.2 * 255.0) as u8; - - let mut glyph_run: DWRITE_GLYPH_RUN = zeroed(); - glyph_run.fontFace = font_face.as_ptr(); - glyph_run.fontEmSize = em_size; - glyph_run.glyphCount = glyph_indices.len() as u32; - glyph_run.glyphIndices = glyph_indices.as_ptr(); - glyph_run.glyphAdvances = glyph_advances.as_ptr(); - glyph_run.glyphOffsets = glyph_offsets.as_ptr(); - glyph_run.isSideways = 0; - glyph_run.bidiLevel = 0; - - let mut rect: RECT = zeroed(); - let hr = (*self.native.get()).DrawGlyphRun( + let color = COLORREF((r as u32) | ((g as u32) << 8) | ((b as u32) << 16)); + + let glyph_run = DWRITE_GLYPH_RUN { + fontFace: ManuallyDrop::new(Some(font_face.as_ptr().clone())), + fontEmSize: em_size, + glyphCount: glyph_indices.len() as u32, + glyphIndices: glyph_indices.as_ptr(), + glyphAdvances: glyph_advances.as_ptr(), + glyphOffsets: glyph_offsets.as_ptr(), + isSideways: FALSE, + bidiLevel: 0, + }; + + let mut rect = MaybeUninit::uninit(); + self.native.DrawGlyphRun( baseline_origin_x, baseline_origin_y, measuring_mode, &glyph_run, rendering_params.as_ptr(), - RGB(r, g, b), - &mut rect, - ); - assert!(hr == 0); - rect + color, + Some(rect.as_mut_ptr()), + ).unwrap(); + rect.assume_init() } } @@ -96,12 +91,13 @@ impl BitmapRenderTarget { // Now grossness to pull out the pixels unsafe { let memory_dc = self.get_memory_dc(); - let mut bitmap: BITMAP = zeroed(); + let mut bitmap = MaybeUninit::::uninit(); let ret = GetObjectW( - GetCurrentObject(memory_dc, OBJ_BITMAP), + GetCurrentObject(HDC(memory_dc.0), OBJ_BITMAP), size_of::() as i32, - &mut bitmap as *mut _ as *mut c_void, + Some(bitmap.as_mut_ptr() as *mut _), ); + let bitmap = bitmap.assume_init(); assert!(ret == size_of::() as i32); assert!(bitmap.bmBitsPixel == 32); diff --git a/src/com_helpers.rs b/src/com_helpers.rs deleted file mode 100644 index aa28b2d..0000000 --- a/src/com_helpers.rs +++ /dev/null @@ -1,127 +0,0 @@ -// This is only handy for implementing a single-interface-implementing IUnknown. - -macro_rules! implement_iunknown { - ($interface:ident, $typ:ident) => { - IUnknownVtbl { - QueryInterface: { - #[allow(non_snake_case)] - unsafe extern "system" fn QueryInterface( - unknown_this: *mut IUnknown, - riid: REFIID, - ppv_object: *mut *mut c_void, - ) -> HRESULT { - use $crate::winapi::Interface; - let this = if $crate::winapi::shared::guiddef::IsEqualGUID( - &*riid, - &$interface::uuidof(), - ) { - mem::transmute(unknown_this) - } else if $crate::winapi::shared::guiddef::IsEqualGUID( - &*riid, - &IUnknown::uuidof(), - ) { - mem::transmute(unknown_this) - } else { - return $crate::winapi::shared::winerror::E_NOINTERFACE; - }; - - (*unknown_this).AddRef(); - *ppv_object = this; - return S_OK; - } - QueryInterface - }, - AddRef: { - unsafe extern "system" fn AddRef(unknown_this: *mut IUnknown) -> ULONG { - let this = $typ::from_interface(unknown_this); - let count = this.refcount.fetch_add(1, atomic::Ordering::Relaxed) + 1; - count as ULONG - } - AddRef - }, - Release: { - unsafe extern "system" fn Release(unknown_this: *mut IUnknown) -> ULONG { - let this = $typ::from_interface(unknown_this); - let count = this.refcount.fetch_sub(1, atomic::Ordering::Release) - 1; - if count == 0 { - <$typ as Com<$interface>>::destroy(unknown_this as *mut $interface); - } - count as ULONG - } - Release - }, - } - }; - (static $interface:ident, $typ:ident) => { - IUnknownVtbl { - QueryInterface: { - #[allow(non_snake_case)] - unsafe extern "system" fn QueryInterface( - unknown_this: *mut IUnknown, - riid: REFIID, - ppvObject: *mut *mut $crate::winapi::ctypes::c_void, - ) -> HRESULT { - use $crate::winapi::Interface; - let this = if $crate::winapi::shared::guiddef::IsEqualGUID( - &*riid, - &$interface::uuidof(), - ) { - mem::transmute(unknown_this) - } else if $crate::winapi::shared::guiddef::IsEqualGUID( - &*riid, - &IUnknown::uuidof(), - ) { - mem::transmute(unknown_this) - } else { - return $crate::winapi::shared::winerror::E_NOINTERFACE; - }; - - (*unknown_this).AddRef(); - *ppvObject = this; - return S_OK; - } - QueryInterface - }, - AddRef: { - // FIXME(pcwalton): Uh? Maybe we should actually reference count? - #[allow(non_snake_case)] - unsafe extern "system" fn AddRef(_: *mut IUnknown) -> ULONG { - 1 - } - AddRef - }, - Release: { - #[allow(non_snake_case)] - unsafe extern "system" fn Release(_: *mut IUnknown) -> ULONG { - 1 - } - Release - }, - } - }; -} - -#[repr(C)] -pub struct ComRepr(*const Vtbl, Type); - -pub trait Com -where - Self: Sized, -{ - type Vtbl: 'static; - - fn vtbl() -> &'static Self::Vtbl; - - fn into_interface(self) -> *mut Interface { - let com = Box::new(ComRepr(Self::vtbl(), self)); - Box::into_raw(com) as *mut Interface - } - - unsafe fn from_interface<'a>(thing: *mut Interface) -> &'a mut Self { - &mut (*(thing as *mut ComRepr)).1 - } - - unsafe fn destroy(thing: *mut Interface) { - let _ = Box::from_raw(thing as *mut ComRepr); - } -} diff --git a/src/font.rs b/src/font.rs index 37b915d..1a342a9 100644 --- a/src/font.rs +++ b/src/font.rs @@ -2,57 +2,26 @@ * 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::mem; -use std::ptr; -use winapi::shared::minwindef::{FALSE, TRUE}; -use winapi::shared::winerror::S_OK; -use winapi::um::dwrite::IDWriteFont; -use winapi::um::dwrite::IDWriteFontFace; -use winapi::um::dwrite::IDWriteFontFamily; -use winapi::um::dwrite::IDWriteLocalizedStrings; -use winapi::um::dwrite::DWRITE_FONT_METRICS; -use winapi::um::dwrite::DWRITE_INFORMATIONAL_STRING_COPYRIGHT_NOTICE; -use winapi::um::dwrite::DWRITE_INFORMATIONAL_STRING_DESCRIPTION; -use winapi::um::dwrite::DWRITE_INFORMATIONAL_STRING_DESIGNER; -use winapi::um::dwrite::DWRITE_INFORMATIONAL_STRING_DESIGNER_URL; -use winapi::um::dwrite::DWRITE_INFORMATIONAL_STRING_DESIGN_SCRIPT_LANGUAGE_TAG; -use winapi::um::dwrite::DWRITE_INFORMATIONAL_STRING_FONT_VENDOR_URL; -use winapi::um::dwrite::DWRITE_INFORMATIONAL_STRING_FULL_NAME; -use winapi::um::dwrite::DWRITE_INFORMATIONAL_STRING_ID; -use winapi::um::dwrite::DWRITE_INFORMATIONAL_STRING_LICENSE_DESCRIPTION; -use winapi::um::dwrite::DWRITE_INFORMATIONAL_STRING_LICENSE_INFO_URL; -use winapi::um::dwrite::DWRITE_INFORMATIONAL_STRING_MANUFACTURER; -use winapi::um::dwrite::DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_CID_NAME; -use winapi::um::dwrite::DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_NAME; -use winapi::um::dwrite::DWRITE_INFORMATIONAL_STRING_PREFERRED_FAMILY_NAMES; -use winapi::um::dwrite::DWRITE_INFORMATIONAL_STRING_PREFERRED_SUBFAMILY_NAMES; -use winapi::um::dwrite::DWRITE_INFORMATIONAL_STRING_SAMPLE_TEXT; -use winapi::um::dwrite::DWRITE_INFORMATIONAL_STRING_SUPPORTED_SCRIPT_LANGUAGE_TAG; -use winapi::um::dwrite::DWRITE_INFORMATIONAL_STRING_TRADEMARK; -use winapi::um::dwrite::DWRITE_INFORMATIONAL_STRING_VERSION_STRINGS; -use winapi::um::dwrite::DWRITE_INFORMATIONAL_STRING_WIN32_FAMILY_NAMES; -use winapi::um::dwrite::DWRITE_INFORMATIONAL_STRING_WIN32_SUBFAMILY_NAMES; -use winapi::um::dwrite::DWRITE_INFORMATIONAL_STRING_WWS_FAMILY_NAME; -use winapi::um::dwrite_1::{IDWriteFont1, DWRITE_FONT_METRICS1}; -use wio::com::ComPtr; +use std::mem::MaybeUninit; +use windows::Win32::Foundation::{FALSE, TRUE}; +use windows::Win32::Graphics::DirectWrite::{IDWriteFont, IDWriteFont1}; +use windows_core::Interface; use super::*; use helpers::*; +#[derive(Clone)] pub struct Font { - native: UnsafeCell>, + native: IDWriteFont, } impl Font { - pub fn take(native: ComPtr) -> Font { - Font { - native: UnsafeCell::new(native), - } + pub fn take(native: IDWriteFont) -> Font { + Font { native } } - pub unsafe fn as_ptr(&self) -> *mut IDWriteFont { - (*self.native.get()).as_raw() + pub fn as_ptr(&self) -> &IDWriteFont { + &self.native } pub fn to_descriptor(&self) -> FontDescriptor { @@ -65,57 +34,49 @@ impl Font { } pub fn stretch(&self) -> FontStretch { - unsafe { mem::transmute::((*self.native.get()).GetStretch()) } + unsafe { self.native.GetStretch().into() } } pub fn style(&self) -> FontStyle { - unsafe { mem::transmute::((*self.native.get()).GetStyle()) } + unsafe { self.native.GetStyle().into() } } pub fn weight(&self) -> FontWeight { - unsafe { FontWeight::from_u32((*self.native.get()).GetWeight()) } + unsafe { self.native.GetWeight().into() } } pub fn is_monospace(&self) -> Option { unsafe { - let font1: Option> = (*self.native.get()).cast().ok(); + let font1 = self.native.cast::().ok(); font1.map(|font| font.IsMonospacedFont() == TRUE) } } pub fn simulations(&self) -> FontSimulations { - unsafe { mem::transmute::((*self.native.get()).GetSimulations()) } + unsafe { self.native.GetSimulations().into() } } pub fn family_name(&self) -> String { - unsafe { - let mut family: *mut IDWriteFontFamily = ptr::null_mut(); - let hr = (*self.native.get()).GetFontFamily(&mut family); - assert!(hr == 0); - - FontFamily::take(ComPtr::from_raw(family)).name() - } + let family = unsafe { self.native.GetFontFamily().unwrap() }; + let family = FontFamily::take(family); + family.family_name().unwrap() } pub fn face_name(&self) -> String { - unsafe { - let mut names: *mut IDWriteLocalizedStrings = ptr::null_mut(); - let hr = (*self.native.get()).GetFaceNames(&mut names); - assert!(hr == 0); - - get_locale_string(&mut ComPtr::from_raw(names)) - } + let faces = unsafe { self.native.GetFaceNames().unwrap() }; + get_locale_string(faces).unwrap() } pub fn informational_string(&self, id: InformationalStringId) -> Option { unsafe { - let mut names: *mut IDWriteLocalizedStrings = ptr::null_mut(); let mut exists = FALSE; - let id = id as DWRITE_INFORMATIONAL_STRING_ID; - let hr = (*self.native.get()).GetInformationalStrings(id, &mut names, &mut exists); - assert!(hr == S_OK); + let mut strings = None; + self + .native + .GetInformationalStrings(id.into(), &mut strings, &mut exists) + .ok()?; if exists == TRUE { - Some(get_locale_string(&mut ComPtr::from_raw(names))) + strings.and_then(|s| get_locale_string(s).ok()) } else { None } @@ -126,45 +87,54 @@ impl Font { // FIXME create_font_face should cache the FontFace and return it, // there's a 1:1 relationship unsafe { - let mut face: *mut IDWriteFontFace = ptr::null_mut(); - let hr = (*self.native.get()).CreateFontFace(&mut face); - assert!(hr == 0); - FontFace::take(ComPtr::from_raw(face)) + let face = self.native.CreateFontFace().unwrap(); + FontFace::take(face) } } pub fn metrics(&self) -> FontMetrics { - unsafe { - let font_1: Option> = (*self.native.get()).cast().ok(); - match font_1 { - None => { - let mut metrics = mem::zeroed(); - (*self.native.get()).GetMetrics(&mut metrics); - FontMetrics::Metrics0(metrics) - } - Some(font_1) => { - let mut metrics_1 = mem::zeroed(); - font_1.GetMetrics(&mut metrics_1); - FontMetrics::Metrics1(metrics_1) - } + let font1 = self.native.cast::().ok(); + match font1 { + None => unsafe { + let mut metrics = MaybeUninit::uninit(); + self.native.GetMetrics(metrics.as_mut_ptr()); + FontMetrics::Metrics0(metrics.assume_init()) + } + Some(font1) => unsafe { + let mut metrics1 = MaybeUninit::uninit(); + font1.GetMetrics(metrics1.as_mut_ptr()); + FontMetrics::Metrics1(metrics1.assume_init()) } } } } -impl Clone for Font { - fn clone(&self) -> Font { - unsafe { - Font { - native: UnsafeCell::new((*self.native.get()).clone()), +macro_rules! define_informational_string_id { + ( $($name:ident = $value:ident),* $(,)? ) => { + #[repr(u32)] + #[derive(Clone, Copy, Debug, PartialEq)] + pub enum InformationalStringId { + $( $name = ::windows::Win32::Graphics::DirectWrite::$value.0 as u32, )* + } + + impl From for windows::Win32::Graphics::DirectWrite::DWRITE_INFORMATIONAL_STRING_ID { + fn from(id: InformationalStringId) -> Self { + match id { + $( InformationalStringId::$name => windows::Win32::Graphics::DirectWrite::$value, )* + } } } - } + impl From for InformationalStringId { + fn from(id: windows::Win32::Graphics::DirectWrite::DWRITE_INFORMATIONAL_STRING_ID) -> Self { + match id { + $( windows::Win32::Graphics::DirectWrite::$value => InformationalStringId::$name, )* + _ => panic!("Unknown InformationalStringId value"), + } + } + } + }; } - -#[repr(u32)] -#[derive(Clone, Copy, Debug, PartialEq)] -pub enum InformationalStringId { +define_informational_string_id! { FullName = DWRITE_INFORMATIONAL_STRING_FULL_NAME, PostscriptName = DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_NAME, PostscriptCidName = DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_CID_NAME, @@ -187,32 +157,21 @@ pub enum InformationalStringId { Win32SubfamilyNames = DWRITE_INFORMATIONAL_STRING_WIN32_SUBFAMILY_NAMES, WwsFamilyName = DWRITE_INFORMATIONAL_STRING_WWS_FAMILY_NAME, } - /// A wrapper around the `DWRITE_FONT_METRICS` and `DWRITE_FONT_METRICS1` types. pub enum FontMetrics { /// Windows 7. - Metrics0(DWRITE_FONT_METRICS), + Metrics0(FontMetrics0), /// Windows 8 and up. - Metrics1(DWRITE_FONT_METRICS1), + Metrics1(FontMetrics1), } impl FontMetrics { /// Convert self to the Metrics0 arm (throwing away additional information) - pub fn metrics0(self) -> DWRITE_FONT_METRICS { + #[inline] + pub fn metrics0(self) -> FontMetrics0 { match self { FontMetrics::Metrics0(metrics) => metrics, - FontMetrics::Metrics1(metrics) => DWRITE_FONT_METRICS { - designUnitsPerEm: metrics.designUnitsPerEm, - ascent: metrics.ascent, - descent: metrics.descent, - lineGap: metrics.lineGap, - capHeight: metrics.capHeight, - xHeight: metrics.xHeight, - underlinePosition: metrics.underlinePosition, - underlineThickness: metrics.underlineThickness, - strikethroughPosition: metrics.strikethroughPosition, - strikethroughThickness: metrics.strikethroughThickness, - }, + FontMetrics::Metrics1(metrics) => metrics.Base, } } } diff --git a/src/font_collection.rs b/src/font_collection.rs index 2154b28..a2e021d 100644 --- a/src/font_collection.rs +++ b/src/font_collection.rs @@ -2,24 +2,19 @@ * 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::mem; -use std::ptr; -use std::sync::atomic::{AtomicUsize, Ordering}; -use winapi::shared::minwindef::{BOOL, FALSE, TRUE}; -use winapi::shared::winerror::S_OK; -use winapi::um::dwrite::IDWriteFontCollectionLoader; -use winapi::um::dwrite::{IDWriteFont, IDWriteFontCollection, IDWriteFontFamily}; -use winapi::um::winnt::HRESULT; -use wio::com::ComPtr; - -use super::{DWriteFactory, Font, FontDescriptor, FontFace, FontFamily}; -use crate::helpers::*; - -static NEXT_ID: AtomicUsize = AtomicUsize::new(0); +use std::mem::MaybeUninit; +use std::sync::atomic::{AtomicU32, AtomicUsize, Ordering}; +use windows::Win32::Foundation::FALSE; +use windows::Win32::Graphics::DirectWrite::{IDWriteFontCollection, IDWriteFontCollectionLoader}; +use windows_core::{BOOL, HRESULT, PCWSTR}; + +use super::helpers::ToWide; +use super::{Font, FontDescriptor, FontFace, FontFamily, DWriteFactory}; + +static NEXT_ID: AtomicU32 = AtomicU32::new(0); pub struct FontCollectionFamilyIterator { - collection: ComPtr, + collection: IDWriteFontCollection, curr: u32, count: u32, } @@ -32,30 +27,24 @@ impl Iterator for FontCollectionFamilyIterator { } unsafe { - let mut family: *mut IDWriteFontFamily = ptr::null_mut(); - let hr = self.collection.GetFontFamily(self.curr, &mut family); - assert!(hr == 0); + let family = self.collection.GetFontFamily(self.curr).ok()?; self.curr += 1; - Some(FontFamily::take(ComPtr::from_raw(family))) + Some(FontFamily::take(family)) } } } pub struct FontCollection { - native: UnsafeCell>, + native: IDWriteFontCollection, } impl FontCollection { pub fn get_system(update: bool) -> FontCollection { unsafe { - let mut native: *mut IDWriteFontCollection = ptr::null_mut(); - let hr = (*DWriteFactory()) - .GetSystemFontCollection(&mut native, if update { TRUE } else { FALSE }); - assert!(hr == 0); - - FontCollection { - native: UnsafeCell::new(ComPtr::from_raw(native)), - } + let factory = DWriteFactory(); + let mut fontcollection = MaybeUninit::uninit(); + factory.GetSystemFontCollection(fontcollection.as_mut_ptr(), update).unwrap(); + FontCollection::take(fontcollection.assume_init().unwrap()) } } @@ -63,50 +52,38 @@ impl FontCollection { FontCollection::get_system(false) } - pub fn take(native: ComPtr) -> FontCollection { - FontCollection { - native: UnsafeCell::new(native), - } + pub fn take(native: IDWriteFontCollection) -> FontCollection { + FontCollection { native } } - pub fn from_loader(collection_loader: ComPtr) -> FontCollection { + pub fn from_loader(collection_loader: &IDWriteFontCollectionLoader) -> FontCollection { unsafe { let factory = DWriteFactory(); - assert_eq!( - (*factory).RegisterFontCollectionLoader(collection_loader.clone().into_raw()), - S_OK - ); - let mut collection: *mut IDWriteFontCollection = ptr::null_mut(); + factory.RegisterFontCollectionLoader(collection_loader).unwrap(); let id = NEXT_ID.fetch_add(1, Ordering::SeqCst); - assert_eq!( - (*factory).CreateCustomFontCollection( - collection_loader.clone().into_raw(), - &id as *const usize as *const _, - mem::size_of::() as u32, - &mut collection - ), - S_OK - ); - FontCollection::take(ComPtr::from_raw(collection)) + let collection = factory.CreateCustomFontCollection( + collection_loader, + &id as *const _ as *const _, + std::mem::size_of::() as u32 + ).unwrap(); + FontCollection::take(collection) } } - pub unsafe fn as_ptr(&self) -> *mut IDWriteFontCollection { - (*self.native.get()).as_raw() + pub unsafe fn as_ptr(&self) -> &IDWriteFontCollection { + &self.native } pub fn families_iter(&self) -> FontCollectionFamilyIterator { - unsafe { - FontCollectionFamilyIterator { - collection: (*self.native.get()).clone(), - curr: 0, - count: (*self.native.get()).GetFontFamilyCount(), - } + FontCollectionFamilyIterator { + collection: self.native.clone(), + curr: 0, + count: self.get_font_family_count(), } } pub fn get_font_family_count(&self) -> u32 { - unsafe { (*self.native.get()).GetFontFamilyCount() } + unsafe { self.native.GetFontFamilyCount() } } #[deprecated(note = "Use `font_family` instead.")] @@ -116,13 +93,9 @@ impl FontCollection { /// Returns the [`FontFamily`] at the given index. pub fn font_family(&self, index: u32) -> Result { - let mut family: *mut IDWriteFontFamily = ptr::null_mut(); unsafe { - let hr = (*self.native.get()).GetFontFamily(index, &mut family); - if hr != S_OK { - return Err(hr); - } - Ok(FontFamily::take(ComPtr::from_raw(family))) + let family = self.native.GetFontFamily(index).map_err(|e| e.code())?; + Ok(FontFamily::take(family)) } } @@ -154,13 +127,9 @@ impl FontCollection { /// Get a [`Font`] from the given [`FontFace`]. pub fn font_from_face(&self, face: &FontFace) -> Result { - let mut font: *mut IDWriteFont = ptr::null_mut(); unsafe { - let hr = (*self.native.get()).GetFontFromFontFace(face.as_ptr(), &mut font); - if hr != S_OK { - return Err(hr); - } - Ok(Font::take(ComPtr::from_raw(font))) + let font = self.native.GetFontFromFontFace(face.as_ptr()).map_err(|e| e.code())?; + Ok(Font::take(font)) } } @@ -175,25 +144,15 @@ impl FontCollection { let mut index: u32 = 0; let mut exists: BOOL = FALSE; unsafe { - let hr = (*self.native.get()).FindFamilyName( + self.native.FindFamilyName(PCWSTR( family_name.to_wide_null().as_ptr(), - &mut index, - &mut exists, - ); - if hr != S_OK { - return Err(hr); - } + ), &mut index, &mut exists).map_err(|e| e.code())?; if exists == FALSE { return Ok(None); } - let mut family: *mut IDWriteFontFamily = ptr::null_mut(); - let hr = (*self.native.get()).GetFontFamily(index, &mut family); - if hr != S_OK { - return Err(hr); - } - - Ok(Some(FontFamily::take(ComPtr::from_raw(family)))) + let family = self.native.GetFontFamily(index).map_err(|e| e.code())?; + Ok(Some(FontFamily::take(family))) } } } diff --git a/src/font_collection_impl.rs b/src/font_collection_impl.rs index 56c85d3..82a0136 100644 --- a/src/font_collection_impl.rs +++ b/src/font_collection_impl.rs @@ -4,117 +4,75 @@ // 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; -use winapi::um::dwrite::IDWriteFontCollectionLoader; -use winapi::um::dwrite::IDWriteFontCollectionLoaderVtbl; -use winapi::um::dwrite::IDWriteFontFile; -use winapi::um::dwrite::IDWriteFontFileEnumerator; -use winapi::um::dwrite::IDWriteFontFileEnumeratorVtbl; -use winapi::um::unknwnbase::{IUnknown, IUnknownVtbl}; -use winapi::um::winnt::HRESULT; -use wio::com::ComPtr; +use windows::Win32::Graphics::DirectWrite::IDWriteFontFile; -use crate::com_helpers::Com; use crate::FontFile; -static FONT_COLLECTION_LOADER_VTBL: IDWriteFontCollectionLoaderVtbl = - IDWriteFontCollectionLoaderVtbl { - parent: implement_iunknown!(static IDWriteFontCollectionLoader, - CustomFontCollectionLoaderImpl), - CreateEnumeratorFromKey: CustomFontCollectionLoaderImpl_CreateEnumeratorFromKey, - }; - #[repr(C)] pub struct CustomFontCollectionLoaderImpl { // NB: This must be the first field. _refcount: AtomicUsize, - font_files: Vec>, -} - -impl Com for CustomFontCollectionLoaderImpl { - type Vtbl = IDWriteFontCollectionLoaderVtbl; - #[inline] - fn vtbl() -> &'static IDWriteFontCollectionLoaderVtbl { - &FONT_COLLECTION_LOADER_VTBL - } -} - -impl Com for CustomFontCollectionLoaderImpl { - type Vtbl = IUnknownVtbl; - #[inline] - fn vtbl() -> &'static IUnknownVtbl { - &FONT_COLLECTION_LOADER_VTBL.parent - } + font_files: Vec, } impl CustomFontCollectionLoaderImpl { - pub fn new(font_files: &[FontFile]) -> ComPtr { - unsafe { - ComPtr::from_raw( - CustomFontCollectionLoaderImpl { - _refcount: AtomicUsize::new(1), - font_files: font_files.iter().map(|file| file.as_com_ptr()).collect(), - } - .into_interface(), - ) + pub fn new(font_files: &[FontFile]) -> CustomFontCollectionLoaderImpl { + CustomFontCollectionLoaderImpl { + _refcount: AtomicUsize::new(1), + font_files: font_files.iter().map(|file| file.as_ptr().clone()).collect(), } } } -#[allow(non_snake_case)] -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::::from_raw(enumerator.into_interface()); - *out_enumerator = enumerator.as_raw(); - mem::forget(enumerator); - S_OK -} +// #[allow(non_snake_case)] +// 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 = enumerator.into_interface(); +// *out_enumerator = enumerator.as_raw(); +// mem::forget(enumerator); +// S_OK +// } #[repr(C)] struct CustomFontFileEnumeratorImpl { // NB(pcwalton): This must be the first field. _refcount: AtomicUsize, - font_files: Vec>, + font_files: Vec, index: isize, } -impl Com for CustomFontFileEnumeratorImpl { - type Vtbl = IDWriteFontFileEnumeratorVtbl; - #[inline] - fn vtbl() -> &'static IDWriteFontFileEnumeratorVtbl { - &FONT_FILE_ENUMERATOR_VTBL - } -} - -impl Com 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, CustomFontFileEnumeratorImpl), - GetCurrentFontFile: CustomFontFileEnumeratorImpl_GetCurrentFontFile, - MoveNext: CustomFontFileEnumeratorImpl_MoveNext, -}; +// impl Com for CustomFontFileEnumeratorImpl { +// type Vtbl = IDWriteFontFileEnumerator_Vtbl; +// #[inline] +// fn vtbl() -> &'static IDWriteFontFileEnumerator_Vtbl { +// &FONT_FILE_ENUMERATOR_VTBL +// } +// } + +// impl Com for CustomFontFileEnumeratorImpl { +// type Vtbl = IUnknownVtbl; +// #[inline] +// fn vtbl() -> &'static IUnknownVtbl { +// &FONT_FILE_ENUMERATOR_VTBL.parent +// } +// } + +// static FONT_FILE_ENUMERATOR_VTBL: IDWriteFontFileEnumerator_Vtbl = IDWriteFontFileEnumerator_Vtbl { +// parent: implement_iunknown!(static IDWriteFontFileEnumerator, CustomFontFileEnumeratorImpl), +// GetCurrentFontFile: CustomFontFileEnumeratorImpl_GetCurrentFontFile, +// MoveNext: CustomFontFileEnumeratorImpl_MoveNext, +// }; impl CustomFontFileEnumeratorImpl { - pub fn new(font_files: Vec>) -> CustomFontFileEnumeratorImpl { + pub fn new(font_files: Vec) -> CustomFontFileEnumeratorImpl { CustomFontFileEnumeratorImpl { _refcount: AtomicUsize::new(1), font_files, @@ -123,35 +81,35 @@ impl CustomFontFileEnumeratorImpl { } } -#[allow(non_snake_case)] -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_raw(); - mem::forget(new_font_file); - S_OK -} - -#[allow(non_snake_case)] -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 -} +// #[allow(non_snake_case)] +// 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_raw(); +// mem::forget(new_font_file); +// S_OK +// } + +// #[allow(non_snake_case)] +// 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 +// } diff --git a/src/font_face.rs b/src/font_face.rs index 0a330ea..7d35deb 100644 --- a/src/font_face.rs +++ b/src/font_face.rs @@ -2,72 +2,49 @@ * 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::mem::{self, zeroed}; +use std::ffi::c_void; +use std::mem::{MaybeUninit, zeroed}; use std::slice; use std::{error, fmt, ptr}; -use winapi::ctypes::c_void; -use winapi::shared::minwindef::{BOOL, FALSE, TRUE}; -use winapi::shared::winerror::S_OK; -use winapi::um::dcommon::DWRITE_MEASURING_MODE; -use winapi::um::dwrite::IDWriteRenderingParams; -use winapi::um::dwrite::DWRITE_FONT_FACE_TYPE_TRUETYPE; -use winapi::um::dwrite::{IDWriteFontFace, IDWriteFontFile}; -use winapi::um::dwrite::{DWRITE_FONT_FACE_TYPE_BITMAP, DWRITE_FONT_FACE_TYPE_CFF}; -use winapi::um::dwrite::{DWRITE_FONT_FACE_TYPE_RAW_CFF, DWRITE_FONT_FACE_TYPE_TYPE1}; -use winapi::um::dwrite::{DWRITE_FONT_FACE_TYPE_TRUETYPE_COLLECTION, DWRITE_FONT_FACE_TYPE_VECTOR}; -use winapi::um::dwrite::{DWRITE_FONT_SIMULATIONS, DWRITE_GLYPH_METRICS}; -use winapi::um::dwrite::{DWRITE_GLYPH_OFFSET, DWRITE_MATRIX, DWRITE_RENDERING_MODE}; -use winapi::um::dwrite::{DWRITE_RENDERING_MODE_DEFAULT, DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC}; -use winapi::um::dwrite_1::IDWriteFontFace1; -use winapi::um::dwrite_3::{ - IDWriteFontFace5, IDWriteFontResource, DWRITE_FONT_AXIS_ATTRIBUTES_VARIABLE, - DWRITE_FONT_AXIS_VALUE, -}; -use winapi::um::winnt::HRESULT; -use winapi::Interface; -use wio::com::ComPtr; - -use super::{DWriteFactory, DefaultDWriteRenderParams, FontFile, FontMetrics}; -use crate::com_helpers::Com; +use windows::Win32::Foundation::{FALSE, TRUE}; + +use windows::Win32::Graphics::Direct2D::Common::ID2D1SimplifiedGeometrySink; +use windows::Win32::Graphics::DirectWrite::{ + DWRITE_FONT_AXIS_ATTRIBUTES_NONE, DWRITE_FONT_AXIS_ATTRIBUTES_VARIABLE, DWRITE_FONT_AXIS_TAG, DWRITE_FONT_AXIS_VALUE, DWRITE_FONT_FACE_TYPE_BITMAP, DWRITE_FONT_FACE_TYPE_CFF, DWRITE_FONT_FACE_TYPE_RAW_CFF, DWRITE_FONT_FACE_TYPE_TRUETYPE, DWRITE_FONT_FACE_TYPE_TRUETYPE_COLLECTION, DWRITE_FONT_FACE_TYPE_TYPE1, DWRITE_FONT_FACE_TYPE_VECTOR, DWRITE_FONT_SIMULATIONS, DWRITE_GLYPH_METRICS, DWRITE_GLYPH_OFFSET, DWRITE_MATRIX, DWRITE_MEASURING_MODE, DWRITE_RENDERING_MODE, DWRITE_RENDERING_MODE_DEFAULT, IDWriteFontFace, IDWriteFontFace1, IDWriteFontFace5, IDWriteFontFile, IDWriteRenderingParams}; +use windows_core::{HRESULT, Interface}; +use super::{DWriteFactory, FontFile, FontMetrics, DefaultDWriteRenderParams, FontSimulations}; use crate::geometry_sink_impl::GeometrySinkImpl; use crate::outline_builder::OutlineBuilder; -use crate::FontSimulations; +#[derive(Clone)] pub struct FontFace { - native: UnsafeCell>, - face1: UnsafeCell>>, - face5: UnsafeCell>>, + native: IDWriteFontFace, + face1: Option, + face5: Option, } impl FontFace { - pub fn take(native: ComPtr) -> FontFace { - let cell = UnsafeCell::new(native); + pub fn take(native: IDWriteFontFace) -> FontFace { FontFace { - native: cell, - face1: UnsafeCell::new(None), - face5: UnsafeCell::new(None), + native, + face1: None, + face5: None, } } - pub unsafe fn as_ptr(&self) -> *mut IDWriteFontFace { - (*self.native.get()).as_raw() + pub unsafe fn as_ptr(&self) -> &IDWriteFontFace { + &self.native } - unsafe fn raw_files(&self) -> Result, HRESULT> { - let mut number_of_files: u32 = 0; - let hr = (*self.native.get()).GetFiles(&mut number_of_files, ptr::null_mut()); - if hr != S_OK { - return Err(hr); - } - - let mut file_ptrs: Vec<*mut IDWriteFontFile> = - vec![ptr::null_mut(); number_of_files as usize]; - let hr = (*self.native.get()).GetFiles(&mut number_of_files, file_ptrs.as_mut_ptr()); - if hr != S_OK { - return Err(hr); + unsafe fn raw_files(&self) -> Result>, HRESULT> { + unsafe { + let mut number_of_files: u32 = 0; + self.native.GetFiles(&mut number_of_files, None).map_err(|e| e.code())?; + let mut file_ptrs: Vec> = Vec::with_capacity(number_of_files as usize); + file_ptrs.set_len(number_of_files as usize); + self.native.GetFiles(&mut number_of_files, Some(file_ptrs.as_mut_ptr())).map_err(|e| e.code())?; + Ok(file_ptrs) } - Ok(file_ptrs) } #[deprecated(note = "Use `files` instead.")] @@ -79,9 +56,10 @@ impl FontFace { unsafe { self.raw_files().map(|file_ptrs| { file_ptrs - .iter() - .map(|p| FontFile::take(ComPtr::from_raw(*p))) - .collect() + .into_iter() + .flatten() + .map(|f| FontFile::take(f)) + .collect::>() }) } } @@ -91,43 +69,31 @@ impl FontFace { simulations: DWRITE_FONT_SIMULATIONS, ) -> FontFace { unsafe { - let file_ptrs = self.raw_files().unwrap(); - let face_type = (*self.native.get()).GetType(); - let face_index = (*self.native.get()).GetIndex(); - let mut face: *mut IDWriteFontFace = ptr::null_mut(); - let hr = (*DWriteFactory()).CreateFontFace( - face_type, - file_ptrs.len() as u32, - file_ptrs.as_ptr(), - face_index, - simulations, - &mut face, - ); - for p in file_ptrs { - let _ = ComPtr::::from_raw(p); - } - assert!(hr == 0); - FontFace::take(ComPtr::from_raw(face)) + let files = self.raw_files().unwrap(); + let face_type = self.native.GetType(); + let face_index = self.native.GetIndex(); + let face = DWriteFactory().CreateFontFace(face_type, &files, face_index, simulations).unwrap(); + FontFace::take(face) } } pub fn get_glyph_count(&self) -> u16 { - unsafe { (*self.native.get()).GetGlyphCount() } + unsafe { self.native.GetGlyphCount() } } pub fn metrics(&self) -> FontMetrics { unsafe { - let font_1 = self.get_face1(); + let font_1 = &self.face1; match font_1 { None => { - let mut metrics = mem::zeroed(); - (*self.native.get()).GetMetrics(&mut metrics); - FontMetrics::Metrics0(metrics) + let mut metrics = MaybeUninit::uninit(); + self.native.GetMetrics(metrics.as_mut_ptr()); + FontMetrics::Metrics0(metrics.assume_init()) } Some(font_1) => { - let mut metrics_1 = mem::zeroed(); - font_1.GetMetrics(&mut metrics_1); - FontMetrics::Metrics1(metrics_1) + let mut metrics_1 = MaybeUninit::uninit(); + font_1.GetMetrics(metrics_1.as_mut_ptr()); + FontMetrics::Metrics1(metrics_1.assume_init()) } } } @@ -139,16 +105,13 @@ impl FontFace { } pub fn glyph_indices(&self, code_points: &[u32]) -> Result, HRESULT> { - let mut glyph_indices: Vec = vec![0; code_points.len()]; unsafe { - let hr = (*self.native.get()).GetGlyphIndices( + let mut glyph_indices: Vec = vec![0; code_points.len()]; + self.native.GetGlyphIndices( code_points.as_ptr(), code_points.len() as u32, glyph_indices.as_mut_ptr(), - ); - if hr != S_OK { - return Err(hr); - } + ).map_err(|e| e.code())?; Ok(glyph_indices) } } @@ -170,15 +133,12 @@ impl FontFace { ) -> Result, HRESULT> { unsafe { let mut metrics: Vec = vec![zeroed(); glyph_indices.len()]; - let hr = (*self.native.get()).GetDesignGlyphMetrics( + self.native.GetDesignGlyphMetrics( glyph_indices.as_ptr(), glyph_indices.len() as u32, metrics.as_mut_ptr(), - is_sideways as BOOL, - ); - if hr != S_OK { - return Err(hr); - } + is_sideways, + ).map_err(|e| e.code())?; Ok(metrics) } } @@ -215,19 +175,16 @@ impl FontFace { ) -> Result, HRESULT> { unsafe { let mut metrics: Vec = vec![zeroed(); glyph_indices.len()]; - let hr = (*self.native.get()).GetGdiCompatibleGlyphMetrics( + self.native.GetGdiCompatibleGlyphMetrics( em_size, pixels_per_dip, - transform, - use_gdi_natural as BOOL, + Some(transform), + use_gdi_natural, glyph_indices.as_ptr(), glyph_indices.len() as u32, metrics.as_mut_ptr(), - is_sideways as BOOL, - ); - if hr != S_OK { - return Err(hr); - } + is_sideways, + ).map_err(|e| e.code())?; Ok(metrics) } } @@ -242,30 +199,23 @@ impl FontFace { /// NB: The bytes of the tag are reversed! You probably want to use the `u32::swap_bytes()` /// method on the tag value before calling this method. pub fn font_table(&self, opentype_table_tag: u32) -> Result>, HRESULT> { - let mut table_data_ptr: *const u8 = ptr::null_mut(); - let mut table_size: u32 = 0; - let mut table_context: *mut c_void = ptr::null_mut(); - let mut exists: BOOL = FALSE; unsafe { - let hr = (*self.native.get()).TryGetFontTable( + let mut table_data_ptr: *const u8 = ptr::null_mut(); + let mut table_size: u32 = 0; + let mut table_context: *mut c_void = ptr::null_mut(); + let mut exists = FALSE; + self.native.TryGetFontTable( opentype_table_tag, - &mut table_data_ptr as *mut *const _ as *mut *const c_void, + &mut table_data_ptr as *mut *const _ as *mut *mut c_void, &mut table_size, &mut table_context, &mut exists, - ); - if hr != S_OK { - return Err(hr); - } - + ).map_err(|e| e.code())?; if exists == FALSE { return Ok(None); } - let table_bytes = slice::from_raw_parts(table_data_ptr, table_size as usize).to_vec(); - - (*self.native.get()).ReleaseFontTable(table_context); - + self.native.ReleaseFontTable(table_context); Ok(Some(table_bytes)) } } @@ -275,23 +225,15 @@ impl FontFace { em_size: f32, pixels_per_dip: f32, measure_mode: DWRITE_MEASURING_MODE, - rendering_params: *mut IDWriteRenderingParams, + rendering_params: &IDWriteRenderingParams, ) -> DWRITE_RENDERING_MODE { unsafe { - let mut render_mode: DWRITE_RENDERING_MODE = DWRITE_RENDERING_MODE_DEFAULT; - let hr = (*self.native.get()).GetRecommendedRenderingMode( + self.native.GetRecommendedRenderingMode( em_size, pixels_per_dip, measure_mode, rendering_params, - &mut render_mode, - ); - - if hr != S_OK { - return DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC; - } - - render_mode + ).unwrap_or(DWRITE_RENDERING_MODE_DEFAULT) } } @@ -305,7 +247,7 @@ impl FontFace { em_size, pixels_per_dip, measure_mode, - DefaultDWriteRenderParams(), + DefaultDWriteRenderParams() ) } @@ -360,31 +302,25 @@ impl FontFace { glyph_offsets.as_ptr() } }; - let is_sideways = if is_sideways { TRUE } else { FALSE }; - let is_right_to_left = if is_right_to_left { TRUE } else { FALSE }; - let geometry_sink = GeometrySinkImpl::new(outline_builder); - let geometry_sink = geometry_sink.into_interface(); + let geometry_sink: ID2D1SimplifiedGeometrySink = GeometrySinkImpl::new(outline_builder).into(); unsafe { - let hr = (*self.native.get()).GetGlyphRunOutline( + self.native.GetGlyphRunOutline( em_size, glyph_indices.as_ptr(), - glyph_advances, - glyph_offsets, + Some(glyph_advances), + Some(glyph_offsets), glyph_indices.len() as u32, is_sideways, is_right_to_left, - geometry_sink, - ); - if hr != S_OK { - return Err(GlyphRunOutlineError::Win32Error(hr)); - } + &geometry_sink, + ).map_err(|e| GlyphRunOutlineError::Win32Error(e.code()))?; } Ok(()) } pub fn has_kerning_pairs(&self) -> bool { unsafe { - match self.get_face1() { + match &self.face1 { Some(face1) => face1.HasKerningPairs() == TRUE, None => false, } @@ -403,17 +339,14 @@ impl FontFace { second_glyph: u16, ) -> Result { unsafe { - match self.get_face1() { + match &self.face1 { Some(face1) => { let mut adjustments = [0; 2]; - let hr = face1.GetKerningPairAdjustments( + face1.GetKerningPairAdjustments( 2, [first_glyph, second_glyph].as_ptr(), adjustments.as_mut_ptr(), - ); - if hr != S_OK { - return Err(hr); - } + ).map_err(|e| e.code())?; Ok(adjustments[0]) } @@ -425,7 +358,7 @@ impl FontFace { #[inline] pub fn get_type(&self) -> FontFaceType { unsafe { - match (*self.native.get()).GetType() { + match self.native.GetType() { DWRITE_FONT_FACE_TYPE_CFF => FontFaceType::Cff, DWRITE_FONT_FACE_TYPE_RAW_CFF => FontFaceType::RawCff, DWRITE_FONT_FACE_TYPE_TRUETYPE => FontFaceType::TrueType, @@ -440,35 +373,15 @@ impl FontFace { #[inline] pub fn get_index(&self) -> u32 { - unsafe { (*self.native.get()).GetIndex() } - } - - #[inline] - unsafe fn get_face1(&self) -> Option> { - self.get_interface(&self.face1) - } - - #[inline] - unsafe fn get_face5(&self) -> Option> { - self.get_interface(&self.face5) - } - - #[inline] - unsafe fn get_interface( - &self, - interface: &UnsafeCell>>, - ) -> Option> { - if (*interface.get()).is_none() { - *interface.get() = (*self.native.get()).cast().ok() - } - (*interface.get()).clone() + unsafe { self.native.GetIndex() } } pub fn has_variations(&self) -> bool { unsafe { - match self.get_face5() { - Some(face5) => face5.HasVariations() == TRUE, - None => false, + if let Some(face5) = &self.face5 { + face5.HasVariations() == TRUE + } else { + false } } } @@ -477,8 +390,7 @@ impl FontFace { /// variation axes and their values. If the font does not have variations, /// return an empty `Vec`. pub fn variations(&self) -> Result, HRESULT> { - let face5 = unsafe { self.get_face5() }; - let Some(face5) = face5 else { + let Some(face5) = &self.face5 else { return Ok(vec![]); }; if unsafe { face5.HasVariations() != TRUE } { @@ -489,33 +401,25 @@ impl FontFace { return Ok(vec![]); } - let mut resource: *mut IDWriteFontResource = ptr::null_mut(); - let hr = unsafe { face5.GetFontResource(&mut resource) }; - if hr != S_OK || resource.is_null() { - return Err(hr); - } + let resource = unsafe { face5.GetFontResource().map_err(|e| e.code())? }; let mut axis_values = Vec::with_capacity(axis_count); axis_values.resize( axis_count, DWRITE_FONT_AXIS_VALUE { - axisTag: 0, + axisTag: DWRITE_FONT_AXIS_TAG(0), value: 0., }, ); - let hr = unsafe { face5.GetFontAxisValues(axis_values.as_mut_ptr(), axis_count as u32) }; - if hr != S_OK { - return Err(hr); - } + unsafe { face5.GetFontAxisValues(&mut axis_values).map_err(|e| e.code())? }; - let resource = unsafe { &*resource }; Ok(axis_values .iter() .enumerate() .filter_map(|(index, axis_value)| { let attributes = unsafe { resource.GetFontAxisAttributes(index as u32) }; - if attributes & DWRITE_FONT_AXIS_ATTRIBUTES_VARIABLE == 0 { + if attributes & DWRITE_FONT_AXIS_ATTRIBUTES_VARIABLE == DWRITE_FONT_AXIS_ATTRIBUTES_NONE { None } else { Some(*axis_value) @@ -530,46 +434,18 @@ impl FontFace { axis_values: &[DWRITE_FONT_AXIS_VALUE], ) -> Option { unsafe { - if let Some(face5) = self.get_face5() { - let mut resource: *mut IDWriteFontResource = ptr::null_mut(); - let hr = face5.GetFontResource(&mut resource); - if hr == S_OK && !resource.is_null() { - let resource = ComPtr::from_raw(resource); - let mut var_face: *mut IDWriteFontFace5 = ptr::null_mut(); - let hr = resource.CreateFontFace( - simulations, - axis_values.as_ptr(), - axis_values.len() as u32, - &mut var_face, - ); - if hr == S_OK && !var_face.is_null() { - let var_face = ComPtr::from_raw(var_face).cast().unwrap(); - return Some(FontFace::take(var_face)); - } - } + if let Some(face5) = &self.face5 { + let resource = face5.GetFontResource().ok()?; + let face = resource.CreateFontFace(simulations, axis_values).ok()?; + let face = face.cast::().unwrap(); + return Some(FontFace::take(face)); } None } } pub fn simulations(&self) -> FontSimulations { - unsafe { - std::mem::transmute::( - (*self.native.get()).GetSimulations(), - ) - } - } -} - -impl Clone for FontFace { - fn clone(&self) -> FontFace { - unsafe { - FontFace { - native: UnsafeCell::new((*self.native.get()).clone()), - face1: UnsafeCell::new(None), - face5: UnsafeCell::new(None), - } - } + unsafe { self.native.GetSimulations().into() } } } @@ -595,7 +471,7 @@ impl fmt::Display for GlyphRunOutlineError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::InvalidInput => write!(f, "Invalid input"), - Self::Win32Error(code) => write!(f, "{:#x}", code), + Self::Win32Error(code) => write!(f, "{:#x}", code.0), } } } diff --git a/src/font_fallback.rs b/src/font_fallback.rs index 1fa1338..0dc07e6 100644 --- a/src/font_fallback.rs +++ b/src/font_fallback.rs @@ -2,15 +2,17 @@ * 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::ptr::null_mut; -use winapi::um::dwrite_2::{IDWriteFactory2, IDWriteFontFallback}; -use wio::com::ComPtr; +use std::mem::MaybeUninit; + +use windows::Win32::Graphics::DirectWrite::{IDWriteFactory2, IDWriteFontFallback}; +use windows_core::{Interface, PCWSTR}; + +use crate::helpers::ToWide; use super::*; pub struct FontFallback { - native: UnsafeCell>, + native: IDWriteFontFallback, } pub struct FallbackResult { @@ -25,68 +27,56 @@ pub struct FallbackResult { impl FontFallback { pub fn get_system_fallback() -> Option { unsafe { - let factory = ComPtr::from_raw(DWriteFactory()); - let factory2: Option> = factory.cast().ok(); - std::mem::forget(factory); + let factory = DWriteFactory(); + let factory2 = factory.cast::().ok(); let factory2 = factory2?; - let mut native = null_mut(); - let hr = factory2.GetSystemFontFallback(&mut native); - assert_eq!(hr, 0); - Some(Self::take(ComPtr::from_raw(native))) + let native = factory2.GetSystemFontFallback().ok()?; + Some(FontFallback::take(native)) } } - pub fn take(native: ComPtr) -> FontFallback { - FontFallback { - native: UnsafeCell::new(native), - } + pub fn take(native: IDWriteFontFallback) -> FontFallback { + FontFallback { native } } // TODO: I'm following crate conventions for unsafe, but it's bullshit - pub unsafe fn as_ptr(&self) -> *mut IDWriteFontFallback { - (*self.native.get()).as_raw() + pub fn as_ptr(&self) -> &IDWriteFontFallback { + &self.native } // TODO: map_characters (main function) pub fn map_characters( &self, - text_analysis_source: &TextAnalysisSource, + text_analysis_source: TextAnalysisSource, text_position: u32, text_length: u32, base_font: &FontCollection, - base_family: Option<&str>, + base_family: &str, base_weight: FontWeight, base_style: FontStyle, base_stretch: FontStretch, ) -> FallbackResult { unsafe { - let mut font = null_mut(); let mut mapped_length = 0; + let mut mapped_font = MaybeUninit::uninit(); let mut scale = 0.0; - let hr = (*self.as_ptr()).MapCharacters( + self.native.MapCharacters( text_analysis_source.as_ptr(), text_position, text_length, base_font.as_ptr(), - base_family - .map(|s| s.to_wide_null().as_mut_ptr()) - .unwrap_or(null_mut()), - base_weight.t(), - base_style.t(), - base_stretch.t(), + PCWSTR(base_family.to_wide_null().as_ptr()), + base_weight.into(), + base_style.into(), + base_stretch.into(), &mut mapped_length, - &mut font, - &mut scale, - ); - assert_eq!(hr, 0); - let mapped_font = if font.is_null() { - None - } else { - Some(Font::take(ComPtr::from_raw(font))) - }; + mapped_font.as_mut_ptr(), + &mut scale + ).unwrap(); + let mapped_font = mapped_font.assume_init(); FallbackResult { mapped_length: mapped_length as usize, - mapped_font, + mapped_font: mapped_font.map(|f| Font::take(f)), scale, } } diff --git a/src/font_family.rs b/src/font_family.rs index 78dadaa..caec85f 100644 --- a/src/font_family.rs +++ b/src/font_family.rs @@ -2,28 +2,27 @@ * 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::ptr; -use winapi::um::dwrite::IDWriteLocalizedStrings; -use winapi::um::dwrite::{IDWriteFont, IDWriteFontCollection, IDWriteFontFamily}; -use wio::com::ComPtr; +use windows::Win32::Graphics::DirectWrite::IDWriteFontFamily; +use windows_core::HRESULT; +use super::helpers::get_locale_string; use super::*; -use helpers::*; +#[derive(Debug, Clone)] pub struct FontFamily { - native: UnsafeCell>, + native: IDWriteFontFamily, } impl FontFamily { - pub fn take(native: ComPtr) -> FontFamily { + pub fn take(native: IDWriteFontFamily) -> FontFamily { FontFamily { - native: UnsafeCell::new(native), + native, } } pub unsafe fn as_ptr(&self) -> *mut IDWriteFontFamily { - (*self.native.get()).as_raw() + // self.native + unimplemented!() } #[deprecated(note = "Use `family_name` instead.")] @@ -32,13 +31,9 @@ impl FontFamily { } pub fn family_name(&self) -> Result { - let mut family_names: *mut IDWriteLocalizedStrings = ptr::null_mut(); unsafe { - let hr = (*self.native.get()).GetFamilyNames(&mut family_names); - if hr != 0 { - return Err(hr); - } - Ok(get_locale_string(&mut ComPtr::from_raw(family_names))) + let family_names = self.native.GetFamilyNames().map_err(|e| e.code())?; + get_locale_string(family_names).map_err(|e| e.code()) } } @@ -58,18 +53,13 @@ impl FontFamily { stretch: FontStretch, style: FontStyle, ) -> Result { - let mut font: *mut IDWriteFont = ptr::null_mut(); unsafe { - let hr = (*self.native.get()).GetFirstMatchingFont( - weight.t(), - stretch.t(), - style.t(), - &mut font, - ); - if hr != 0 { - return Err(hr); - } - Ok(Font::take(ComPtr::from_raw(font))) + let font = self.native.GetFirstMatchingFont( + weight.into(), + stretch.into(), + style.into(), + ).map_err(|err| err.code())?; + Ok(Font::take(font)) } } @@ -79,18 +69,14 @@ impl FontFamily { } pub fn font_collection(&self) -> Result { - let mut collection: *mut IDWriteFontCollection = ptr::null_mut(); unsafe { - let hr = (*self.native.get()).GetFontCollection(&mut collection); - if hr != 0 { - return Err(hr); - } - Ok(FontCollection::take(ComPtr::from_raw(collection))) + let collection = self.native.GetFontCollection().map_err(|e| e.code())?; + Ok(FontCollection::take(collection)) } } pub fn get_font_count(&self) -> u32 { - unsafe { (*self.native.get()).GetFontCount() } + unsafe { self.native.GetFontCount() } } #[deprecated(note = "Use `font` instead.")] @@ -99,13 +85,9 @@ impl FontFamily { } pub fn font(&self, index: u32) -> Result { - let mut font: *mut IDWriteFont = ptr::null_mut(); unsafe { - let hr = (*self.native.get()).GetFont(index, &mut font); - if hr != 0 { - return Err(hr); - } - Ok(Font::take(ComPtr::from_raw(font))) + let font = self.native.GetFont(index).map_err(|e| e.code())?; + Ok(Font::take(font)) } } } diff --git a/src/font_file.rs b/src/font_file.rs index a3c420a..38a6962 100644 --- a/src/font_file.rs +++ b/src/font_file.rs @@ -2,30 +2,26 @@ * 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::mem::MaybeUninit; +use std::os::raw::c_void; 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::shared::winerror::S_OK; -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 windows::Win32::Foundation::FALSE; +use windows_core::{HRESULT, PCWSTR, Interface}; +use windows::Win32::Graphics::DirectWrite::{IDWriteFontFile, DWRITE_FONT_FACE_TYPE, DWRITE_FONT_FACE_TYPE_UNKNOWN, DWRITE_FONT_FILE_TYPE_UNKNOWN, DWRITE_FONT_SIMULATIONS, IDWriteLocalFontFileLoader}; + +use super::{FontFace, DWriteFactory}; use crate::font_file_loader_impl::DataFontHelper; +use crate::helpers::ToWide; +#[derive(Clone)] pub struct FontFile { - native: UnsafeCell>, - stream: UnsafeCell>>, + native: IDWriteFontFile, + // stream: Option, data_key: usize, face_type: DWRITE_FONT_FACE_TYPE, } @@ -36,22 +32,14 @@ impl FontFile { P: AsRef, { unsafe { - let mut path: Vec = 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 font_file = DWriteFactory().CreateFontFileReference( + PCWSTR(path.as_ref().as_os_str().to_wide_null().as_ptr()), + None, + ).ok()?; let mut ff = FontFile { - native: UnsafeCell::new(ComPtr::from_raw(font_file)), - stream: UnsafeCell::new(None), + native: font_file, + // stream: None, data_key: 0, face_type: DWRITE_FONT_FACE_TYPE_UNKNOWN, }; @@ -64,17 +52,12 @@ impl FontFile { } } - #[deprecated(since = "0.11.2", note = "please use `new_from_buffer` instead")] - pub fn new_from_data(data: Arc>) -> Option { - Self::new_from_buffer(data) - } - pub fn new_from_buffer(data: Arc + Sync + Send>) -> Option { - let (font_file, font_file_stream, key) = DataFontHelper::register_font_buffer(data); + let (font_file, _font_file_stream, key) = DataFontHelper::register_font_buffer(data); let mut ff = FontFile { - native: UnsafeCell::new(font_file), - stream: UnsafeCell::new(Some(font_file_stream)), + native: font_file, + // stream: Some(font_file_stream), data_key: key, face_type: DWRITE_FONT_FACE_TYPE_UNKNOWN, }; @@ -86,17 +69,12 @@ impl FontFile { } } - #[deprecated(since = "0.11.2", note = "please use `analyze_buffer` instead")] - pub fn analyze_data(data: Arc>) -> u32 { - Self::analyze_buffer(data) - } - pub fn analyze_buffer(buffer: Arc + Sync + Send>) -> u32 { - let (font_file, font_file_stream, key) = DataFontHelper::register_font_buffer(buffer); + let (font_file, _font_file_stream, key) = DataFontHelper::register_font_buffer(buffer); let mut ff = FontFile { - native: UnsafeCell::new(font_file), - stream: UnsafeCell::new(Some(font_file_stream)), + native: font_file, + // stream: Some(font_file_stream), data_key: key, face_type: DWRITE_FONT_FACE_TYPE_UNKNOWN, }; @@ -108,16 +86,16 @@ impl FontFile { let mut face_type = DWRITE_FONT_FACE_TYPE_UNKNOWN; let mut num_faces = 0; unsafe { - let mut supported = 0; + let mut supported = FALSE; let mut _file_type = DWRITE_FONT_FILE_TYPE_UNKNOWN; - let hr = (*self.native.get()).Analyze( - &mut supported, + let result = self.native.Analyze( + &mut supported as *mut _, &mut _file_type, - &mut face_type, + Some(&mut face_type), &mut num_faces, ); - if hr != 0 || supported == 0 { + if let Err(_) = result { return 0; } } @@ -125,10 +103,10 @@ impl FontFile { num_faces } - pub fn take(native: ComPtr) -> FontFile { + pub fn take(native: IDWriteFontFile) -> FontFile { let mut ff = FontFile { - native: UnsafeCell::new(native), - stream: UnsafeCell::new(None), + native, + // stream: None, data_key: 0, face_type: DWRITE_FONT_FACE_TYPE_UNKNOWN, }; @@ -144,8 +122,8 @@ impl FontFile { } } - pub(crate) unsafe fn as_com_ptr(&self) -> ComPtr { - (*self.native.get()).clone() + pub(crate) fn as_ptr(&self) -> &IDWriteFontFile { + &self.native } #[deprecated(note = "Use `font_file_bytes` instead.")] @@ -160,44 +138,20 @@ impl FontFile { 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); - if hr != S_OK { - return Err(hr); - } + self.native.GetReferenceKey(&mut ref_key as *mut _ as *mut *mut _, &mut ref_key_size).map_err(|e| e.code())?; + let loader = self.native.GetLoader().map_err(|e| e.code())?; + let stream = loader.CreateStreamFromKey(ref_key, ref_key_size).map_err(|e| e.code())?; - let mut loader: *mut IDWriteFontFileLoader = ptr::null_mut(); - let hr = (*self.native.get()).GetLoader(&mut loader); - if hr != S_OK { - return Err(hr); - } - let loader = ComPtr::from_raw(loader); + let file_size = stream.GetFileSize().map_err(|e| e.code())?; + + let mut fragment_start = MaybeUninit::uninit(); + let mut fragment_context = MaybeUninit::uninit(); + stream.ReadFileFragment(fragment_start.as_mut_ptr(), 0, file_size, fragment_context.as_mut_ptr()).map_err(|e| e.code())?; - let mut stream: *mut IDWriteFontFileStream = ptr::null_mut(); - let hr = loader.CreateStreamFromKey(ref_key, ref_key_size, &mut stream); - if hr != S_OK { - return Err(hr); - } - let stream = ComPtr::from_raw(stream); - - let mut file_size: u64 = 0; - let hr = stream.GetFileSize(&mut file_size); - if hr != S_OK { - return Err(hr); - } - - 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); - if hr != S_OK { - return Err(hr); - } - - let in_ptr = slice::from_raw_parts(fragment_start as *const u8, file_size as usize); + let in_ptr = slice::from_raw_parts(fragment_start.assume_init() as *const u8, file_size as usize); let bytes = in_ptr.to_vec(); - stream.ReleaseFileFragment(fragment_context); - + stream.ReleaseFileFragment(fragment_context.assume_init()); Ok(bytes) } } @@ -213,43 +167,14 @@ impl FontFile { 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); - if hr != S_OK { - return Err(hr); - } - - let mut loader: *mut IDWriteFontFileLoader = ptr::null_mut(); - let hr = (*self.native.get()).GetLoader(&mut loader); - if hr != S_OK { - return Err(hr); - } - let loader = ComPtr::from_raw(loader); - - let local_loader: ComPtr = loader.cast()?; - - let mut file_path_len = 0; - let hr = - local_loader.GetFilePathLengthFromKey(ref_key, ref_key_size, &mut file_path_len); - if hr != S_OK { - return Err(hr); - } - - 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, - ); - if hr != S_OK { - return Err(hr); - } - - if let Some(&0) = file_path_buf.last() { - file_path_buf.pop(); - } - - Ok(PathBuf::from(OsString::from_wide(&file_path_buf))) + self.native.GetReferenceKey(&mut ref_key as *mut _ as *mut *mut _, &mut ref_key_size).map_err(|e| e.code())?; + let loader = self.native.GetLoader().map_err(|e| e.code())?; + let local_loader = loader.cast::().map_err(|e| e.code())?; + let len = local_loader.GetFilePathLengthFromKey(ref_key, ref_key_size).map_err(|e| e.code())?; + let mut file_path = Vec::::with_capacity((len + 1) as usize); + file_path.set_len((len + 1) as usize); + local_loader.GetFilePathFromKey(ref_key, ref_key_size, &mut file_path).map_err(|e| e.code())?; + Ok(PathBuf::from(String::from_utf16(&file_path).ok().unwrap())) } } @@ -257,36 +182,12 @@ impl FontFile { &self, face_index: u32, simulations: DWRITE_FONT_SIMULATIONS, - ) -> Result { + ) -> windows::core::Result { 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, - } + let face = DWriteFactory() + .CreateFontFace(self.face_type, &[None], face_index, simulations) + .map_err(|e| e.code())?; + Ok(FontFace::take(face)) } } } diff --git a/src/font_file_loader_impl.rs b/src/font_file_loader_impl.rs index 8887830..e90c113 100644 --- a/src/font_file_loader_impl.rs +++ b/src/font_file_loader_impl.rs @@ -2,139 +2,61 @@ use std::collections::HashMap; use std::marker::Send; +use std::mem; 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::*; +use windows::Win32::Foundation::{E_FAIL, E_INVALIDARG, E_NOTIMPL}; +use windows::Win32::Graphics::DirectWrite::{ + DWriteCreateFactory, IDWriteFactory, IDWriteFontFile, IDWriteFontFileLoader, IDWriteFontFileLoader_Impl, + IDWriteFontFileStream, IDWriteFontFileStream_Impl, DWRITE_FACTORY_TYPE_SHARED, +}; +#[windows::core::implement(IDWriteFontFileLoader)] struct FontFileLoader; -const FontFileLoaderVtbl: &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::() 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 +impl IDWriteFontFileLoader_Impl for FontFileLoader_Impl { + fn CreateStreamFromKey( + &self, + fontfilereferencekey: *const core::ffi::c_void, + _fontfilereferencekeysize: u32, + ) -> windows_core::Result { + // if fontFileReferenceKey.is_null() || fontFileStream.is_null() { + // return E_INVALIDARG; + // } + // assert!(fontFileReferenceKeySize == mem::size_of::() 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 + if fontfilereferencekey.is_null() { + return Err(E_INVALIDARG.into()); } - CreateStreamFromKey - }, -}; - -impl Com for FontFileLoader { - type Vtbl = IDWriteFontFileLoaderVtbl; - fn vtbl() -> &'static IDWriteFontFileLoaderVtbl { - FontFileLoaderVtbl - } -} -impl Com for FontFileLoader { - type Vtbl = IUnknownVtbl; - fn vtbl() -> &'static IUnknownVtbl { - &FontFileLoaderVtbl.parent - } -} - -impl FontFileLoader { - pub fn new() -> FontFileLoader { - FontFileLoader + let key = unsafe { *(fontfilereferencekey as *const usize) }; + match FONT_FILE_STREAM_MAP.lock().unwrap().get(&key) { + None => Err(E_FAIL.into()), + Some(&FontFileStreamPtr(ref file_stream)) => Ok(file_stream.clone()), + } } } -unsafe impl Send for FontFileLoader {} -unsafe impl Sync for FontFileLoader {} - +#[windows::core::implement(IDWriteFontFileStream)] struct FontFileStream { refcount: atomic::AtomicUsize, key: usize, data: Arc + Sync + Send>, } -const FontFileStreamVtbl: &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(); - let data = (*this.data).as_ref(); - if (fileOffset + fragmentSize) as usize > data.len() { - return E_INVALIDARG; - } - let index = fileOffset as usize; - *fragmentStart = 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).as_ref().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 + Sync + Send>) -> FontFileStream { FontFileStream { @@ -151,28 +73,43 @@ impl Drop for FontFileStream { } } -impl Com for FontFileStream { - type Vtbl = IDWriteFontFileStreamVtbl; - fn vtbl() -> &'static IDWriteFontFileStreamVtbl { - FontFileStreamVtbl +impl IDWriteFontFileStream_Impl for FontFileStream_Impl { + fn ReadFileFragment(&self, fragment_start: *mut *mut core::ffi::c_void, file_offset:u64, fragment_size:u64, fragment_context: *mut *mut core::ffi::c_void) -> windows_core::Result<()> { + unsafe { + *fragment_context = std::ptr::null_mut(); + let data = self.data.as_ref(); + if (file_offset + fragment_size) as usize > data.as_ref().len() { + return Err(E_INVALIDARG.into()); + } + let index = file_offset as usize; + *fragment_start = data.as_ref()[index..].as_ptr() as *mut core::ffi::c_void; + Ok(()) + } + + } + + fn ReleaseFileFragment(&self, _fragmentcontext: *mut core::ffi::c_void) { + // noop } -} -impl Com for FontFileStream { - type Vtbl = IUnknownVtbl; - fn vtbl() -> &'static IUnknownVtbl { - &FontFileStreamVtbl.parent + fn GetFileSize(&self) -> windows_core::Result { + let slice: &[u8] = self.data.as_ref().as_ref(); + Ok(slice.len() as u64) + } + + fn GetLastWriteTime(&self) -> windows_core::Result { + Err(E_NOTIMPL.into()) } } -struct FontFileStreamPtr(*mut IDWriteFontFileStream); +struct FontFileStreamPtr(IDWriteFontFileStream); unsafe impl Send for FontFileStreamPtr {} static mut FONT_FILE_KEY: atomic::AtomicUsize = AtomicUsize::new(0); #[derive(Clone)] -struct FontFileLoaderWrapper(ComPtr); +struct FontFileLoaderWrapper(IDWriteFontFileLoader); unsafe impl Send for FontFileLoaderWrapper {} unsafe impl Sync for FontFileLoaderWrapper {} @@ -182,10 +119,10 @@ lazy_static! { Mutex::new(HashMap::new()); static ref FONT_FILE_LOADER: Mutex = { unsafe { - let ffl_native = FontFileLoader::new(); - let ffl = ComPtr::::from_raw(ffl_native.into_interface()); - let hr = (*DWriteFactory()).RegisterFontFileLoader(ffl.as_raw()); - assert!(hr == 0); + let factory: IDWriteFactory = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED).unwrap(); + let ffl = FontFileLoader {}; + let ffl: IDWriteFontFileLoader = ffl.into(); + factory.RegisterFontFileLoader(&ffl).unwrap(); Mutex::new(FontFileLoaderWrapper(ffl)) } }; @@ -196,34 +133,26 @@ pub(crate) struct DataFontHelper; impl DataFontHelper { pub(crate) fn register_font_buffer( font_data: Arc + Sync + Send>, - ) -> ( - ComPtr, - ComPtr, - usize, - ) { + ) -> (IDWriteFontFile, 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 = - ComPtr::from_raw(font_file_stream_native.into_interface()); + let font_file_stream = FontFileStream::new(key, font_data); + let font_file_stream: IDWriteFontFileStream = font_file_stream.into(); { let mut map = FONT_FILE_STREAM_MAP.lock().unwrap(); - map.insert(key, FontFileStreamPtr(font_file_stream.as_raw())); + map.insert(key, FontFileStreamPtr(font_file_stream.clone())); } - let mut font_file: *mut IDWriteFontFile = ptr::null_mut(); - { - let loader = FONT_FILE_LOADER.lock().unwrap(); - let hr = (*DWriteFactory()).CreateCustomFontFileReference( + let factory: IDWriteFactory = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED).unwrap(); + let loader = FONT_FILE_LOADER.lock().unwrap(); + let font_file = factory + .CreateCustomFontFileReference( mem::transmute(&key), - mem::size_of::() as UINT32, - loader.0.as_raw(), - &mut font_file, - ); - assert!(hr == S_OK); - } - let font_file = ComPtr::from_raw(font_file); + mem::size_of::() as u32, + &loader.0, + ) + .unwrap(); (font_file, font_file_stream, key) } diff --git a/src/gdi_interop.rs b/src/gdi_interop.rs index fcf2794..5ae0ec5 100644 --- a/src/gdi_interop.rs +++ b/src/gdi_interop.rs @@ -2,45 +2,33 @@ * 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::ptr; -use winapi::um::dwrite::IDWriteBitmapRenderTarget; -use winapi::um::dwrite::IDWriteGdiInterop; -use wio::com::ComPtr; - +use windows::Win32::Graphics::DirectWrite::IDWriteGdiInterop; use super::{BitmapRenderTarget, DWriteFactory}; pub struct GdiInterop { - native: UnsafeCell>, + native: IDWriteGdiInterop, } impl GdiInterop { pub fn create() -> GdiInterop { unsafe { - let mut native: *mut IDWriteGdiInterop = ptr::null_mut(); - let hr = (*DWriteFactory()).GetGdiInterop(&mut native); - assert!(hr == 0); - GdiInterop::take(ComPtr::from_raw(native)) + let native = DWriteFactory().GetGdiInterop().unwrap(); + GdiInterop::take(native) } } - pub fn take(native: ComPtr) -> GdiInterop { - GdiInterop { - native: UnsafeCell::new(native), - } + pub fn take(native: IDWriteGdiInterop) -> GdiInterop { + GdiInterop { native } } pub fn create_bitmap_render_target(&self, width: u32, height: u32) -> BitmapRenderTarget { unsafe { - let mut native: *mut IDWriteBitmapRenderTarget = ptr::null_mut(); - let hr = (*self.native.get()).CreateBitmapRenderTarget( - ptr::null_mut(), + let native = self.native.CreateBitmapRenderTarget( + None, width, height, - &mut native, - ); - assert!(hr == 0); - BitmapRenderTarget::take(ComPtr::from_raw(native)) + ).unwrap(); + BitmapRenderTarget::take(native) } } } diff --git a/src/geometry_sink_impl.rs b/src/geometry_sink_impl.rs index eae7e12..fabbbf3 100644 --- a/src/geometry_sink_impl.rs +++ b/src/geometry_sink_impl.rs @@ -1,127 +1,80 @@ #![allow(non_snake_case, non_upper_case_globals)] -use std::mem; -use std::slice; use std::sync::atomic::AtomicUsize; -use winapi::shared::guiddef::REFIID; -use winapi::shared::minwindef::{UINT, ULONG}; -use winapi::shared::winerror::S_OK; -use winapi::um::d2d1::{ID2D1SimplifiedGeometrySink, ID2D1SimplifiedGeometrySinkVtbl}; -use winapi::um::d2d1::{D2D1_BEZIER_SEGMENT, D2D1_FIGURE_BEGIN, D2D1_FIGURE_END}; -use winapi::um::d2d1::{D2D1_FIGURE_END_CLOSED, D2D1_FILL_MODE, D2D1_PATH_SEGMENT, D2D1_POINT_2F}; -use winapi::um::unknwnbase::{IUnknown, IUnknownVtbl}; -use winapi::um::winnt::HRESULT; +use std::cell::RefCell; + +use windows::Win32::Graphics::Direct2D::Common::{D2D1_BEZIER_SEGMENT, D2D1_FIGURE_BEGIN, D2D1_FIGURE_END, D2D1_FIGURE_END_CLOSED, D2D1_FILL_MODE, D2D1_PATH_SEGMENT, ID2D1SimplifiedGeometrySink, ID2D1SimplifiedGeometrySink_Impl}; +use windows_core::implement; +use windows_numerics::Vector2; -use crate::com_helpers::Com; use crate::outline_builder::OutlineBuilder; -static GEOMETRY_SINK_VTBL: ID2D1SimplifiedGeometrySinkVtbl = ID2D1SimplifiedGeometrySinkVtbl { - parent: implement_iunknown!(static ID2D1SimplifiedGeometrySink, GeometrySinkImpl), - BeginFigure: GeometrySinkImpl_BeginFigure, - EndFigure: GeometrySinkImpl_EndFigure, - AddLines: GeometrySinkImpl_AddLines, - AddBeziers: GeometrySinkImpl_AddBeziers, - Close: GeometrySinkImpl_Close, - SetFillMode: GeometrySinkImpl_SetFillMode, - SetSegmentFlags: GeometrySinkImpl_SetSegmentFlags, -}; +// static GEOMETRY_SINK_VTBL: ID2D1SimplifiedGeometrySink_Vtbl = ID2D1SimplifiedGeometrySink_Vtbl { +// parent: implement_iunknown!(static ID2D1SimplifiedGeometrySink, GeometrySinkImpl), +// BeginFigure: GeometrySinkImpl_BeginFigure, +// EndFigure: GeometrySinkImpl_EndFigure, +// AddLines: GeometrySinkImpl_AddLines, +// AddBeziers: GeometrySinkImpl_AddBeziers, +// Close: GeometrySinkImpl_Close, +// SetFillMode: GeometrySinkImpl_SetFillMode, +// SetSegmentFlags: GeometrySinkImpl_SetSegmentFlags, +// }; -#[repr(C)] +#[implement(ID2D1SimplifiedGeometrySink)] pub struct GeometrySinkImpl { // NB: This must be the first field. _refcount: AtomicUsize, - outline_builder: Box, + outline_builder: RefCell>, } -impl Com for GeometrySinkImpl { - type Vtbl = ID2D1SimplifiedGeometrySinkVtbl; - #[inline] - fn vtbl() -> &'static ID2D1SimplifiedGeometrySinkVtbl { - &GEOMETRY_SINK_VTBL +impl ID2D1SimplifiedGeometrySink_Impl for GeometrySinkImpl_Impl { + fn SetFillMode(&self, _: D2D1_FILL_MODE) { + // noop } -} -impl Com for GeometrySinkImpl { - type Vtbl = IUnknownVtbl; - #[inline] - fn vtbl() -> &'static IUnknownVtbl { - &GEOMETRY_SINK_VTBL.parent + fn SetSegmentFlags(&self, _: D2D1_PATH_SEGMENT) { + // noop } -} - -impl GeometrySinkImpl { - pub fn new(outline_builder: Box) -> GeometrySinkImpl { - GeometrySinkImpl { - _refcount: AtomicUsize::new(1), - outline_builder, + fn BeginFigure(&self, start_point: &Vector2, _figurebegin: D2D1_FIGURE_BEGIN) { + self.outline_builder.borrow_mut().move_to(start_point.X, start_point.Y); + } + fn AddLines(&self, points: *const Vector2, points_count: u32) { + let points = unsafe { std::slice::from_raw_parts(points, points_count as usize) }; + let mut builder = self.outline_builder.borrow_mut(); + for point in points { + builder.line_to(point.X, point.Y); } } -} - -unsafe extern "system" fn GeometrySinkImpl_BeginFigure( - this: *mut ID2D1SimplifiedGeometrySink, - start_point: D2D1_POINT_2F, - _: D2D1_FIGURE_BEGIN, -) { - let this = GeometrySinkImpl::from_interface(this); - this - .outline_builder - .move_to(start_point.x, start_point.y) -} - -unsafe extern "system" fn GeometrySinkImpl_EndFigure( - this: *mut ID2D1SimplifiedGeometrySink, - figure_end: D2D1_FIGURE_END, -) { - let this = GeometrySinkImpl::from_interface(this); - if figure_end == D2D1_FIGURE_END_CLOSED { - this.outline_builder.close() + fn AddBeziers(&self, beziers: *const D2D1_BEZIER_SEGMENT, beziers_count: u32) { + let beziers = unsafe { std::slice::from_raw_parts(beziers, beziers_count as usize) }; + let mut builder = self.outline_builder.borrow_mut(); + for bezier in beziers { + builder.curve_to( + bezier.point1.X, + bezier.point1.Y, + bezier.point2.X, + bezier.point2.Y, + bezier.point3.X, + bezier.point3.Y, + ); + } } -} - -unsafe extern "system" fn GeometrySinkImpl_AddLines( - this: *mut ID2D1SimplifiedGeometrySink, - points: *const D2D1_POINT_2F, - points_count: UINT, -) { - let this = GeometrySinkImpl::from_interface(this); - let points = slice::from_raw_parts(points, points_count as usize); - for point in points { - this.outline_builder.line_to(point.x, point.y) + fn EndFigure(&self, figure_end: D2D1_FIGURE_END) { + if figure_end == D2D1_FIGURE_END_CLOSED { + self.outline_builder.borrow_mut().close(); + } } -} -unsafe extern "system" fn GeometrySinkImpl_AddBeziers( - this: *mut ID2D1SimplifiedGeometrySink, - beziers: *const D2D1_BEZIER_SEGMENT, - beziers_count: UINT, -) { - let this = GeometrySinkImpl::from_interface(this); - let beziers = slice::from_raw_parts(beziers, beziers_count as usize); - for bezier in beziers { - this.outline_builder.curve_to( - bezier.point1.x, - bezier.point1.y, - bezier.point2.x, - bezier.point2.y, - bezier.point3.x, - bezier.point3.y, - ) + fn Close(&self) -> windows_core::Result<()> { + Ok(()) } } -unsafe extern "system" fn GeometrySinkImpl_Close(_: *mut ID2D1SimplifiedGeometrySink) -> HRESULT { - S_OK -} - -unsafe extern "system" fn GeometrySinkImpl_SetFillMode( - _: *mut ID2D1SimplifiedGeometrySink, - _: D2D1_FILL_MODE, -) { -} - -unsafe extern "system" fn GeometrySinkImpl_SetSegmentFlags( - _: *mut ID2D1SimplifiedGeometrySink, - _: D2D1_PATH_SEGMENT, -) { +impl GeometrySinkImpl { + pub fn new(outline_builder: Box) -> GeometrySinkImpl { + GeometrySinkImpl { + _refcount: AtomicUsize::new(1), + outline_builder: RefCell::new(outline_builder), + } + } } diff --git a/src/glyph_run_analysis.rs b/src/glyph_run_analysis.rs index 5224c60..d979f3f 100644 --- a/src/glyph_run_analysis.rs +++ b/src/glyph_run_analysis.rs @@ -2,22 +2,14 @@ * 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::mem; -use std::ptr; -use winapi::shared::windef::RECT; -use winapi::um::dcommon::DWRITE_MEASURING_MODE; -use winapi::um::dwrite::DWRITE_TEXTURE_CLEARTYPE_3x1; -use winapi::um::dwrite::IDWriteGlyphRunAnalysis; -use winapi::um::dwrite::{DWRITE_TEXTURE_ALIASED_1x1, DWRITE_GLYPH_RUN, DWRITE_TEXTURE_TYPE}; -use winapi::um::dwrite::{DWRITE_MATRIX, DWRITE_RENDERING_MODE}; -use winapi::um::winnt::HRESULT; -use wio::com::ComPtr; +use windows::Win32::Foundation::RECT; +use windows::Win32::Graphics::DirectWrite::{IDWriteGlyphRunAnalysis, DWRITE_GLYPH_RUN, DWRITE_MATRIX, DWRITE_RENDERING_MODE, DWRITE_MEASURING_MODE, DWRITE_TEXTURE_TYPE, DWRITE_TEXTURE_CLEARTYPE_3x1, DWRITE_TEXTURE_ALIASED_1x1}; +use windows_core::HRESULT; use super::DWriteFactory; pub struct GlyphRunAnalysis { - native: UnsafeCell>, + native: IDWriteGlyphRunAnalysis, } impl GlyphRunAnalysis { @@ -31,32 +23,21 @@ impl GlyphRunAnalysis { baseline_y: f32, ) -> Result { unsafe { - let mut native: *mut IDWriteGlyphRunAnalysis = ptr::null_mut(); - let hr = (*DWriteFactory()).CreateGlyphRunAnalysis( - glyph_run as *const DWRITE_GLYPH_RUN, + let native = DWriteFactory().CreateGlyphRunAnalysis( + glyph_run, pixels_per_dip, - transform - .as_ref() - .map(|x| x as *const _) - .unwrap_or(ptr::null()), + transform.map(|t| &t as *const _), rendering_mode, measuring_mode, baseline_x, baseline_y, - &mut native, - ); - if hr != 0 { - Err(hr) - } else { - Ok(GlyphRunAnalysis::take(ComPtr::from_raw(native))) - } + ) .map_err(|e| e.code())?; + Ok(GlyphRunAnalysis::take(native)) } } - pub fn take(native: ComPtr) -> GlyphRunAnalysis { - GlyphRunAnalysis { - native: UnsafeCell::new(native), - } + pub fn take(native: IDWriteGlyphRunAnalysis) -> GlyphRunAnalysis { + GlyphRunAnalysis { native } } pub fn get_alpha_texture_bounds( @@ -64,15 +45,7 @@ impl GlyphRunAnalysis { texture_type: DWRITE_TEXTURE_TYPE, ) -> Result { unsafe { - let mut rect: RECT = mem::zeroed(); - rect.left = 1234; - rect.top = 1234; - let hr = (*self.native.get()).GetAlphaTextureBounds(texture_type, &mut rect); - if hr != 0 { - Err(hr) - } else { - Ok(rect) - } + self.native.GetAlphaTextureBounds(texture_type).map_err(|e| e.code()) } } @@ -91,17 +64,12 @@ impl GlyphRunAnalysis { }; let mut out_bytes: Vec = vec![0; rect_bytes as usize]; - let hr = (*self.native.get()).CreateAlphaTexture( + self.native.CreateAlphaTexture( texture_type, &rect, - out_bytes.as_mut_ptr(), - out_bytes.len() as u32, - ); - if hr != 0 { - Err(hr) - } else { - Ok(out_bytes) - } + &mut out_bytes, + ).map_err(|e| e.code())?; + Ok(out_bytes) } } } diff --git a/src/helpers.rs b/src/helpers.rs index 45bf005..b5ec7e0 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -4,47 +4,44 @@ use std::ffi::OsStr; use std::os::windows::ffi::OsStrExt; -use winapi::ctypes::wchar_t; -use winapi::shared::minwindef::{BOOL, FALSE}; -use winapi::shared::winerror::S_OK; -use winapi::um::dwrite::IDWriteLocalizedStrings; -use winapi::um::winnls::GetUserDefaultLocaleName; -use wio::com::ComPtr; + +use windows::Win32::Foundation::{E_FAIL, FALSE}; +use windows::Win32::Globalization::GetUserDefaultLocaleName; +use windows::Win32::Graphics::DirectWrite::IDWriteLocalizedStrings; +use windows::Win32::System::SystemServices::LOCALE_NAME_MAX_LENGTH; +use windows_core::PCWSTR; lazy_static! { - static ref SYSTEM_LOCALE: Vec = { + static ref SYSTEM_LOCALE: Vec = { unsafe { - let mut locale: Vec = vec![0; 85]; - GetUserDefaultLocaleName(locale.as_mut_ptr(), locale.len() as i32 - 1); + let mut locale: Vec = vec![0; LOCALE_NAME_MAX_LENGTH as usize]; + let length = GetUserDefaultLocaleName(&mut locale); + locale.truncate(length as usize); locale } }; - static ref EN_US_LOCALE: Vec = OsStr::new("en-us").to_wide_null(); + static ref EN_US_LOCALE: Vec = OsStr::new("en-us").to_wide_null(); } -pub fn get_locale_string(strings: &mut ComPtr) -> String { +pub fn get_locale_string(strings: IDWriteLocalizedStrings) -> windows_core::Result { unsafe { let mut index: u32 = 0; - let mut exists: BOOL = FALSE; - let hr = strings.FindLocaleName((*SYSTEM_LOCALE).as_ptr(), &mut index, &mut exists); - if hr != S_OK || exists == FALSE { - let hr = strings.FindLocaleName((*EN_US_LOCALE).as_ptr(), &mut index, &mut exists); - if hr != S_OK || exists == FALSE { + let mut exists = FALSE; + let mut res = strings.FindLocaleName(PCWSTR(SYSTEM_LOCALE.as_ptr()), &mut index, &mut exists); + if res.is_err() || exists == FALSE { + res = strings.FindLocaleName(PCWSTR(EN_US_LOCALE.as_ptr()), &mut index, &mut exists); + if res.is_err() || exists == FALSE { // Ultimately fall back to first locale on list index = 0; } } + let length = strings.GetStringLength(index).map_err(|e| e.code())? as usize; - let mut length: u32 = 0; - let hr = strings.GetStringLength(index, &mut length); - assert!(hr == 0); - - let mut name: Vec = Vec::with_capacity(length as usize + 1); - let hr = strings.GetString(index, name.as_mut_ptr(), length + 1); - assert!(hr == 0); - name.set_len(length as usize); + let mut name = vec![0u16; length + 1]; + strings.GetString(index, &mut name).map_err(|e| e.code())?; + name.set_len(length); - String::from_utf16(&name).ok().unwrap() + String::from_utf16(&name).or(Err(E_FAIL.into())) } } diff --git a/src/lib.rs b/src/lib.rs index 07d73d1..30b7f12 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,63 +13,36 @@ extern crate serde_derive; #[macro_use] extern crate lazy_static; extern crate libc; -extern crate winapi; +extern crate windows; include!("types.rs"); -use std::ffi::CString; -use std::ptr; -use winapi::shared::guiddef::REFIID; -use winapi::shared::winerror::S_OK; -use winapi::um::dwrite::IDWriteFactory; -use winapi::um::dwrite::IDWriteRenderingParams; -use winapi::um::dwrite::DWRITE_FACTORY_TYPE; -use winapi::um::dwrite::DWRITE_FACTORY_TYPE_SHARED; -use winapi::um::unknwnbase::IUnknown; -use winapi::um::winnt::LPCSTR; -use winapi::Interface; +use windows::Win32::Graphics::DirectWrite::{DWriteCreateFactory, IDWriteFactory, DWRITE_FACTORY_TYPE_SHARED, IDWriteRenderingParams}; -pub use winapi::um::winnt::HRESULT; +pub use windows_core::HRESULT; mod helpers; -use helpers::ToWide; -use std::os::raw::c_void; #[cfg(test)] mod test; // We still use the DWrite structs for things like metrics; re-export them // here -pub use winapi::shared::windef::RECT; -pub use winapi::um::dcommon::DWRITE_MEASURING_MODE; -pub use winapi::um::dcommon::{ - DWRITE_MEASURING_MODE_GDI_CLASSIC, DWRITE_MEASURING_MODE_GDI_NATURAL, - DWRITE_MEASURING_MODE_NATURAL, -}; -pub use winapi::um::dwrite::DWRITE_FONT_METRICS as FontMetrics0; -pub use winapi::um::dwrite::DWRITE_FONT_SIMULATIONS; -pub use winapi::um::dwrite::DWRITE_GLYPH_OFFSET as GlyphOffset; -pub use winapi::um::dwrite::DWRITE_RENDERING_MODE; -pub use winapi::um::dwrite::DWRITE_TEXTURE_TYPE; -pub use winapi::um::dwrite::{DWRITE_TEXTURE_ALIASED_1x1, DWRITE_TEXTURE_CLEARTYPE_3x1}; -pub use winapi::um::dwrite::{ - DWRITE_FONT_SIMULATIONS_BOLD, DWRITE_FONT_SIMULATIONS_NONE, DWRITE_FONT_SIMULATIONS_OBLIQUE, -}; -pub use winapi::um::dwrite::{DWRITE_GLYPH_RUN, DWRITE_MATRIX}; -pub use winapi::um::dwrite::{ +pub use windows::Win32::Foundation::RECT; +pub use windows::Win32::Graphics::DirectWrite::{ + DWRITE_TEXTURE_ALIASED_1x1, DWRITE_TEXTURE_CLEARTYPE_3x1, DWRITE_FONT_AXIS_VALUE, + DWRITE_FONT_METRICS as FontMetrics0, DWRITE_FONT_METRICS1 as FontMetrics1, + DWRITE_FONT_SIMULATIONS, DWRITE_FONT_SIMULATIONS_BOLD, DWRITE_FONT_SIMULATIONS_NONE, + DWRITE_FONT_SIMULATIONS_OBLIQUE, DWRITE_GLYPH_OFFSET as GlyphOffset, DWRITE_GLYPH_RUN, + DWRITE_MATRIX, DWRITE_MEASURING_MODE, DWRITE_MEASURING_MODE_GDI_CLASSIC, + DWRITE_MEASURING_MODE_GDI_NATURAL, DWRITE_MEASURING_MODE_NATURAL, DWRITE_RENDERING_MODE, DWRITE_RENDERING_MODE_ALIASED, DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC, DWRITE_RENDERING_MODE_CLEARTYPE_GDI_NATURAL, DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL, DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC, DWRITE_RENDERING_MODE_DEFAULT, DWRITE_RENDERING_MODE_GDI_CLASSIC, DWRITE_RENDERING_MODE_GDI_NATURAL, DWRITE_RENDERING_MODE_NATURAL, DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC, - DWRITE_RENDERING_MODE_OUTLINE, + DWRITE_RENDERING_MODE_OUTLINE, DWRITE_TEXTURE_TYPE, }; -pub use winapi::um::dwrite_1::DWRITE_FONT_METRICS1 as FontMetrics1; -pub use winapi::um::dwrite_3::DWRITE_FONT_AXIS_VALUE; -use winapi::um::libloaderapi::{GetProcAddress, LoadLibraryW}; - -#[macro_use] -mod com_helpers; mod bitmap_render_target; pub use bitmap_render_target::BitmapRenderTarget; @@ -116,38 +89,12 @@ pub use text_analysis_source_impl::{ mod geometry_sink_impl; lazy_static! { - static ref DWRITE_FACTORY_RAW_PTR: usize = { - unsafe { - type DWriteCreateFactoryType = - extern "system" fn(DWRITE_FACTORY_TYPE, REFIID, *mut *mut IUnknown) -> HRESULT; - - let dwrite_dll = LoadLibraryW("dwrite.dll".to_wide_null().as_ptr()); - assert!(!dwrite_dll.is_null()); - let create_factory_name = CString::new("DWriteCreateFactory").unwrap(); - let dwrite_create_factory_ptr = - GetProcAddress(dwrite_dll, create_factory_name.as_ptr() as LPCSTR); - assert!(!dwrite_create_factory_ptr.is_null()); - - let dwrite_create_factory = mem::transmute::<*const c_void, DWriteCreateFactoryType>( - dwrite_create_factory_ptr as *const _, - ); - - let mut factory: *mut IDWriteFactory = ptr::null_mut(); - let hr = dwrite_create_factory( - DWRITE_FACTORY_TYPE_SHARED, - &IDWriteFactory::uuidof(), - &mut factory as *mut *mut IDWriteFactory as *mut *mut IUnknown, - ); - assert!(hr == S_OK); - factory as usize - } + static ref DWRITE_FACTORY: IDWriteFactory = unsafe { + DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED).unwrap() }; - static ref DEFAULT_DWRITE_RENDERING_PARAMS_RAW_PTR: usize = { + static ref DEFAULT_DWRITE_RENDERING_PARAMS_RAW_PTR: IDWriteRenderingParams = { unsafe { - let mut default_rendering_params: *mut IDWriteRenderingParams = ptr::null_mut(); - let hr = (*DWriteFactory()).CreateRenderingParams(&mut default_rendering_params); - assert!(hr == S_OK); - default_rendering_params as usize + DWriteFactory().CreateRenderingParams().unwrap() } }; } // end lazy static @@ -157,11 +104,13 @@ lazy_static! { // DWriteFactory().SomeOperation() as opposed to // (*DWriteFactory()).SomeOperation() #[allow(non_snake_case)] -fn DWriteFactory() -> *mut IDWriteFactory { - (*DWRITE_FACTORY_RAW_PTR) as *mut IDWriteFactory +#[inline] +fn DWriteFactory() -> &'static IDWriteFactory { + &DWRITE_FACTORY } #[allow(non_snake_case)] -fn DefaultDWriteRenderParams() -> *mut IDWriteRenderingParams { - (*DEFAULT_DWRITE_RENDERING_PARAMS_RAW_PTR) as *mut IDWriteRenderingParams +#[inline] +fn DefaultDWriteRenderParams() -> &'static IDWriteRenderingParams { + &DEFAULT_DWRITE_RENDERING_PARAMS_RAW_PTR } diff --git a/src/rendering_params.rs b/src/rendering_params.rs index 977c38a..1bba113 100644 --- a/src/rendering_params.rs +++ b/src/rendering_params.rs @@ -2,34 +2,27 @@ * 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::ptr; -use winapi::um::dwrite::IDWriteRenderingParams; -use wio::com::ComPtr; +use windows::Win32::Graphics::DirectWrite::IDWriteRenderingParams; use super::DWriteFactory; pub struct RenderingParams { - native: UnsafeCell>, + native: IDWriteRenderingParams, } impl RenderingParams { pub fn create_for_primary_monitor() -> RenderingParams { unsafe { - let mut native: *mut IDWriteRenderingParams = ptr::null_mut(); - let hr = (*DWriteFactory()).CreateRenderingParams(&mut native); - assert!(hr == 0); - RenderingParams::take(ComPtr::from_raw(native)) + let native = DWriteFactory().CreateRenderingParams().unwrap(); + RenderingParams::take(native) } } - pub fn take(native: ComPtr) -> RenderingParams { - RenderingParams { - native: UnsafeCell::new(native), - } + pub fn take(native: IDWriteRenderingParams) -> RenderingParams { + RenderingParams { native } } - pub unsafe fn as_ptr(&self) -> *mut IDWriteRenderingParams { - (*self.native.get()).as_raw() + pub unsafe fn as_ptr(&self) -> &IDWriteRenderingParams { + &self.native } } diff --git a/src/test.rs b/src/test.rs index 8810f54..07ba3d4 100644 --- a/src/test.rs +++ b/src/test.rs @@ -10,9 +10,7 @@ fn test_system_family_iter() { let system_fc = FontCollection::system(); let count = system_fc.families_iter().count(); assert!(count > 0); - assert!(system_fc - .families_iter() - .any(|f| f.name() == "Arial")); + assert!(system_fc.families_iter().any(|f| f.name() == "Arial")); } #[test] @@ -90,11 +88,6 @@ fn test_create_font_file_from_bytes() { let bytes = files[0].get_font_file_bytes(); assert!(!bytes.is_empty()); - // now go back - #[allow(deprecated)] - let new_font = FontFile::new_from_data(Arc::new(bytes.clone())); - assert!(new_font.is_some()); - let new_font = FontFile::new_from_buffer(Arc::new(bytes)); assert!(new_font.is_some()); @@ -121,7 +114,7 @@ fn test_glyph_image() { let design_units_per_em = match face.metrics() { FontMetrics::Metrics0(ref metrics) => metrics.designUnitsPerEm, - FontMetrics::Metrics1(ref metrics) => metrics.designUnitsPerEm, + FontMetrics::Metrics1(ref metrics) => metrics.Base.designUnitsPerEm, }; let design_units_per_pixel = design_units_per_em as f32 / 16.; @@ -153,7 +146,7 @@ fn test_glyph_image() { rt.draw_glyph_run( x, y, - DWRITE_MEASURING_MODE_NATURAL, + windows::Win32::Graphics::DirectWrite::DWRITE_MEASURING_MODE_GDI_NATURAL, &face, em_size, &[a_index], diff --git a/src/text_analysis_source.rs b/src/text_analysis_source.rs index 7ef7688..dffae07 100644 --- a/src/text_analysis_source.rs +++ b/src/text_analysis_source.rs @@ -4,16 +4,15 @@ use std::borrow::Cow; use std::marker::PhantomData; -use winapi::ctypes::wchar_t; -use winapi::um::dwrite::IDWriteTextAnalysisSource; -use wio::com::ComPtr; + +use libc::wchar_t; +use windows::Win32::Graphics::DirectWrite::IDWriteTextAnalysisSource; use super::*; -use crate::com_helpers::Com; pub struct TextAnalysisSource<'a> { - native: ComPtr, - phantom: PhantomData>, + native: IDWriteTextAnalysisSource, + _marker: PhantomData<&'a ()>, } impl<'a> TextAnalysisSource<'a> { @@ -24,16 +23,15 @@ impl<'a> TextAnalysisSource<'a> { /// `from_text_and_number_subst` if you need number substitution. pub fn from_text( inner: Box, - text: Cow<'a, [wchar_t]>, + text: Cow<'a, [wchar_t]> ) -> TextAnalysisSource<'a> { - let native = unsafe { - ComPtr::from_raw( - CustomTextAnalysisSourceImpl::from_text_native(inner, text).into_interface(), - ) - }; + let native = CustomTextAnalysisSourceImpl::from_text( + inner, + text + ).into(); TextAnalysisSource { native, - phantom: PhantomData, + _marker: PhantomData, } } @@ -47,23 +45,18 @@ impl<'a> TextAnalysisSource<'a> { text: Cow<'a, [wchar_t]>, number_subst: NumberSubstitution, ) -> TextAnalysisSource<'a> { - let native = unsafe { - ComPtr::from_raw( - CustomTextAnalysisSourceImpl::from_text_and_number_subst_native( - inner, - text, - number_subst, - ) - .into_interface(), - ) - }; + let native = CustomTextAnalysisSourceImpl::from_text_and_number_subst( + inner, + text, + number_subst + ).into(); TextAnalysisSource { native, - phantom: PhantomData, + _marker: PhantomData, } } - pub fn as_ptr(&self) -> *mut IDWriteTextAnalysisSource { - self.native.as_raw() + pub fn as_ptr(&self) -> &IDWriteTextAnalysisSource { + &self.native } } diff --git a/src/text_analysis_source_impl.rs b/src/text_analysis_source_impl.rs index c022d17..addbf62 100644 --- a/src/text_analysis_source_impl.rs +++ b/src/text_analysis_source_impl.rs @@ -1,93 +1,42 @@ -/* 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/. */ +// /* 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 custom implementation of the "text analysis source" interface so that -//! we can convey data to the `FontFallback::map_characters` method. +// //! A custom implementation of the "text analysis source" interface so that +// //! we can convey data to the `FontFallback::map_characters` method. #![allow(non_snake_case)] +use std::os::windows::ffi::OsStrExt; use std::borrow::Cow; use std::ffi::OsStr; -use std::mem; -use std::os::windows::ffi::OsStrExt; -use std::ptr::{self, null}; -use std::sync::atomic::AtomicUsize; -use winapi::ctypes::wchar_t; -use winapi::shared::basetsd::UINT32; -use winapi::shared::guiddef::REFIID; -use winapi::shared::minwindef::{FALSE, TRUE, ULONG}; -use winapi::shared::ntdef::LOCALE_NAME_MAX_LENGTH; -use winapi::shared::winerror::{E_INVALIDARG, S_OK}; -use winapi::um::dwrite::IDWriteNumberSubstitution; -use winapi::um::dwrite::IDWriteTextAnalysisSource; -use winapi::um::dwrite::IDWriteTextAnalysisSourceVtbl; -use winapi::um::dwrite::DWRITE_NUMBER_SUBSTITUTION_METHOD; -use winapi::um::dwrite::DWRITE_READING_DIRECTION; -use winapi::um::unknwnbase::{IUnknown, IUnknownVtbl}; -use winapi::um::winnt::HRESULT; -use wio::com::ComPtr; - -use super::DWriteFactory; -use crate::com_helpers::Com; -use crate::helpers::ToWide; -/// The Rust side of a custom text analysis source implementation. -pub trait TextAnalysisSourceMethods { - /// Determine the locale for a range of text. - /// - /// Return locale and length of text (in utf-16 code units) for which the - /// locale is valid. - fn get_locale_name(&self, text_position: u32) -> (Cow<'_, str>, u32); +use libc::wchar_t; +use windows::Win32::Foundation::E_INVALIDARG; +use windows::Win32::Graphics::DirectWrite::{DWRITE_NUMBER_SUBSTITUTION_METHOD, DWRITE_READING_DIRECTION, IDWriteNumberSubstitution, IDWriteTextAnalysisSource, IDWriteTextAnalysisSource_Impl}; +use windows_core::{PCWSTR, implement}; - /// Get the text direction for the paragraph. - fn get_paragraph_reading_direction(&self) -> DWRITE_READING_DIRECTION; -} +use super::helpers::ToWide; +use super::*; -#[repr(C)] +#[implement(IDWriteTextAnalysisSource)] pub struct CustomTextAnalysisSourceImpl<'a> { - // NB: This must be the first field. - _refcount: AtomicUsize, inner: Box, text: Cow<'a, [wchar_t]>, number_subst: Option, - locale_buf: [wchar_t; LOCALE_NAME_MAX_LENGTH], } -/// A wrapped version of an `IDWriteNumberSubstitution` object. -pub struct NumberSubstitution { - native: ComPtr, -} - -// TODO: implement Clone, for convenience and efficiency? - -static TEXT_ANALYSIS_SOURCE_VTBL: IDWriteTextAnalysisSourceVtbl = IDWriteTextAnalysisSourceVtbl { - parent: implement_iunknown!(static IDWriteTextAnalysisSource, CustomTextAnalysisSourceImpl), - GetLocaleName: CustomTextAnalysisSourceImpl_GetLocaleName, - GetNumberSubstitution: CustomTextAnalysisSourceImpl_GetNumberSubstitution, - GetParagraphReadingDirection: CustomTextAnalysisSourceImpl_GetParagraphReadingDirection, - GetTextAtPosition: CustomTextAnalysisSourceImpl_GetTextAtPosition, - GetTextBeforePosition: CustomTextAnalysisSourceImpl_GetTextBeforePosition, -}; - impl<'a> CustomTextAnalysisSourceImpl<'a> { /// Create a new custom TextAnalysisSource for the given text and a trait /// implementation. /// /// Note: this method has no NumberSubsitution specified. See - /// `from_text_and_number_subst_native` if you need number substitution. - pub fn from_text_native( + /// `from_text_and_number_subst` if you need number substitution. + pub fn from_text( inner: Box, text: Cow<'a, [wchar_t]>, ) -> CustomTextAnalysisSourceImpl<'a> { - assert!(text.len() <= (u32::MAX as usize)); - CustomTextAnalysisSourceImpl { - _refcount: AtomicUsize::new(1), - inner, - text, - number_subst: None, - locale_buf: [0u16; LOCALE_NAME_MAX_LENGTH], - } + CustomTextAnalysisSourceImpl { inner, text, number_subst: None } } /// Create a new custom TextAnalysisSource for the given text and a trait @@ -95,130 +44,84 @@ impl<'a> CustomTextAnalysisSourceImpl<'a> { /// /// Note: this method only supports a single `NumberSubstitution` for the /// entire string. - pub fn from_text_and_number_subst_native( + pub fn from_text_and_number_subst( inner: Box, text: Cow<'a, [wchar_t]>, number_subst: NumberSubstitution, ) -> CustomTextAnalysisSourceImpl<'a> { - assert!(text.len() <= (u32::MAX as usize)); - CustomTextAnalysisSourceImpl { - _refcount: AtomicUsize::new(1), - inner, - text, - number_subst: Some(number_subst), - locale_buf: [0u16; LOCALE_NAME_MAX_LENGTH], - } - } -} - -impl Com for CustomTextAnalysisSourceImpl<'_> { - type Vtbl = IDWriteTextAnalysisSourceVtbl; - #[inline] - fn vtbl() -> &'static IDWriteTextAnalysisSourceVtbl { - &TEXT_ANALYSIS_SOURCE_VTBL + CustomTextAnalysisSourceImpl { inner, text, number_subst: Some(number_subst) } } } -impl Com for CustomTextAnalysisSourceImpl<'_> { - type Vtbl = IUnknownVtbl; - #[inline] - fn vtbl() -> &'static IUnknownVtbl { - &TEXT_ANALYSIS_SOURCE_VTBL.parent +impl<'a> IDWriteTextAnalysisSource_Impl for CustomTextAnalysisSourceImpl_Impl<'a> { + fn GetTextAtPosition(&self, text_position: u32, text_string: *mut *mut u16, text_length: *mut u32) -> windows_core::Result<()> { + unsafe { + if text_position >= (self.text.len() as u32) { + *text_string = std::ptr::null_mut(); + *text_length = 0; + return Ok(()); + } + *text_string = self.text.as_ptr().add(text_position as usize) as *mut u16; + *text_length = (self.text.len() as u32) - text_position; + Ok(()) + } } -} -unsafe extern "system" fn CustomTextAnalysisSourceImpl_GetLocaleName( - this: *mut IDWriteTextAnalysisSource, - text_position: UINT32, - text_length: *mut UINT32, - locale_name: *mut *const wchar_t, -) -> HRESULT { - let this = CustomTextAnalysisSourceImpl::from_interface(this); - let (locale, text_len) = this.inner.get_locale_name(text_position); - - // Copy the locale data into the buffer - for (i, c) in OsStr::new(&*locale) - .encode_wide() - .chain(Some(0)) - .enumerate() - { - // -1 here is deliberate: it ensures that we never write to the last character in - // this.locale_buf, so that the buffer is always null-terminated. - if i >= this.locale_buf.len() - 1 { - break; + fn GetTextBeforePosition(&self, text_position: u32, text_string: *mut *mut u16, text_length: *mut u32) -> windows_core::Result<()> { + unsafe { + if text_position == 0 || text_position > (self.text.len() as u32) { + *text_string = std::ptr::null_mut(); + *text_length = 0; + return Ok(()); + } + *text_string = self.text.as_ptr() as *mut u16; + *text_length = text_position; + Ok(()) } - - *this.locale_buf.get_unchecked_mut(i) = c; } - *text_length = text_len; - *locale_name = this.locale_buf.as_ptr(); - S_OK -} - -unsafe extern "system" fn CustomTextAnalysisSourceImpl_GetNumberSubstitution( - this: *mut IDWriteTextAnalysisSource, - text_position: UINT32, - text_length: *mut UINT32, - number_substitution: *mut *mut IDWriteNumberSubstitution, -) -> HRESULT { - let this = CustomTextAnalysisSourceImpl::from_interface(this); - if text_position >= (this.text.len() as u32) { - return E_INVALIDARG; + fn GetParagraphReadingDirection(&self) -> DWRITE_READING_DIRECTION { + self.inner.get_paragraph_reading_direction() } - *text_length = (this.text.len() as UINT32) - text_position; - *number_substitution = match &this.number_subst { - Some(number_subst) => { - let com_ptr = &number_subst.native; - com_ptr.AddRef(); - com_ptr.as_raw() + fn GetLocaleName(&self, text_position: u32, text_length: *mut u32, locale_name: *mut *mut u16) -> windows_core::Result<()> { + unsafe { + let (locale, text_len) = self.inner.get_locale_name(text_position); + + // Copy the locale data into the buffer + let mut locale_buf: [u16; 32] = [0; 32]; + for (i, c) in OsStr::new(&*locale).encode_wide().chain(Some(0)).enumerate() { + // -1 here is deliberate: it ensures that we never write to the last character in + // this.locale_buf, so that the buffer is always null-terminated. + if i >= locale_buf.len() - 1 { + break; + } + *locale_buf.get_unchecked_mut(i) = c; + } + + *text_length = text_len; + *locale_name = locale_buf.as_ptr() as *mut u16; + Ok(()) } - None => std::ptr::null_mut(), - }; + } - S_OK -} + fn GetNumberSubstitution(&self, text_position: u32, text_length: *mut u32, number_substitution: windows_core::OutRef) -> windows_core::Result<()> { + unsafe { + if text_position >= (self.text.len() as u32) { + return Err(windows_core::Error::from_hresult(E_INVALIDARG)); + } -unsafe extern "system" fn CustomTextAnalysisSourceImpl_GetParagraphReadingDirection( - this: *mut IDWriteTextAnalysisSource, -) -> DWRITE_READING_DIRECTION { - let this = CustomTextAnalysisSourceImpl::from_interface(this); - this.inner.get_paragraph_reading_direction() -} + *text_length = (self.text.len() as u32) - text_position; + number_substitution.write(self.number_subst.as_ref().map(|n| n.native.clone()))?; -unsafe extern "system" fn CustomTextAnalysisSourceImpl_GetTextAtPosition( - this: *mut IDWriteTextAnalysisSource, - text_position: UINT32, - text_string: *mut *const wchar_t, - text_length: *mut UINT32, -) -> HRESULT { - let this = CustomTextAnalysisSourceImpl::from_interface(this); - if text_position >= (this.text.len() as u32) { - *text_string = null(); - *text_length = 0; - return S_OK; + Ok(()) + } } - *text_string = this.text.as_ptr().add(text_position as usize); - *text_length = (this.text.len() as UINT32) - text_position; - S_OK } -unsafe extern "system" fn CustomTextAnalysisSourceImpl_GetTextBeforePosition( - this: *mut IDWriteTextAnalysisSource, - text_position: UINT32, - text_string: *mut *const wchar_t, - text_length: *mut UINT32, -) -> HRESULT { - let this = CustomTextAnalysisSourceImpl::from_interface(this); - if text_position == 0 || text_position > (this.text.len() as u32) { - *text_string = null(); - *text_length = 0; - return S_OK; - } - *text_string = this.text.as_ptr(); - *text_length = text_position; - S_OK +/// A wrapped version of an `IDWriteNumberSubstitution` object. +pub struct NumberSubstitution { + pub(crate) native: IDWriteNumberSubstitution, } impl NumberSubstitution { @@ -228,17 +131,24 @@ impl NumberSubstitution { ignore_user_overrides: bool, ) -> NumberSubstitution { unsafe { - let mut native: *mut IDWriteNumberSubstitution = ptr::null_mut(); - let hr = (*DWriteFactory()).CreateNumberSubstitution( + let native = DWriteFactory().CreateNumberSubstitution( subst_method, - locale.to_wide_null().as_ptr(), - if ignore_user_overrides { TRUE } else { FALSE }, - &mut native, - ); - assert_eq!(hr, 0, "error creating number substitution"); - NumberSubstitution { - native: ComPtr::from_raw(native), - } + PCWSTR(locale.to_wide_null().as_ptr()), + ignore_user_overrides, + ).expect("error creating number substitution"); + NumberSubstitution { native } } } } + +/// The Rust side of a custom text analysis source implementation. +pub trait TextAnalysisSourceMethods { + /// Determine the locale for a range of text. + /// + /// Return locale and length of text (in utf-16 code units) for which the + /// locale is valid. + fn get_locale_name(&self, text_position: u32) -> (Cow<'_, str>, u32); + + /// Get the text direction for the paragraph. + fn get_paragraph_reading_direction(&self) -> DWRITE_READING_DIRECTION; +} diff --git a/src/types.rs b/src/types.rs index 6429fdc..374b464 100644 --- a/src/types.rs +++ b/src/types.rs @@ -4,7 +4,9 @@ /* this is include!()'d in lib.rs */ use std::mem; -use winapi::um::dwrite::{DWRITE_FONT_STYLE, DWRITE_FONT_WEIGHT, DWRITE_FONT_STRETCH}; +use windows::Win32::Graphics::DirectWrite::{ + DWRITE_FONT_STRETCH, DWRITE_FONT_STYLE, DWRITE_FONT_WEIGHT +}; // mirrors DWRITE_FONT_WEIGHT #[cfg_attr(feature = "serde_serialization", derive(Deserialize, Serialize))] @@ -25,9 +27,6 @@ pub enum FontWeight { } impl FontWeight { - fn t(&self) -> DWRITE_FONT_WEIGHT { - unsafe { mem::transmute::(self.to_u32()) } - } pub fn to_u32(&self) -> u32 { match self { FontWeight::Thin=> 100, @@ -62,6 +61,19 @@ impl FontWeight { } } +impl From for DWRITE_FONT_WEIGHT { + #[inline] + fn from(value: FontWeight) -> Self { + DWRITE_FONT_WEIGHT(value.to_u32() as i32) + } +} +impl From for FontWeight { + #[inline] + fn from(value: DWRITE_FONT_WEIGHT) -> FontWeight { + FontWeight::from_u32(value.0 as u32) + } +} + // mirrors DWRITE_FONT_STRETCH #[repr(u32)] #[cfg_attr(feature = "serde_serialization", derive(Deserialize, Serialize))] @@ -80,13 +92,23 @@ pub enum FontStretch { } impl FontStretch { - fn t(&self) -> DWRITE_FONT_STRETCH { - unsafe { mem::transmute::(*self) } - } pub fn to_u32(&self) -> u32 { unsafe { mem::transmute::(*self) } } pub fn from_u32(v: u32) -> FontStretch { unsafe { mem::transmute::(v) } } } +impl From for DWRITE_FONT_STRETCH { + #[inline] + fn from(value: FontStretch) -> Self { + DWRITE_FONT_STRETCH(value.to_u32() as i32) + } +} +impl From for FontStretch { + #[inline] + fn from(value: DWRITE_FONT_STRETCH) -> FontStretch { + FontStretch::from_u32(value.0 as u32) + } +} + // mirrors DWRITE_FONT_STYLE #[repr(u32)] #[cfg_attr(feature = "serde_serialization", derive(Deserialize, Serialize))] @@ -98,22 +120,51 @@ pub enum FontStyle { } impl FontStyle { - fn t(&self) -> DWRITE_FONT_STYLE { - unsafe { mem::transmute::(*self) } - } pub fn to_u32(&self) -> u32 { unsafe { mem::transmute::(*self) } } pub fn from_u32(v: u32) -> FontStyle { unsafe { mem::transmute::(v) } } } +impl From for DWRITE_FONT_STYLE { + #[inline] + fn from(value: FontStyle) -> Self { + DWRITE_FONT_STYLE(value.to_u32() as i32) + } +} +impl From for FontStyle { + #[inline] + fn from(value: DWRITE_FONT_STYLE) -> FontStyle { + FontStyle::from_u32(value.0 as u32) + } +} + // mirrors DWRITE_FONT_SIMULATIONS #[repr(u32)] #[derive(PartialEq, Debug, Clone, Copy)] pub enum FontSimulations { - None = winapi::um::dwrite::DWRITE_FONT_SIMULATIONS_NONE, - Bold = winapi::um::dwrite::DWRITE_FONT_SIMULATIONS_BOLD, - Oblique = winapi::um::dwrite::DWRITE_FONT_SIMULATIONS_OBLIQUE, - BoldOblique = winapi::um::dwrite::DWRITE_FONT_SIMULATIONS_BOLD | - winapi::um::dwrite::DWRITE_FONT_SIMULATIONS_OBLIQUE, + None = windows::Win32::Graphics::DirectWrite::DWRITE_FONT_SIMULATIONS_NONE.0 as u32, + Bold = windows::Win32::Graphics::DirectWrite::DWRITE_FONT_SIMULATIONS_BOLD.0 as u32, + Oblique = windows::Win32::Graphics::DirectWrite::DWRITE_FONT_SIMULATIONS_OBLIQUE.0 as u32, + BoldOblique = (windows::Win32::Graphics::DirectWrite::DWRITE_FONT_SIMULATIONS_BOLD.0 | + windows::Win32::Graphics::DirectWrite::DWRITE_FONT_SIMULATIONS_OBLIQUE.0) as u32, +} + +impl From for FontSimulations { + #[inline] + fn from(value: windows::Win32::Graphics::DirectWrite::DWRITE_FONT_SIMULATIONS) -> Self { + match value.0 { + x if x == FontSimulations::None as i32 => FontSimulations::None, + x if x == FontSimulations::Bold as i32 => FontSimulations::Bold, + x if x == FontSimulations::Oblique as i32 => FontSimulations::Oblique, + x if x == FontSimulations::BoldOblique as i32 => FontSimulations::BoldOblique, + _ => FontSimulations::None, // default case + } + } +} +impl From for windows::Win32::Graphics::DirectWrite::DWRITE_FONT_SIMULATIONS { + #[inline] + fn from(value: FontSimulations) -> Self { + windows::Win32::Graphics::DirectWrite::DWRITE_FONT_SIMULATIONS(value as i32) + } } #[cfg_attr(feature = "serde_serialization", derive(Deserialize, Serialize))]