parent
f718aa9ce3
commit
07d978909c
|
@ -414,7 +414,7 @@ fn rasterize_glyph_with_core_graphics(font_key: &FontKey,
|
||||||
fn rasterize_glyph_with_core_graphics(_: &FontKey,
|
fn rasterize_glyph_with_core_graphics(_: &FontKey,
|
||||||
_: u32,
|
_: u32,
|
||||||
_: Arc<Vec<u8>>,
|
_: Arc<Vec<u8>>,
|
||||||
_: &FontInstance,
|
_: &FontInstance<FontKey>,
|
||||||
_: &GlyphKey)
|
_: &GlyphKey)
|
||||||
-> Result<GlyphImage, FontError> {
|
-> Result<GlyphImage, FontError> {
|
||||||
Err(FontError::ReferenceRasterizerUnavailable)
|
Err(FontError::ReferenceRasterizerUnavailable)
|
||||||
|
|
|
@ -8,18 +8,21 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
|
//! Font loading using a hybrid of Windows DirectWrite and FreeType for hinting.
|
||||||
|
|
||||||
#![allow(non_snake_case, non_upper_case_globals)]
|
#![allow(non_snake_case, non_upper_case_globals)]
|
||||||
|
|
||||||
use dwrite;
|
use dwrite;
|
||||||
use euclid::{Point2D, Size2D};
|
use euclid::{Point2D, Size2D};
|
||||||
use kernel32;
|
use kernel32;
|
||||||
use pathfinder_path_utils::PathCommand;
|
use lyon_path::PathEvent;
|
||||||
use pathfinder_path_utils::cubic::{CubicPathCommand, CubicPathCommandApproxStream};
|
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
use std::hash::Hash;
|
||||||
|
use std::iter::Cloned;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::os::raw::c_void;
|
use std::os::raw::c_void;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
use std::slice;
|
use std::slice::{self, Iter};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use uuid::IID_ID2D1SimplifiedGeometrySink;
|
use uuid::IID_ID2D1SimplifiedGeometrySink;
|
||||||
use winapi::winerror::{self, S_OK};
|
use winapi::winerror::{self, S_OK};
|
||||||
|
@ -30,13 +33,11 @@ use winapi::{FLOAT, GUID, HRESULT, ID2D1SimplifiedGeometrySinkVtbl, IDWriteFacto
|
||||||
use winapi::{IDWriteFontCollectionLoader, IDWriteFontCollectionLoaderVtbl, IDWriteFontFace};
|
use winapi::{IDWriteFontCollectionLoader, IDWriteFontCollectionLoaderVtbl, IDWriteFontFace};
|
||||||
use winapi::{IDWriteFontFile, IDWriteFontFileEnumerator, IDWriteFontFileEnumeratorVtbl};
|
use winapi::{IDWriteFontFile, IDWriteFontFileEnumerator, IDWriteFontFileEnumeratorVtbl};
|
||||||
use winapi::{IDWriteFontFileLoader, IDWriteFontFileLoaderVtbl, IDWriteFontFileStream};
|
use winapi::{IDWriteFontFileLoader, IDWriteFontFileLoaderVtbl, IDWriteFontFileStream};
|
||||||
use winapi::{IDWriteFontFileStreamVtbl, IDWriteGdiInterop, IDWriteGeometrySink, IUnknown};
|
use winapi::{IDWriteFontFileStreamVtbl, IDWriteGeometrySink, IUnknown, IUnknownVtbl, TRUE, UINT16};
|
||||||
use winapi::{IUnknownVtbl, TRUE, UINT16, UINT32, UINT64, UINT};
|
use winapi::{UINT32, UINT64, UINT};
|
||||||
|
|
||||||
use self::com::{PathfinderCoclass, PathfinderComObject, PathfinderComPtr};
|
use self::com::{PathfinderCoclass, PathfinderComObject, PathfinderComPtr};
|
||||||
use {FontInstance, FontKey, GlyphDimensions, GlyphKey};
|
use {FontInstance, GlyphDimensions, GlyphImage, GlyphKey};
|
||||||
|
|
||||||
//! Font loading using Windows DirectWrite.
|
|
||||||
|
|
||||||
mod com;
|
mod com;
|
||||||
|
|
||||||
|
@ -60,24 +61,18 @@ DEFINE_GUID! {
|
||||||
0x6d4865fe, 0x0ab8, 0x4d91, 0x8f, 0x62, 0x5d, 0xd6, 0xbe, 0x34, 0xa3, 0xe0
|
0x6d4865fe, 0x0ab8, 0x4d91, 0x8f, 0x62, 0x5d, 0xd6, 0xbe, 0x34, 0xa3, 0xe0
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type GlyphOutline = Vec<PathCommand>;
|
|
||||||
|
|
||||||
const CURVE_APPROX_ERROR_BOUND: f32 = 0.1;
|
|
||||||
|
|
||||||
static PATHFINDER_FONT_COLLECTION_KEY: [u8; 17] = *b"MEMORY_COLLECTION";
|
static PATHFINDER_FONT_COLLECTION_KEY: [u8; 17] = *b"MEMORY_COLLECTION";
|
||||||
static PATHFINDER_FONT_FILE_KEY: [u8; 11] = *b"MEMORY_FILE";
|
static PATHFINDER_FONT_FILE_KEY: [u8; 11] = *b"MEMORY_FILE";
|
||||||
|
|
||||||
/// An object that loads and renders fonts using Windows DirectWrite.
|
/// An object that loads and renders fonts using Windows DirectWrite.
|
||||||
pub struct FontContext {
|
pub struct FontContext<FK> where FK: Clone + Hash + Eq + Ord {
|
||||||
dwrite_factory: PathfinderComPtr<IDWriteFactory>,
|
dwrite_factory: PathfinderComPtr<IDWriteFactory>,
|
||||||
#[allow(unused)]
|
dwrite_font_faces: BTreeMap<FK, PathfinderComPtr<IDWriteFontFace>>,
|
||||||
dwrite_gdi_interop: PathfinderComPtr<IDWriteGdiInterop>,
|
|
||||||
dwrite_font_faces: BTreeMap<FontKey, PathfinderComPtr<IDWriteFontFace>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FontContext {
|
impl<FK> FontContext<FK> where FK: Clone + Hash + Eq + Ord {
|
||||||
/// Creates a new font context instance.
|
/// Creates a new font context instance.
|
||||||
pub fn new() -> Result<FontContext, ()> {
|
pub fn new() -> Result<FontContext<FK>, ()> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut factory: *mut IDWriteFactory = ptr::null_mut();
|
let mut factory: *mut IDWriteFactory = ptr::null_mut();
|
||||||
if !winerror::SUCCEEDED(dwrite::DWriteCreateFactory(winapi::DWRITE_FACTORY_TYPE_SHARED,
|
if !winerror::SUCCEEDED(dwrite::DWriteCreateFactory(winapi::DWRITE_FACTORY_TYPE_SHARED,
|
||||||
|
@ -88,15 +83,8 @@ impl FontContext {
|
||||||
}
|
}
|
||||||
let factory = PathfinderComPtr::new(factory);
|
let factory = PathfinderComPtr::new(factory);
|
||||||
|
|
||||||
let mut gdi_interop: *mut IDWriteGdiInterop = ptr::null_mut();
|
|
||||||
if !winerror::SUCCEEDED((**factory).GetGdiInterop(&mut gdi_interop)) {
|
|
||||||
return Err(())
|
|
||||||
}
|
|
||||||
let gdi_interop = PathfinderComPtr::new(gdi_interop);
|
|
||||||
|
|
||||||
Ok(FontContext {
|
Ok(FontContext {
|
||||||
dwrite_factory: factory,
|
dwrite_factory: factory,
|
||||||
dwrite_gdi_interop: gdi_interop,
|
|
||||||
dwrite_font_faces: BTreeMap::new(),
|
dwrite_font_faces: BTreeMap::new(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -111,7 +99,7 @@ impl FontContext {
|
||||||
///
|
///
|
||||||
/// `font_index` is the index of the font within the collection, if `bytes` refers to a
|
/// `font_index` is the index of the font within the collection, if `bytes` refers to a
|
||||||
/// collection (`.ttc`).
|
/// collection (`.ttc`).
|
||||||
pub fn add_font_from_memory(&mut self, font_key: &FontKey, bytes: Arc<Vec<u8>>, _: u32)
|
pub fn add_font_from_memory(&mut self, font_key: &FK, bytes: Arc<Vec<u8>>, _: u32)
|
||||||
-> Result<(), ()> {
|
-> Result<(), ()> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let font_file_loader = PathfinderFontFileLoader::new(bytes.clone());
|
let font_file_loader = PathfinderFontFileLoader::new(bytes.clone());
|
||||||
|
@ -185,7 +173,7 @@ impl FontContext {
|
||||||
return Err(())
|
return Err(())
|
||||||
}
|
}
|
||||||
|
|
||||||
self.dwrite_font_faces.insert(*font_key, font_face);
|
self.dwrite_font_faces.insert((*font_key).clone(), font_face);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -194,7 +182,7 @@ impl FontContext {
|
||||||
///
|
///
|
||||||
/// If the font isn't loaded, does nothing.
|
/// If the font isn't loaded, does nothing.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn delete_font(&mut self, font_key: &FontKey) {
|
pub fn delete_font(&mut self, font_key: &FK) {
|
||||||
self.dwrite_font_faces.remove(font_key);
|
self.dwrite_font_faces.remove(font_key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -205,7 +193,7 @@ impl FontContext {
|
||||||
/// libraries (including Pathfinder) apply modifications to the outlines: for example, to
|
/// libraries (including Pathfinder) apply modifications to the outlines: for example, to
|
||||||
/// dilate them for easier reading. To retrieve extents that account for these modifications,
|
/// dilate them for easier reading. To retrieve extents that account for these modifications,
|
||||||
/// set `exact` to false.
|
/// set `exact` to false.
|
||||||
pub fn glyph_dimensions(&self, font_instance: &FontInstance, glyph_key: &GlyphKey)
|
pub fn glyph_dimensions(&self, font_instance: &FontInstance<FK>, glyph_key: &GlyphKey)
|
||||||
-> Option<GlyphDimensions> {
|
-> Option<GlyphDimensions> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let font_face = match self.dwrite_font_faces.get(&font_instance.font_key) {
|
let font_face = match self.dwrite_font_faces.get(&font_instance.font_key) {
|
||||||
|
@ -231,7 +219,7 @@ impl FontContext {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a list of path commands that represent the given glyph in the given font.
|
/// Returns a list of path commands that represent the given glyph in the given font.
|
||||||
pub fn glyph_outline(&mut self, font_instance: &FontInstance, glyph_key: &GlyphKey)
|
pub fn glyph_outline(&mut self, font_instance: &FontInstance<FK>, glyph_key: &GlyphKey)
|
||||||
-> Result<GlyphOutline, ()> {
|
-> Result<GlyphOutline, ()> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let font_face = match self.dwrite_font_faces.get(&font_instance.font_key) {
|
let font_face = match self.dwrite_font_faces.get(&font_instance.font_key) {
|
||||||
|
@ -258,14 +246,20 @@ impl FontContext {
|
||||||
return Err(())
|
return Err(())
|
||||||
}
|
}
|
||||||
|
|
||||||
let approx_stream =
|
Ok(GlyphOutline {
|
||||||
CubicPathCommandApproxStream::new((**geometry_sink).commands.iter().cloned(),
|
events: mem::replace(&mut (**geometry_sink).commands, vec![]),
|
||||||
CURVE_APPROX_ERROR_BOUND);
|
})
|
||||||
|
|
||||||
let approx_commands: Vec<_> = approx_stream.collect();
|
|
||||||
Ok(approx_commands)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn rasterize_glyph_with_native_rasterizer(&self,
|
||||||
|
_font_instance: &FontInstance<FK>,
|
||||||
|
_glyph_key: &GlyphKey,
|
||||||
|
_exact: bool)
|
||||||
|
-> Result<GlyphImage, ()> {
|
||||||
|
// TODO(pcwalton)
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
|
@ -543,7 +537,7 @@ impl PathfinderFontFileStream {
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
struct PathfinderGeometrySink {
|
struct PathfinderGeometrySink {
|
||||||
object: PathfinderComObject<PathfinderGeometrySink>,
|
object: PathfinderComObject<PathfinderGeometrySink>,
|
||||||
commands: Vec<CubicPathCommand>,
|
commands: Vec<PathEvent>,
|
||||||
}
|
}
|
||||||
|
|
||||||
static PATHFINDER_GEOMETRY_SINK_VTABLE: ID2D1SimplifiedGeometrySinkVtbl =
|
static PATHFINDER_GEOMETRY_SINK_VTABLE: ID2D1SimplifiedGeometrySinkVtbl =
|
||||||
|
@ -591,9 +585,7 @@ impl PathfinderGeometrySink {
|
||||||
PathfinderGeometrySink::d2d_point_2f_to_flipped_f32_point(&bezier.point2);
|
PathfinderGeometrySink::d2d_point_2f_to_flipped_f32_point(&bezier.point2);
|
||||||
let endpoint =
|
let endpoint =
|
||||||
PathfinderGeometrySink::d2d_point_2f_to_flipped_f32_point(&bezier.point3);
|
PathfinderGeometrySink::d2d_point_2f_to_flipped_f32_point(&bezier.point3);
|
||||||
(*this).commands.push(CubicPathCommand::CubicCurveTo(control_point_0,
|
(*this).commands.push(PathEvent::CubicTo(control_point_0, control_point_1, endpoint));
|
||||||
control_point_1,
|
|
||||||
endpoint))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -604,7 +596,7 @@ impl PathfinderGeometrySink {
|
||||||
let points = slice::from_raw_parts(points, points_count as usize);
|
let points = slice::from_raw_parts(points, points_count as usize);
|
||||||
for point in points {
|
for point in points {
|
||||||
let point = PathfinderGeometrySink::d2d_point_2f_to_flipped_f32_point(&point);
|
let point = PathfinderGeometrySink::d2d_point_2f_to_flipped_f32_point(&point);
|
||||||
(*this).commands.push(CubicPathCommand::LineTo(point))
|
(*this).commands.push(PathEvent::LineTo(point))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -613,7 +605,7 @@ impl PathfinderGeometrySink {
|
||||||
_: D2D1_FIGURE_BEGIN) {
|
_: D2D1_FIGURE_BEGIN) {
|
||||||
let this = this as *mut PathfinderGeometrySink;
|
let this = this as *mut PathfinderGeometrySink;
|
||||||
let start_point = PathfinderGeometrySink::d2d_point_2f_to_flipped_f32_point(&start_point);
|
let start_point = PathfinderGeometrySink::d2d_point_2f_to_flipped_f32_point(&start_point);
|
||||||
(*this).commands.push(CubicPathCommand::MoveTo(start_point))
|
(*this).commands.push(PathEvent::MoveTo(start_point))
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe extern "system" fn Close(_: *mut IDWriteGeometrySink) -> HRESULT {
|
unsafe extern "system" fn Close(_: *mut IDWriteGeometrySink) -> HRESULT {
|
||||||
|
@ -624,7 +616,7 @@ impl PathfinderGeometrySink {
|
||||||
figure_end: D2D1_FIGURE_END) {
|
figure_end: D2D1_FIGURE_END) {
|
||||||
let this = this as *mut PathfinderGeometrySink;
|
let this = this as *mut PathfinderGeometrySink;
|
||||||
if figure_end == D2D1_FIGURE_END_CLOSED {
|
if figure_end == D2D1_FIGURE_END_CLOSED {
|
||||||
(*this).commands.push(CubicPathCommand::ClosePath)
|
(*this).commands.push(PathEvent::Close)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -641,3 +633,14 @@ impl PathfinderGeometrySink {
|
||||||
Point2D::new(point.x, -point.y)
|
Point2D::new(point.x, -point.y)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct GlyphOutline {
|
||||||
|
events: Vec<PathEvent>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GlyphOutline {
|
||||||
|
#[inline]
|
||||||
|
pub fn iter(&self) -> Cloned<Iter<PathEvent>> {
|
||||||
|
self.events.iter().cloned()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue