Allow specific fonts in collections to be selected

This commit is contained in:
Patrick Walton 2017-02-08 15:34:16 -08:00
parent ed4bc9b5b6
commit a0b23592b5
5 changed files with 104 additions and 41 deletions

View File

@ -16,6 +16,7 @@ git = "https://github.com/pcwalton/compute-shader.git"
[dev-dependencies]
bencher = "0.1"
clap = "2.20"
image = "0.12"
quickcheck = "0.4"

View File

@ -1,6 +1,7 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
extern crate clap;
extern crate compute_shader;
extern crate euclid;
extern crate gl;
@ -9,9 +10,10 @@ extern crate lord_drawquaad;
extern crate memmap;
extern crate pathfinder;
use clap::{App, Arg};
use compute_shader::buffer;
use compute_shader::image::{ExternalImage, Format};
use compute_shader::instance::Instance;
use compute_shader::image::{Color, ExternalImage, Format};
use compute_shader::instance::{Instance, ShadingLanguage};
use euclid::{Point2D, Rect, Size2D};
use gl::types::{GLint, GLuint};
use glfw::{Action, Context, Key, OpenGlProfileHint, WindowEvent, WindowHint, WindowMode};
@ -22,7 +24,6 @@ use pathfinder::coverage::CoverageBuffer;
use pathfinder::outline::OutlineBuilder;
use pathfinder::otf::Font;
use pathfinder::rasterizer::{Rasterizer, RasterizerOptions};
use std::env;
use std::os::raw::c_void;
const DEFAULT_POINT_SIZE: f32 = 24.0;
@ -30,6 +31,20 @@ const WIDTH: u32 = 512;
const HEIGHT: u32 = 384;
fn main() {
let index_arg = Arg::with_name("index").short("i")
.long("index")
.help("Select an index within a font collection")
.takes_value(true);
let font_arg = Arg::with_name("FONT-FILE").help("Select the font file (`.ttf`, `.otf`, etc.)")
.required(true)
.index(1);
let point_size_arg = Arg::with_name("POINT-SIZE").help("Select the point size")
.index(2);
let matches = App::new("generate-atlas").arg(index_arg)
.arg(font_arg)
.arg(point_size_arg)
.get_matches();
let mut glfw = glfw::init(glfw::LOG_ERRORS).unwrap();
glfw.window_hint(WindowHint::ContextVersion(3, 3));
glfw.window_hint(WindowHint::OpenGlForwardCompat(true));
@ -48,23 +63,27 @@ fn main() {
let rasterizer_options = RasterizerOptions::from_env().unwrap();
let rasterizer = Rasterizer::new(&instance, device, queue, rasterizer_options).unwrap();
let file = Mmap::open_path(env::args().nth(1).unwrap(), Protection::Read).unwrap();
let file = Mmap::open_path(matches.value_of("FONT-FILE").unwrap(), Protection::Read).unwrap();
let point_size = match env::args().nth(2) {
let point_size = match matches.value_of("POINT-SIZE") {
Some(point_size) => point_size.parse().unwrap(),
None => DEFAULT_POINT_SIZE,
Some(point_size) => point_size.parse().unwrap()
};
let font_index = match matches.value_of("index") {
Some(index) => index.parse().unwrap(),
None => 0,
};
// FIXME(pcwalton)
let shelf_height = (point_size * 2.0).ceil() as u32;
let (outlines, atlas);
unsafe {
let font = Font::new(file.as_slice()).unwrap();
let font = Font::from_collection_index(file.as_slice(), font_index).unwrap();
let codepoint_ranges = [CodepointRange::new(' ' as u32, '~' as u32)];
let glyph_mapping = font.glyph_mapping_for_codepoint_ranges(&codepoint_ranges).unwrap();
let shelf_height = font.shelf_height(point_size);
let mut outline_builder = OutlineBuilder::new();
let mut glyph_count = 0;
for (_, glyph_id) in glyph_mapping.iter() {
@ -87,6 +106,8 @@ fn main() {
.create_image(Format::R8, buffer::Protection::ReadWrite, &atlas_size)
.unwrap();
rasterizer.queue().submit_clear(&image, &Color::UInt(0, 0, 0, 0), &[]).unwrap();
let rect = Rect::new(Point2D::new(0, 0), atlas_size);
rasterizer.draw_atlas(&image, &rect, &atlas, &outlines, &coverage_buffer).unwrap();
@ -96,7 +117,9 @@ fn main() {
let mut gl_texture = 0;
unsafe {
if instance.shading_language() == ShadingLanguage::Glsl {
gl::MemoryBarrier(gl::SHADER_IMAGE_ACCESS_BARRIER_BIT | gl::TEXTURE_FETCH_BARRIER_BIT);
}
gl::GenTextures(1, &mut gl_texture);
image.bind_to(&ExternalImage::GlTexture(gl_texture)).unwrap();

View File

@ -1,9 +1,7 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
#![feature(alloc_system)]
extern crate alloc_system;
extern crate clap;
extern crate compute_shader;
extern crate euclid;
extern crate gl;
@ -12,9 +10,10 @@ extern crate image;
extern crate memmap;
extern crate pathfinder;
use clap::{App, Arg};
use compute_shader::buffer;
use compute_shader::image::{ExternalImage, Format, Image};
use compute_shader::instance::Instance;
use compute_shader::instance::{Instance, ShadingLanguage};
use euclid::{Point2D, Rect, Size2D};
use gl::types::{GLchar, GLint, GLsizei, GLsizeiptr, GLuint, GLvoid};
use glfw::{Action, Context, Key, OpenGlProfileHint, SwapInterval, WindowEvent};
@ -28,13 +27,11 @@ use pathfinder::outline::{OutlineBuilder, Outlines};
use pathfinder::rasterizer::{DrawAtlasProfilingEvents, Rasterizer, RasterizerOptions};
use pathfinder::shaper;
use std::char;
use std::env;
use std::fs::File;
use std::io::Read;
use std::mem;
use std::os::raw::c_void;
use std::path::Path;
use std::process;
const ATLAS_SIZE: u32 = 2048;
const WIDTH: u32 = 640;
@ -55,6 +52,17 @@ static TEXT_COLOR: [f32; 4] = [0.0, 0.0, 0.0, 1.0];
static ATLAS_DUMP_FILENAME: &'static str = "lorem-ipsum-atlas.png";
fn main() {
let index_arg = Arg::with_name("index").short("i")
.long("index")
.help("Select an index within a font collection")
.takes_value(true);
let font_arg = Arg::with_name("FONT-FILE").help("Select the font file (`.ttf`, `.otf`, etc.)")
.required(true)
.index(1);
let text_arg = Arg::with_name("TEXT-FILE").help("Select a file containing text to display")
.index(2);
let matches = App::new("lorem-ipsum").arg(index_arg).arg(font_arg).arg(text_arg).get_matches();
let mut glfw = glfw::init(glfw::LOG_ERRORS).unwrap();
glfw.window_hint(WindowHint::ContextVersion(3, 3));
glfw.window_hint(WindowHint::OpenGlForwardCompat(true));
@ -74,12 +82,8 @@ fn main() {
let (width, height) = window.get_framebuffer_size();
let mut device_pixel_size = Size2D::new(width as u32, height as u32);
let mut args = env::args();
args.next();
let font_path = args.next().unwrap_or_else(|| usage());
let mut text = "".to_string();
match args.next() {
match matches.value_of("TEXT-FILE") {
Some(path) => drop(File::open(path).unwrap().read_to_string(&mut text).unwrap()),
None => text.push_str(TEXT),
}
@ -94,10 +98,15 @@ fn main() {
chars.sort();
let codepoint_ranges = CodepointRanges::from_sorted_chars(&chars);
let file = Mmap::open_path(font_path, Protection::Read).unwrap();
let font_index = match matches.value_of("index") {
Some(index) => index.parse().unwrap(),
None => 0,
};
let file = Mmap::open_path(matches.value_of("FONT-FILE").unwrap(), Protection::Read).unwrap();
let (font, glyph_mapping);
unsafe {
font = Font::new(file.as_slice()).unwrap();
font = Font::from_collection_index(file.as_slice(), font_index).unwrap();
glyph_mapping = font.glyph_mapping_for_codepoint_ranges(&codepoint_ranges.ranges).unwrap();
}
@ -270,6 +279,8 @@ struct Renderer {
fps_gl_texture: GLuint,
query: GLuint,
shading_language: ShadingLanguage,
}
impl Renderer {
@ -378,6 +389,8 @@ impl Renderer {
gl::GenQueries(1, &mut query);
}
let shading_language = instance.shading_language();
Renderer {
rasterizer: rasterizer,
@ -407,6 +420,8 @@ impl Renderer {
fps_gl_texture: fps_gl_texture,
query: query,
shading_language: shading_language,
}
}
@ -438,7 +453,10 @@ impl Renderer {
self.rasterizer.queue().flush().unwrap();
unsafe {
gl::MemoryBarrier(gl::SHADER_IMAGE_ACCESS_BARRIER_BIT | gl::TEXTURE_FETCH_BARRIER_BIT);
if self.shading_language == ShadingLanguage::Glsl {
gl::MemoryBarrier(gl::SHADER_IMAGE_ACCESS_BARRIER_BIT |
gl::TEXTURE_FETCH_BARRIER_BIT);
}
gl::Viewport(0,
0,
@ -794,11 +812,6 @@ fn create_image(rasterizer: &Rasterizer, atlas_size: &Size2D<u32>) -> (Image, GL
(compute_image, gl_texture)
}
fn usage() -> ! {
println!("usage: lorem-ipsum /path/to/font.ttf [/path/to/text.txt]");
process::exit(0)
}
static COMPOSITE_VERTEX_SHADER: &'static str = "\
#version 330

View File

@ -96,11 +96,24 @@ pub struct FontTable<'a> {
}
impl<'a> Font<'a> {
/// Creates a new font from a byte buffer containing the contents of a file (`.ttf`, `.otf`,
/// etc.)
/// Creates a new font from a byte buffer containing the contents of a file or font collection
/// (`.ttf`, `.ttc`, `.otf`, etc.)
///
/// If this is a `.ttc` or `.dfont` collection, this returns the first font within it. If you
/// want to read another one, use the `Font::from_collection_index` API.
///
/// Returns the font on success or an error on failure.
pub fn new<'b>(bytes: &'b [u8]) -> Result<Font<'b>, Error> {
Font::from_collection_index(bytes, 0)
}
/// Creates a new font from a single font within a byte buffer containing the contents of a
/// file or a font collection (`.ttf`, `.ttc`, `.otf`, etc.)
///
/// If this is a `.ttc` or `.dfont` collection, this returns the appropriate font within it.
///
/// Returns the font on success or an error on failure.
pub fn from_collection_index<'b>(bytes: &'b [u8], index: u32) -> Result<Font<'b>, Error> {
// Check magic number.
let mut reader = bytes;
let mut magic_number = try!(reader.read_u32::<BigEndian>().map_err(Error::eof));
@ -116,15 +129,16 @@ impl<'a> Font<'a> {
}
let num_fonts = try!(reader.read_u32::<BigEndian>().map_err(Error::eof));
if num_fonts == 0 {
return Err(Error::Failed)
if index >= num_fonts {
return Err(Error::FontIndexOutOfBounds)
}
try!(reader.jump(index as usize * mem::size_of::<u32>()).map_err(Error::eof));
let table_offset = try!(reader.read_u32::<BigEndian>().map_err(Error::eof));
Font::from_otf(&bytes, table_offset)
}
magic_number if SFNT_VERSIONS.contains(&magic_number) => Font::from_otf(bytes, 0),
0x0100 => Font::from_dfont(bytes),
0x0100 => Font::from_dfont_index(bytes, index),
OTTO => {
// TODO(pcwalton): Support CFF outlines.
Err(Error::UnsupportedCffOutlines)
@ -202,7 +216,7 @@ impl<'a> Font<'a> {
}
/// https://github.com/kreativekorp/ksfl/wiki/Macintosh-Resource-File-Format
fn from_dfont<'b>(bytes: &'b [u8]) -> Result<Font<'b>, Error> {
fn from_dfont_index<'b>(bytes: &'b [u8], index: u32) -> Result<Font<'b>, Error> {
let mut reader = bytes;
// Read the Mac resource file header.
@ -250,10 +264,14 @@ impl<'a> Font<'a> {
}
}
// Check whether the index is in bounds.
if index >= resource_count as u32 + 1 {
return Err(Error::FontIndexOutOfBounds)
}
// Find the font we're interested in.
//
// TODO(pcwalton): This only gets the first one. Allow the user of this library to select
// others.
try!(reader.jump(index as usize * (mem::size_of::<u16>() * 2 + mem::size_of::<u32>() * 2))
.map_err(Error::eof));
let sfnt_id = try!(reader.read_u16::<BigEndian>().map_err(Error::eof));
let sfnt_name_offset = try!(reader.read_u16::<BigEndian>().map_err(Error::eof));
let sfnt_data_offset = try!(reader.read_u32::<BigEndian>().map_err(Error::eof)) &
@ -351,6 +369,8 @@ pub enum Error {
Failed,
/// The file ended unexpectedly.
UnexpectedEof,
/// There is no font with this index in this font collection.
FontIndexOutOfBounds,
/// The file declared that it was in a version of the format we don't support.
UnsupportedVersion,
/// The file was of a format we don't support.

View File

@ -43,6 +43,7 @@ static DRAW_FRAGMENT_SHADER: &'static str = include_str!("../resources/shaders/d
pub struct Rasterizer {
device: Device,
queue: Queue,
shading_language: ShadingLanguage,
draw_program: GLuint,
accum_program: Program,
draw_vertex_array: GLuint,
@ -142,7 +143,8 @@ impl Rasterizer {
}
// FIXME(pcwalton): Don't panic if this fails to compile; just return an error.
let accum_source = match instance.shading_language() {
let shading_language = instance.shading_language();
let accum_source = match shading_language {
ShadingLanguage::Cl => ACCUM_CL_SHADER,
ShadingLanguage::Glsl => ACCUM_COMPUTE_SHADER,
};
@ -153,6 +155,7 @@ impl Rasterizer {
Ok(Rasterizer {
device: device,
queue: queue,
shading_language: shading_language,
draw_program: draw_program,
accum_program: accum_program,
draw_vertex_array: draw_vertex_array,
@ -255,8 +258,11 @@ impl Rasterizer {
// OpenCL, but I don't know how to do that portably (i.e. on Mac…) Just using
// `glFlush()` seems to work in practice.
gl::Flush();
if self.shading_language == ShadingLanguage::Glsl {
gl::MemoryBarrier(gl::ALL_BARRIER_BITS);
}
}
let accum_uniforms = [
(0, Uniform::Image(image)),