Minimal Win32 font platform implementation.

This uses a (very simple) Win32 API call to enumerate font
families available, and load them as byte buffers.

The font rasterization itself is done by freetype.

This gets Servo + WR + Windows working, but should be improved
by adding a proper implementation that matches fonts correctly
and also uses DirectWrite (or GDI) to handle font rasterization.
This commit is contained in:
Glenn Watson 2016-10-04 16:49:56 +10:00
parent 19a5a30113
commit 0849607239
7 changed files with 195 additions and 13 deletions

View file

@ -2,16 +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/. */
#[cfg(any(target_os = "linux", target_os = "android", all(target_os = "windows", target_env = "gnu")))]
pub use platform::freetype::{font, font_context, font_list, font_template};
#[cfg(any(target_os = "linux", target_os = "android", target_os = "windows"))]
pub use platform::freetype::{font, font_context};
#[cfg(any(target_os = "linux", target_os = "android"))]
pub use platform::freetype::{font_list, font_template};
#[cfg(target_os = "windows")]
pub use platform::windows::{font_list, font_template};
#[cfg(target_os = "macos")]
pub use platform::macos::{font, font_context, font_list, font_template};
#[cfg(all(target_os = "windows", target_env = "msvc"))]
pub use platform::dummy::{font, font_context, font_list, font_template};
#[cfg(any(target_os = "linux", target_os = "android", all(target_os = "windows", target_env = "gnu")))]
#[cfg(any(target_os = "linux", target_os = "android", target_os = "windows"))]
mod freetype {
use libc::c_char;
use std::ffi::CStr;
@ -25,7 +28,11 @@ mod freetype {
pub mod font;
pub mod font_context;
#[cfg(any(target_os = "linux", target_os = "android"))]
pub mod font_list;
#[cfg(any(target_os = "linux", target_os = "android"))]
pub mod font_template;
}
@ -37,10 +44,8 @@ mod macos {
pub mod font_template;
}
#[cfg(all(target_os = "windows", target_env = "msvc"))]
mod dummy {
pub mod font;
pub mod font_context;
#[cfg(target_os = "windows")]
mod windows {
pub mod font_list;
pub mod font_template;
}

View file

@ -0,0 +1,74 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use gdi32;
use std::ffi::OsString;
use std::os::windows::ffi::OsStringExt;
use std::ptr;
use winapi::{LOGFONTW, LPARAM, OUT_TT_ONLY_PRECIS, VOID};
use winapi::{c_int, DWORD, LF_FACESIZE};
pub static SANS_SERIF_FONT_FAMILY: &'static str = "Arial";
pub fn system_default_family(_: &str) -> Option<String> {
None
}
pub fn last_resort_font_families() -> Vec<String> {
vec!("Arial".to_owned())
}
unsafe extern "system" fn enum_font_callback(lpelfe: *const LOGFONTW,
_: *const VOID,
_: DWORD,
lparam: LPARAM) -> c_int {
let name = (*lpelfe).lfFaceName;
let term_pos = name.iter().position(|c| *c == 0).unwrap();
let name = OsString::from_wide(&name[0..term_pos]).into_string().unwrap();
let fonts = lparam as *mut Vec<String>;
let fonts = &mut *fonts;
fonts.push(name);
1
}
pub fn for_each_available_family<F>(mut callback: F) where F: FnMut(String) {
let mut fonts = Vec::new();
let mut config = LOGFONTW {
lfHeight: 0,
lfWidth: 0,
lfEscapement: 0,
lfOrientation: 0,
lfWeight: 0,
lfItalic: 0,
lfUnderline: 0,
lfStrikeOut: 0,
lfCharSet: 0,
lfOutPrecision: OUT_TT_ONLY_PRECIS as u8,
lfClipPrecision: 0,
lfQuality: 0,
lfPitchAndFamily: 0,
lfFaceName: [0; LF_FACESIZE],
};
unsafe {
let hdc = gdi32::CreateCompatibleDC(ptr::null_mut());
gdi32::EnumFontFamiliesExW(hdc,
&mut config,
Some(enum_font_callback),
&mut fonts as *mut Vec<String> as LPARAM,
0);
gdi32::DeleteDC(hdc);
}
for family in fonts {
callback(family);
}
}
pub fn for_each_variation<F>(family_name: &str, mut callback: F) where F: FnMut(String) {
callback(family_name.to_owned());
}

View file

@ -0,0 +1,89 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use gdi32;
use std::ffi::OsString;
use std::io::Error;
use std::os::windows::ffi::OsStrExt;
use std::ptr;
use string_cache::Atom;
use webrender_traits::NativeFontHandle;
use winapi::{DWORD, LF_FACESIZE, LOGFONTW, OUT_TT_ONLY_PRECIS, WCHAR};
const GDI_ERROR: DWORD = 0xffffffff;
#[derive(Deserialize, Serialize, Debug)]
pub struct FontTemplateData {
pub bytes: Vec<u8>,
pub identifier: Atom,
}
impl FontTemplateData {
pub fn new(identifier: Atom,
font_data: Option<Vec<u8>>) -> Result<FontTemplateData, Error> {
let bytes = match font_data {
Some(bytes) => {
bytes
},
None => {
assert!(identifier.len() < LF_FACESIZE);
let name = OsString::from(identifier.as_ref());
let buffer: Vec<WCHAR> = name.encode_wide().collect();
let mut string: [WCHAR; LF_FACESIZE] = [0; LF_FACESIZE];
for (src, dest) in buffer.iter().zip(string.iter_mut()) {
*dest = *src;
}
let config = LOGFONTW {
lfHeight: 0,
lfWidth: 0,
lfEscapement: 0,
lfOrientation: 0,
lfWeight: 0,
lfItalic: 0,
lfUnderline: 0,
lfStrikeOut: 0,
lfCharSet: 0,
lfOutPrecision: OUT_TT_ONLY_PRECIS as u8,
lfClipPrecision: 0,
lfQuality: 0,
lfPitchAndFamily: 0,
lfFaceName: string,
};
unsafe {
let hdc = gdi32::CreateCompatibleDC(ptr::null_mut());
let hfont = gdi32::CreateFontIndirectW(&config as *const _);
gdi32::SelectObject(hdc, hfont as *mut _);
let size = gdi32::GetFontData(hdc, 0, 0, ptr::null_mut(), 0);
assert!(size != GDI_ERROR);
let mut buffer: Vec<u8> = vec![0; size as usize];
let actual_size = gdi32::GetFontData(hdc, 0, 0, buffer.as_mut_ptr() as *mut _, size);
assert!(actual_size == size);
gdi32::DeleteDC(hdc);
gdi32::DeleteObject(hfont as *mut _);
buffer
}
}
};
Ok(FontTemplateData {
bytes: bytes,
identifier: identifier,
})
}
pub fn bytes(&self) -> Vec<u8> {
self.bytes.clone()
}
pub fn bytes_if_in_memory(&self) -> Option<Vec<u8>> {
Some(self.bytes())
}
pub fn native_font(&self) -> Option<NativeFontHandle> {
None
}
}