2017-01-09 22:49:00 -05:00
|
|
|
// Copyright 2017 The Servo Project Developers. See the COPYRIGHT
|
|
|
|
// file at the top-level directory of this distribution and at
|
|
|
|
// http://rust-lang.org/COPYRIGHT.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
// except according to those terms.
|
|
|
|
|
2017-02-07 22:32:32 -05:00
|
|
|
//! Glyph vectors, uploaded in a resolution-independent manner to the GPU.
|
|
|
|
|
2017-02-03 21:25:56 -05:00
|
|
|
use error::GlError;
|
2017-02-07 23:20:14 -05:00
|
|
|
use euclid::Size2D;
|
2017-01-24 01:03:40 -05:00
|
|
|
use gl::types::{GLsizeiptr, GLuint};
|
|
|
|
use gl;
|
2017-02-03 20:52:33 -05:00
|
|
|
use otf::{self, Font};
|
2017-01-24 01:03:40 -05:00
|
|
|
use std::mem;
|
|
|
|
use std::os::raw::c_void;
|
2017-01-09 22:49:00 -05:00
|
|
|
|
2017-01-24 18:30:14 -05:00
|
|
|
static DUMMY_VERTEX: Vertex = Vertex {
|
|
|
|
x: 0,
|
|
|
|
y: 0,
|
|
|
|
glyph_index: 0,
|
|
|
|
};
|
2017-01-24 01:03:40 -05:00
|
|
|
|
2017-02-07 23:02:10 -05:00
|
|
|
/// Packs up outlines for glyphs into a format that the GPU can process.
|
2017-02-03 20:18:05 -05:00
|
|
|
pub struct OutlineBuilder {
|
2017-02-07 23:02:10 -05:00
|
|
|
vertices: Vec<Vertex>,
|
|
|
|
indices: Vec<u32>,
|
|
|
|
descriptors: Vec<GlyphDescriptor>,
|
2017-01-09 22:49:00 -05:00
|
|
|
}
|
|
|
|
|
2017-02-03 20:18:05 -05:00
|
|
|
impl OutlineBuilder {
|
2017-02-07 23:02:10 -05:00
|
|
|
/// Creates a new empty set of outlines.
|
2017-01-09 22:49:00 -05:00
|
|
|
#[inline]
|
2017-02-03 20:18:05 -05:00
|
|
|
pub fn new() -> OutlineBuilder {
|
|
|
|
OutlineBuilder {
|
2017-01-24 18:30:14 -05:00
|
|
|
vertices: vec![DUMMY_VERTEX],
|
|
|
|
indices: vec![],
|
2017-01-09 22:49:00 -05:00
|
|
|
descriptors: vec![],
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-07 23:02:10 -05:00
|
|
|
/// Adds a new glyph to the outline builder. Returns the glyph index, which is useful for later
|
|
|
|
/// calls to `Atlas::pack_glyph()`.
|
2017-02-07 20:19:36 -05:00
|
|
|
pub fn add_glyph(&mut self, font: &Font, glyph_id: u16) -> Result<u16, otf::Error> {
|
2017-01-24 01:03:40 -05:00
|
|
|
let glyph_index = self.descriptors.len() as u16;
|
|
|
|
|
2017-01-24 18:30:14 -05:00
|
|
|
let mut point_index = self.vertices.len() as u32;
|
|
|
|
let start_index = self.indices.len() as u32;
|
2017-01-10 22:57:08 -05:00
|
|
|
let start_point = point_index;
|
2017-01-24 18:30:14 -05:00
|
|
|
let mut last_point_on_curve = true;
|
2017-01-09 22:49:00 -05:00
|
|
|
|
2017-02-02 20:00:37 -05:00
|
|
|
try!(font.for_each_point(glyph_id, |point| {
|
2017-01-24 18:30:14 -05:00
|
|
|
self.vertices.push(Vertex {
|
|
|
|
x: point.position.x,
|
|
|
|
y: point.position.y,
|
|
|
|
glyph_index: glyph_index,
|
|
|
|
});
|
|
|
|
|
2017-02-03 18:18:07 -05:00
|
|
|
if point.index_in_contour > 0 && point.on_curve {
|
|
|
|
let indices = if !last_point_on_curve {
|
2017-01-25 14:52:18 -05:00
|
|
|
[point_index - 2, point_index - 1, point_index]
|
2017-02-03 18:18:07 -05:00
|
|
|
} else {
|
|
|
|
[point_index - 1, 0, point_index]
|
2017-01-24 18:30:14 -05:00
|
|
|
};
|
|
|
|
self.indices.extend(indices.iter().cloned());
|
|
|
|
}
|
2017-01-09 22:49:00 -05:00
|
|
|
|
|
|
|
point_index += 1;
|
2017-01-24 18:30:14 -05:00
|
|
|
last_point_on_curve = point.on_curve
|
2017-01-09 22:49:00 -05:00
|
|
|
}));
|
|
|
|
|
2017-01-24 01:03:40 -05:00
|
|
|
// Add a glyph descriptor.
|
2017-01-10 22:57:08 -05:00
|
|
|
self.descriptors.push(GlyphDescriptor {
|
2017-02-02 20:00:37 -05:00
|
|
|
bounds: try!(font.glyph_bounds(glyph_id)),
|
|
|
|
units_per_em: font.units_per_em() as u32,
|
2017-01-10 22:57:08 -05:00
|
|
|
start_point: start_point as u32,
|
2017-01-24 18:30:14 -05:00
|
|
|
start_index: start_index,
|
2017-01-26 21:53:50 -05:00
|
|
|
glyph_id: glyph_id,
|
2017-01-10 22:57:08 -05:00
|
|
|
});
|
2017-01-10 16:37:01 -05:00
|
|
|
|
2017-02-07 20:19:36 -05:00
|
|
|
Ok(glyph_index)
|
2017-01-09 22:49:00 -05:00
|
|
|
}
|
2017-01-10 16:37:01 -05:00
|
|
|
|
2017-02-07 23:02:10 -05:00
|
|
|
/// Uploads the outlines to the GPU.
|
2017-02-07 22:32:32 -05:00
|
|
|
pub fn create_buffers(self) -> Result<Outlines, GlError> {
|
2017-01-24 18:30:14 -05:00
|
|
|
// TODO(pcwalton): Try using `glMapBuffer` here. Requires precomputing contour types and
|
|
|
|
// counts.
|
2017-01-24 01:03:40 -05:00
|
|
|
unsafe {
|
2017-01-24 18:30:14 -05:00
|
|
|
let (mut vertices, mut indices, mut descriptors) = (0, 0, 0);
|
|
|
|
gl::GenBuffers(1, &mut vertices);
|
|
|
|
gl::GenBuffers(1, &mut indices);
|
2017-01-24 01:03:40 -05:00
|
|
|
gl::GenBuffers(1, &mut descriptors);
|
|
|
|
|
2017-01-24 18:30:14 -05:00
|
|
|
gl::BindBuffer(gl::ARRAY_BUFFER, vertices);
|
2017-01-24 01:03:40 -05:00
|
|
|
gl::BufferData(gl::ARRAY_BUFFER,
|
2017-01-24 18:30:14 -05:00
|
|
|
(self.vertices.len() * mem::size_of::<Vertex>()) as GLsizeiptr,
|
|
|
|
self.vertices.as_ptr() as *const Vertex as *const c_void,
|
|
|
|
gl::STATIC_DRAW);
|
|
|
|
|
|
|
|
gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, indices);
|
|
|
|
gl::BufferData(gl::ELEMENT_ARRAY_BUFFER,
|
|
|
|
(self.indices.len() * mem::size_of::<u32>()) as GLsizeiptr,
|
|
|
|
self.indices.as_ptr() as *const u32 as *const c_void,
|
2017-01-24 01:03:40 -05:00
|
|
|
gl::STATIC_DRAW);
|
|
|
|
|
|
|
|
let length = self.descriptors.len() * mem::size_of::<GlyphDescriptor>();
|
|
|
|
gl::BindBuffer(gl::UNIFORM_BUFFER, descriptors);
|
|
|
|
gl::BufferData(gl::UNIFORM_BUFFER,
|
|
|
|
length as GLsizeiptr,
|
|
|
|
self.descriptors.as_ptr() as *const GlyphDescriptor as *const c_void,
|
|
|
|
gl::STATIC_DRAW);
|
|
|
|
|
2017-02-07 22:32:32 -05:00
|
|
|
Ok(Outlines {
|
|
|
|
vertices_buffer: vertices,
|
|
|
|
indices_buffer: indices,
|
|
|
|
descriptors_buffer: descriptors,
|
|
|
|
descriptors: self.descriptors,
|
|
|
|
indices_count: self.indices.len(),
|
2017-01-24 01:03:40 -05:00
|
|
|
})
|
|
|
|
}
|
2017-01-10 16:37:01 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-07 23:02:10 -05:00
|
|
|
/// Resolution-independent glyph vectors uploaded to the GPU.
|
2017-02-07 22:32:32 -05:00
|
|
|
pub struct Outlines {
|
2017-02-07 23:02:10 -05:00
|
|
|
vertices_buffer: GLuint,
|
|
|
|
indices_buffer: GLuint,
|
|
|
|
descriptors_buffer: GLuint,
|
|
|
|
descriptors: Vec<GlyphDescriptor>,
|
|
|
|
indices_count: usize,
|
2017-01-27 14:31:24 -05:00
|
|
|
}
|
|
|
|
|
2017-02-07 22:32:32 -05:00
|
|
|
impl Drop for Outlines {
|
2017-01-27 14:31:24 -05:00
|
|
|
fn drop(&mut self) {
|
|
|
|
unsafe {
|
2017-02-07 22:32:32 -05:00
|
|
|
gl::DeleteBuffers(1, &mut self.descriptors_buffer);
|
|
|
|
gl::DeleteBuffers(1, &mut self.indices_buffer);
|
|
|
|
gl::DeleteBuffers(1, &mut self.vertices_buffer);
|
2017-01-27 14:31:24 -05:00
|
|
|
}
|
|
|
|
}
|
2017-01-09 22:49:00 -05:00
|
|
|
}
|
|
|
|
|
2017-02-07 22:32:32 -05:00
|
|
|
impl Outlines {
|
2017-02-07 23:02:10 -05:00
|
|
|
#[doc(hidden)]
|
|
|
|
#[inline]
|
|
|
|
pub fn vertices_buffer(&self) -> GLuint {
|
|
|
|
self.vertices_buffer
|
|
|
|
}
|
|
|
|
|
|
|
|
#[doc(hidden)]
|
|
|
|
#[inline]
|
|
|
|
pub fn indices_buffer(&self) -> GLuint {
|
|
|
|
self.indices_buffer
|
|
|
|
}
|
|
|
|
|
|
|
|
#[doc(hidden)]
|
|
|
|
#[inline]
|
|
|
|
pub fn descriptors_buffer(&self) -> GLuint {
|
|
|
|
self.descriptors_buffer
|
|
|
|
}
|
|
|
|
|
|
|
|
#[doc(hidden)]
|
|
|
|
#[inline]
|
|
|
|
pub fn descriptor(&self, glyph_index: u16) -> Option<&GlyphDescriptor> {
|
|
|
|
self.descriptors.get(glyph_index as usize)
|
|
|
|
}
|
|
|
|
|
|
|
|
#[doc(hidden)]
|
|
|
|
#[inline]
|
|
|
|
pub fn indices_count(&self) -> usize {
|
|
|
|
self.indices_count
|
|
|
|
}
|
|
|
|
|
2017-02-07 22:32:32 -05:00
|
|
|
/// Returns the glyph rectangle in font units.
|
|
|
|
#[inline]
|
|
|
|
pub fn glyph_bounds(&self, glyph_index: u32) -> GlyphBounds {
|
|
|
|
self.descriptors[glyph_index as usize].bounds
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the glyph rectangle in fractional pixels.
|
|
|
|
#[inline]
|
|
|
|
pub fn glyph_subpixel_bounds(&self, glyph_index: u16, point_size: f32) -> GlyphSubpixelBounds {
|
|
|
|
self.descriptors[glyph_index as usize].subpixel_bounds(point_size)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the boundaries of the glyph, rounded out to the nearest pixel.
|
|
|
|
#[inline]
|
|
|
|
pub fn glyph_pixel_bounds(&self, glyph_index: u16, point_size: f32) -> GlyphPixelBounds {
|
|
|
|
self.descriptors[glyph_index as usize].subpixel_bounds(point_size).round_out()
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the ID of the glyph with the given index.
|
|
|
|
#[inline]
|
|
|
|
pub fn glyph_id(&self, glyph_index: u16) -> u16 {
|
|
|
|
self.descriptors[glyph_index as usize].glyph_id
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[doc(hidden)]
|
2017-01-09 22:49:00 -05:00
|
|
|
#[repr(C)]
|
2017-01-25 14:52:18 -05:00
|
|
|
#[derive(Clone, Copy, Debug)]
|
2017-01-09 22:49:00 -05:00
|
|
|
pub struct GlyphDescriptor {
|
2017-02-07 22:32:32 -05:00
|
|
|
bounds: GlyphBounds,
|
|
|
|
units_per_em: u32,
|
|
|
|
start_point: u32,
|
|
|
|
start_index: u32,
|
|
|
|
glyph_id: u16,
|
2017-01-10 16:37:01 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
impl GlyphDescriptor {
|
2017-02-07 22:32:32 -05:00
|
|
|
#[doc(hidden)]
|
2017-01-10 16:37:01 -05:00
|
|
|
#[inline]
|
2017-02-07 22:32:32 -05:00
|
|
|
pub fn start_index(&self) -> u32 {
|
|
|
|
self.start_index
|
2017-02-06 21:02:16 -05:00
|
|
|
}
|
|
|
|
|
2017-02-07 22:32:32 -05:00
|
|
|
#[doc(hidden)]
|
2017-02-06 21:02:16 -05:00
|
|
|
#[inline]
|
2017-02-07 22:32:32 -05:00
|
|
|
fn subpixel_bounds(&self, point_size: f32) -> GlyphSubpixelBounds {
|
|
|
|
self.bounds.subpixel_bounds(self.units_per_em as u16, point_size)
|
2017-01-10 16:37:01 -05:00
|
|
|
}
|
2017-01-09 22:49:00 -05:00
|
|
|
}
|
|
|
|
|
2017-02-07 23:02:10 -05:00
|
|
|
#[doc(hidden)]
|
2017-01-25 14:52:18 -05:00
|
|
|
#[derive(Copy, Clone, Debug)]
|
2017-01-24 18:30:14 -05:00
|
|
|
#[repr(C)]
|
|
|
|
pub struct Vertex {
|
2017-02-07 23:02:10 -05:00
|
|
|
x: i16,
|
|
|
|
y: i16,
|
|
|
|
glyph_index: u16,
|
2017-01-24 18:30:14 -05:00
|
|
|
}
|
|
|
|
|
2017-02-07 22:32:32 -05:00
|
|
|
/// The boundaries of the glyph in fractional pixels.
|
2017-01-26 23:56:14 -05:00
|
|
|
#[derive(Copy, Clone, Debug)]
|
2017-02-07 22:32:32 -05:00
|
|
|
pub struct GlyphSubpixelBounds {
|
2017-02-06 21:02:16 -05:00
|
|
|
pub left: f32,
|
|
|
|
pub bottom: f32,
|
|
|
|
pub right: f32,
|
|
|
|
pub top: f32,
|
|
|
|
}
|
|
|
|
|
2017-02-07 22:32:32 -05:00
|
|
|
impl GlyphSubpixelBounds {
|
|
|
|
/// Rounds these bounds out to the nearest pixel.
|
2017-02-06 21:02:16 -05:00
|
|
|
#[inline]
|
2017-02-07 22:32:32 -05:00
|
|
|
pub fn round_out(&self) -> GlyphPixelBounds {
|
|
|
|
GlyphPixelBounds {
|
2017-02-06 21:02:16 -05:00
|
|
|
left: self.left.floor() as i32,
|
|
|
|
bottom: self.bottom.floor() as i32,
|
|
|
|
right: self.right.ceil() as i32,
|
|
|
|
top: self.top.ceil() as i32,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-07 22:32:32 -05:00
|
|
|
/// Returns the total size of the glyph in fractional pixels.
|
2017-02-06 21:02:16 -05:00
|
|
|
#[inline]
|
|
|
|
pub fn size(&self) -> Size2D<f32> {
|
|
|
|
Size2D::new(self.right - self.left, self.top - self.bottom)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-07 22:32:32 -05:00
|
|
|
/// The boundaries of the glyph, rounded out to the nearest pixel.
|
|
|
|
#[derive(Copy, Clone, Debug)]
|
|
|
|
pub struct GlyphPixelBounds {
|
|
|
|
pub left: i32,
|
|
|
|
pub bottom: i32,
|
|
|
|
pub right: i32,
|
|
|
|
pub top: i32,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl GlyphPixelBounds {
|
|
|
|
/// Returns the total size of the glyph in whole pixels.
|
|
|
|
#[inline]
|
|
|
|
pub fn size(&self) -> Size2D<i32> {
|
|
|
|
Size2D::new(self.right - self.left, self.top - self.bottom)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-07 23:02:10 -05:00
|
|
|
/// The boundaries of a glyph in font units.
|
2017-02-06 21:02:16 -05:00
|
|
|
#[derive(Copy, Clone, Debug)]
|
2017-02-07 22:32:32 -05:00
|
|
|
pub struct GlyphBounds {
|
2017-01-26 23:56:14 -05:00
|
|
|
pub left: i32,
|
|
|
|
pub bottom: i32,
|
|
|
|
pub right: i32,
|
|
|
|
pub top: i32,
|
|
|
|
}
|
|
|
|
|
2017-02-07 22:32:32 -05:00
|
|
|
impl GlyphBounds {
|
2017-02-07 23:02:10 -05:00
|
|
|
/// Given the units per em of the font and the point size, returns the fractional boundaries of
|
|
|
|
/// this glyph.
|
2017-02-06 17:45:06 -05:00
|
|
|
#[inline]
|
2017-02-07 22:32:32 -05:00
|
|
|
pub fn subpixel_bounds(&self, units_per_em: u16, point_size: f32) -> GlyphSubpixelBounds {
|
2017-02-06 17:45:06 -05:00
|
|
|
let pixels_per_unit = point_size / units_per_em as f32;
|
2017-02-07 22:32:32 -05:00
|
|
|
GlyphSubpixelBounds {
|
2017-02-06 21:02:16 -05:00
|
|
|
left: self.left as f32 * pixels_per_unit,
|
|
|
|
bottom: self.bottom as f32 * pixels_per_unit,
|
|
|
|
right: self.right as f32 * pixels_per_unit,
|
|
|
|
top: self.top as f32 * pixels_per_unit,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-07 22:32:32 -05:00
|
|
|
/// Returns the total size of the glyph in font units.
|
2017-02-06 21:02:16 -05:00
|
|
|
#[inline]
|
|
|
|
pub fn size(&self) -> Size2D<i32> {
|
|
|
|
Size2D::new(self.right - self.left, self.top - self.bottom)
|
2017-02-06 17:45:06 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|