Rename `GlyphRanges` to `GlyphMapping` and document it

This commit is contained in:
Patrick Walton 2017-02-07 20:02:10 -08:00
parent dcd3eefa33
commit ccf17493e0
13 changed files with 303 additions and 236 deletions

View File

@ -71,10 +71,10 @@ fn main() {
let font = Font::new(file.as_slice()).unwrap();
let codepoint_ranges = [CodepointRange::new(' ' as u32, '~' as u32)];
let glyph_ranges = font.glyph_ranges_for_codepoint_ranges(&codepoint_ranges)
.unwrap();
let glyph_mapping = font.glyph_mapping_for_codepoint_ranges(&codepoint_ranges)
.unwrap();
let mut outline_builder = OutlineBuilder::new();
for (_, glyph_id) in glyph_ranges.iter().enumerate() {
for (_, glyph_id) in glyph_mapping.iter() {
outline_builder.add_glyph(&font, glyph_id).unwrap();
glyph_count += 1
}

View File

@ -17,8 +17,8 @@ fn main() {
unsafe {
let font = Font::new(file.as_slice()).unwrap();
let codepoint_ranges = [CodepointRange::new('!' as u32, '~' as u32)];
let glyph_ranges = font.glyph_ranges_for_codepoint_ranges(&codepoint_ranges).unwrap();
for (glyph_index, glyph_id) in glyph_ranges.iter().enumerate() {
let glyph_mapping = font.glyph_mapping_for_codepoint_ranges(&codepoint_ranges).unwrap();
for (glyph_index, (_, glyph_id)) in glyph_mapping.iter().enumerate() {
let codepoint = '!' as u32 + glyph_index as u32;
println!("Glyph {}: codepoint {} '{}':",
glyph_id,

View File

@ -63,17 +63,19 @@ fn main() {
unsafe {
let font = Font::new(file.as_slice()).unwrap();
let codepoint_ranges = [CodepointRange::new(' ' as u32, '~' as u32)];
let glyph_ranges = font.glyph_ranges_for_codepoint_ranges(&codepoint_ranges).unwrap();
let glyph_mapping = font.glyph_mapping_for_codepoint_ranges(&codepoint_ranges).unwrap();
let mut outline_builder = OutlineBuilder::new();
for (glyph_index, glyph_id) in glyph_ranges.iter().enumerate() {
let mut glyph_count = 0;
for (_, glyph_id) in glyph_mapping.iter() {
outline_builder.add_glyph(&font, glyph_id).unwrap();
glyph_count += 1
}
outlines = outline_builder.create_buffers().unwrap();
let mut atlas_builder = AtlasBuilder::new(device_pixel_width as GLuint, shelf_height);
for (glyph_index, glyph_id) in glyph_ranges.iter().enumerate() {
atlas_builder.pack_glyph(&outlines, glyph_index as u16, point_size).unwrap();
for glyph_index in 0..glyph_count {
atlas_builder.pack_glyph(&outlines, glyph_index, point_size).unwrap();
}
atlas = atlas_builder.create_atlas().unwrap();
}

View File

@ -20,9 +20,8 @@ use gl::types::{GLchar, GLint, GLsizei, GLsizeiptr, GLuint, GLvoid};
use glfw::{Action, Context, Key, OpenGlProfileHint, WindowEvent, WindowHint, WindowMode};
use memmap::{Mmap, Protection};
use pathfinder::atlas::{Atlas, AtlasBuilder};
use pathfinder::charmap::CodepointRanges;
use pathfinder::charmap::{CodepointRanges, GlyphMapping};
use pathfinder::coverage::CoverageBuffer;
use pathfinder::glyph_range::GlyphRanges;
use pathfinder::otf::Font;
use pathfinder::outline::{OutlineBuilder, Outlines};
use pathfinder::rasterizer::{DrawAtlasProfilingEvents, Rasterizer, RasterizerOptions};
@ -94,24 +93,24 @@ fn main() {
let codepoint_ranges = CodepointRanges::from_sorted_chars(&chars);
let file = Mmap::open_path(font_path, Protection::Read).unwrap();
let (font, glyph_ranges);
let (font, glyph_mapping);
unsafe {
font = Font::new(file.as_slice()).unwrap();
glyph_ranges = font.glyph_ranges_for_codepoint_ranges(&codepoint_ranges.ranges).unwrap();
glyph_mapping = font.glyph_mapping_for_codepoint_ranges(&codepoint_ranges.ranges).unwrap();
}
// Do some basic line breaking.
let mut glyph_positions = vec![];
let paragraph_width = (device_pixel_size.width as f32 * font.units_per_em() as f32 /
INITIAL_POINT_SIZE) as u32;
let space_advance = font.metrics_for_glyph(glyph_ranges.glyph_for(' ' as u32).unwrap())
let space_advance = font.metrics_for_glyph(glyph_mapping.glyph_for(' ' as u32).unwrap())
.unwrap()
.advance_width as u32;
let line_spacing = font.units_per_em() as u32;
let (mut current_x, mut current_y) = (0, line_spacing);
for word in text.split_whitespace() {
let shaped_glyph_positions = shaper::shape_text(&font, &glyph_ranges, word);
let shaped_glyph_positions = shaper::shape_text(&font, &glyph_mapping, word);
let total_advance: u32 = shaped_glyph_positions.iter().map(|p| p.advance as u32).sum();
if current_x + total_advance > paragraph_width {
current_x = 0;
@ -138,7 +137,7 @@ fn main() {
let mut outline_builder = OutlineBuilder::new();
let mut glyph_indices = vec![];
let mut glyph_count = 0;
for glyph_id in glyph_ranges.iter() {
for (_, glyph_id) in glyph_mapping.iter() {
let glyph_index = outline_builder.add_glyph(&font, glyph_id).unwrap();
while glyph_id as usize >= glyph_indices.len() {
@ -177,7 +176,7 @@ fn main() {
&outlines,
&device_pixel_size,
&glyph_indices,
&glyph_ranges,
&glyph_mapping,
draw_time,
accum_time,
timing,
@ -597,7 +596,7 @@ impl Renderer {
outlines: &Outlines,
device_pixel_size: &Size2D<u32>,
glyph_indices: &[u16],
glyph_ranges: &GlyphRanges,
glyph_mapping: &GlyphMapping,
draw_time: f64,
accum_time: f64,
composite_time: f64,
@ -642,7 +641,7 @@ impl Renderer {
let mut fps_glyphs = vec![];
let mut current_x = 0;
for glyph_pos in &shaper::shape_text(&font, &glyph_ranges, &fps_text) {
for glyph_pos in &shaper::shape_text(&font, &glyph_mapping, &fps_text) {
fps_glyphs.push(GlyphPos {
x: current_x,
y: 0,

View File

@ -74,7 +74,7 @@ impl AtlasBuilder {
let atlas_origin = try!(self.rect_packer.pack(&pixel_bounds.size().cast().unwrap()));
let glyph_id = outlines.glyph_id(glyph_index);
let glyph_index = self.image_descriptors.len() as u32;
let glyph_index = self.image_descriptors.len() as u16;
while self.image_descriptors.len() < glyph_index as usize + 1 {
self.image_descriptors.push(ImageDescriptor::default())
@ -92,12 +92,12 @@ impl AtlasBuilder {
}
self.image_metadata[glyph_index as usize] = ImageMetadata {
glyph_index: glyph_index,
glyph_index: glyph_index as u32,
glyph_id: glyph_id,
start_index: outlines.descriptors[glyph_index as usize].start_index(),
end_index: match outlines.descriptors.get(glyph_index as usize + 1) {
Some(ref descriptor) => descriptor.start_index() as u32,
None => outlines.indices_count as u32,
start_index: outlines.descriptor(glyph_index).unwrap().start_index(),
end_index: match outlines.descriptor(glyph_index + 1) {
Some(descriptor) => descriptor.start_index() as u32,
None => outlines.indices_count() as u32,
},
};

View File

@ -8,19 +8,28 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
/// An inclusive codepoint range.
//! A font's mapping from Unicode codepoints (characters) to glyphs.
//!
//! Consulting this table is typically the first step when rendering some text.
/// A consecutive series of Unicode codepoints.
#[derive(Clone, Copy, Debug)]
pub struct CodepointRange {
/// The starting code point, inclusive.
pub start: u32,
/// The ending code point, *inclusive*.
pub end: u32,
}
/// A collection of Unicode codepoints, organized into consecutive series.
#[derive(Clone, Debug)]
pub struct CodepointRanges {
/// Consecutive series of codepoints.
pub ranges: Vec<CodepointRange>,
}
impl CodepointRange {
/// Creates a new codepoint range from the given start and end codepoints, *inclusive*.
#[inline]
pub fn new(start: u32, end: u32) -> CodepointRange {
CodepointRange {
@ -29,6 +38,7 @@ impl CodepointRange {
}
}
/// Returns an iterator that iterates over all codepoints in this range.
#[inline]
pub fn iter(&self) -> CodepointRangeIter {
CodepointRangeIter {
@ -39,6 +49,10 @@ impl CodepointRange {
}
impl CodepointRanges {
/// Creates codepoint ranges from a sorted array of characters, collapsing duplicates.
///
/// This is useful when creating an atlas from a string. The array can be readily produced with
/// an expression like `"Hello world".chars().collect()`.
pub fn from_sorted_chars(chars: &[char]) -> CodepointRanges {
let mut ranges: Vec<CodepointRange> = vec![];
for &ch in chars {
@ -59,6 +73,7 @@ impl CodepointRanges {
}
}
/// An iterator over all codepoints in a range.
pub struct CodepointRangeIter {
start: u32,
end: u32,
@ -79,3 +94,173 @@ impl Iterator for CodepointRangeIter {
}
}
#[doc(hidden)]
#[derive(Clone, Copy, Debug)]
pub struct GlyphRange {
/// The starting glyph ID in the range, inclusive.
pub start: u16,
/// The ending glyph ID in the range, *inclusive*.
pub end: u16,
}
#[doc(hidden)]
#[derive(Clone, Copy, Debug)]
pub struct MappedGlyphRange {
pub codepoint_start: u32,
pub glyphs: GlyphRange,
}
/// A map from Unicode codepoints to glyph IDs.
#[derive(Clone, Debug)]
pub struct GlyphMapping {
ranges: Vec<MappedGlyphRange>,
}
impl GlyphRange {
/// Returns an iterator over every glyph in this range.
#[inline]
pub fn iter(&self) -> GlyphRangeIter {
GlyphRangeIter {
start: self.start,
end: self.end,
}
}
}
impl GlyphMapping {
#[doc(hidden)]
#[inline]
pub fn new() -> GlyphMapping {
GlyphMapping {
ranges: vec![],
}
}
#[doc(hidden)]
#[inline]
pub fn push(&mut self, range: MappedGlyphRange) {
self.ranges.push(range)
}
#[inline]
pub fn iter(&self) -> GlyphMappingIter {
if self.ranges.is_empty() {
return GlyphMappingIter {
start: GlyphRangesIndex {
range_index: 0,
glyph_index: 0,
},
end: GlyphRangesIndex {
range_index: 0,
glyph_index: 0,
},
codepoint: 0,
ranges: &self.ranges,
}
}
GlyphMappingIter {
start: GlyphRangesIndex {
range_index: 0,
glyph_index: self.ranges[0].glyphs.start,
},
end: GlyphRangesIndex {
range_index: (self.ranges.len() - 1) as u16,
glyph_index: self.ranges.last().unwrap().glyphs.end,
},
codepoint: self.ranges[0].codepoint_start,
ranges: &self.ranges,
}
}
pub fn glyph_for(&self, codepoint: u32) -> Option<u16> {
let (mut lo, mut hi) = (0, self.ranges.len());
while lo < hi {
let mid = (lo + hi) / 2;
if codepoint < self.ranges[mid].codepoint_start {
hi = mid
} else if codepoint > self.ranges[mid].codepoint_end() {
lo = mid + 1
} else {
return Some((codepoint - self.ranges[mid].codepoint_start) as u16 +
self.ranges[mid].glyphs.start)
}
}
None
}
}
#[derive(Clone)]
pub struct GlyphRangeIter {
start: u16,
end: u16,
}
impl Iterator for GlyphRangeIter {
type Item = u16;
#[inline]
fn next(&mut self) -> Option<u16> {
if self.start > self.end {
None
} else {
let item = self.start;
self.start += 1;
Some(item)
}
}
}
/// An iterator over the codepoint-to-glyph mapping.
///
/// Every call to `next()` returns a tuple consisting of the codepoint and glyph ID, in that order.
#[derive(Clone)]
pub struct GlyphMappingIter<'a> {
start: GlyphRangesIndex,
end: GlyphRangesIndex,
codepoint: u32,
ranges: &'a [MappedGlyphRange],
}
impl<'a> Iterator for GlyphMappingIter<'a> {
type Item = (u32, u16);
#[inline]
fn next(&mut self) -> Option<(u32, u16)> {
if self.start.range_index > self.end.range_index {
return None
}
let item = (self.codepoint, self.start.glyph_index);
self.codepoint += 1;
self.start.glyph_index += 1;
while self.start.glyph_index > self.ranges[self.start.range_index as usize].glyphs.end {
self.start.range_index += 1;
if self.start.range_index > self.end.range_index {
break
}
self.start.glyph_index = self.ranges[self.start.range_index as usize].glyphs.start;
self.codepoint = self.ranges[self.start.range_index as usize].codepoint_start;
}
Some(item)
}
}
#[derive(Clone, Copy, Debug)]
struct GlyphRangesIndex {
range_index: u16,
glyph_index: u16,
}
impl MappedGlyphRange {
/// Inclusive.
#[inline]
pub fn codepoint_end(&self) -> u32 {
self.codepoint_start + self.glyphs.end as u32 - self.glyphs.start as u32
}
}

View File

@ -1,157 +0,0 @@
// 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.
#[derive(Clone, Copy, Debug)]
pub struct GlyphRange {
pub start: u16,
pub end: u16,
}
#[derive(Clone, Copy, Debug)]
pub struct MappedGlyphRange {
pub codepoint_start: u32,
pub glyphs: GlyphRange,
}
#[derive(Clone, Debug)]
pub struct GlyphRanges {
pub ranges: Vec<MappedGlyphRange>,
}
impl GlyphRange {
#[inline]
pub fn iter(&self) -> GlyphRangeIter {
GlyphRangeIter {
start: self.start,
end: self.end,
}
}
}
impl GlyphRanges {
#[inline]
pub fn new() -> GlyphRanges {
GlyphRanges {
ranges: vec![],
}
}
#[inline]
pub fn iter(&self) -> GlyphRangesIter {
if self.ranges.is_empty() {
return GlyphRangesIter {
start: GlyphRangesIndex {
range_index: 0,
glyph_index: 0,
},
end: GlyphRangesIndex {
range_index: 0,
glyph_index: 0,
},
ranges: &self.ranges,
}
}
GlyphRangesIter {
start: GlyphRangesIndex {
range_index: 0,
glyph_index: self.ranges[0].glyphs.start,
},
end: GlyphRangesIndex {
range_index: (self.ranges.len() - 1) as u16,
glyph_index: self.ranges.last().unwrap().glyphs.end,
},
ranges: &self.ranges,
}
}
pub fn glyph_for(&self, codepoint: u32) -> Option<u16> {
let (mut lo, mut hi) = (0, self.ranges.len());
while lo < hi {
let mid = (lo + hi) / 2;
if codepoint < self.ranges[mid].codepoint_start {
hi = mid
} else if codepoint > self.ranges[mid].codepoint_end() {
lo = mid + 1
} else {
return Some((codepoint - self.ranges[mid].codepoint_start) as u16 +
self.ranges[mid].glyphs.start)
}
}
None
}
}
#[derive(Clone)]
pub struct GlyphRangeIter {
start: u16,
end: u16,
}
impl Iterator for GlyphRangeIter {
type Item = u16;
#[inline]
fn next(&mut self) -> Option<u16> {
if self.start > self.end {
None
} else {
let item = self.start;
self.start += 1;
Some(item)
}
}
}
#[derive(Clone)]
pub struct GlyphRangesIter<'a> {
start: GlyphRangesIndex,
end: GlyphRangesIndex,
ranges: &'a [MappedGlyphRange],
}
impl<'a> Iterator for GlyphRangesIter<'a> {
type Item = u16;
#[inline]
fn next(&mut self) -> Option<u16> {
if self.start.range_index > self.end.range_index {
return None
}
let item = self.start.glyph_index;
self.start.glyph_index += 1;
while self.start.glyph_index > self.ranges[self.start.range_index as usize].glyphs.end {
self.start.range_index += 1;
if self.start.range_index > self.end.range_index {
break
}
self.start.glyph_index = self.ranges[self.start.range_index as usize].glyphs.start
}
Some(item)
}
}
#[derive(Clone, Copy, Debug)]
struct GlyphRangesIndex {
range_index: u16,
glyph_index: u16,
}
impl MappedGlyphRange {
/// Inclusive.
#[inline]
pub fn codepoint_end(&self) -> u32 {
self.codepoint_start + self.glyphs.end as u32 - self.glyphs.start as u32
}
}

View File

@ -8,6 +8,11 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! A high-performance GPU rasterizer for OpenType fonts.
//!
//! Pathfinder rasterizes glyphs from a `.ttf`, `.ttc`, or `.otf` file loaded in memory to an atlas
//! texture.
#![cfg_attr(test, feature(test))]
#[macro_use]
@ -28,7 +33,6 @@ pub mod atlas;
pub mod charmap;
pub mod coverage;
pub mod error;
pub mod glyph_range;
pub mod otf;
pub mod outline;
pub mod rasterizer;

View File

@ -9,8 +9,7 @@
// except according to those terms.
use byteorder::{BigEndian, ReadBytesExt};
use charmap::CodepointRange;
use glyph_range::{GlyphRange, GlyphRanges, MappedGlyphRange};
use charmap::{CodepointRange, GlyphMapping, GlyphRange, MappedGlyphRange};
use otf::{Error, FontTable};
use std::char;
use std::cmp;
@ -41,8 +40,8 @@ impl<'a> CmapTable<'a> {
}
}
pub fn glyph_ranges_for_codepoint_ranges(&self, codepoint_ranges: &[CodepointRange])
-> Result<GlyphRanges, Error> {
pub fn glyph_mapping_for_codepoint_ranges(&self, codepoint_ranges: &[CodepointRange])
-> Result<GlyphMapping, Error> {
let mut cmap_reader = self.table.bytes;
// Check version.
@ -81,22 +80,22 @@ impl<'a> CmapTable<'a> {
let format = try!(cmap_reader.read_u16::<BigEndian>().map_err(Error::eof));
match format {
FORMAT_SEGMENT_MAPPING_TO_DELTA_VALUES => {
self.glyph_ranges_for_codepoint_ranges_segment_mapping_format(cmap_reader,
codepoint_ranges)
self.glyph_mapping_for_codepoint_ranges_segment_mapping_format(cmap_reader,
codepoint_ranges)
}
FORMAT_SEGMENTED_COVERAGE => {
self.glyph_ranges_for_codepoint_ranges_segmented_coverage(cmap_reader,
codepoint_ranges)
self.glyph_mapping_for_codepoint_ranges_segmented_coverage(cmap_reader,
codepoint_ranges)
}
_ => Err(Error::UnsupportedCmapFormat),
}
}
fn glyph_ranges_for_codepoint_ranges_segment_mapping_format(
fn glyph_mapping_for_codepoint_ranges_segment_mapping_format(
&self,
mut cmap_reader: &[u8],
codepoint_ranges: &[CodepointRange])
-> Result<GlyphRanges, Error> {
-> Result<GlyphMapping, Error> {
// Read the mapping table header.
let _length = try!(cmap_reader.read_u16::<BigEndian>().map_err(Error::eof));
let _language = try!(cmap_reader.read_u16::<BigEndian>().map_err(Error::eof));
@ -122,12 +121,12 @@ impl<'a> CmapTable<'a> {
try!(glyph_ids.jump(seg_count as usize * mem::size_of::<u16>()).map_err(Error::eof));
// Now perform the lookups.
let mut glyph_ranges = GlyphRanges::new();
let mut glyph_mapping = GlyphMapping::new();
for codepoint_range in codepoint_ranges {
let mut codepoint_range = *codepoint_range;
while codepoint_range.end >= codepoint_range.start {
if codepoint_range.start > u16::MAX as u32 {
glyph_ranges.ranges.push(MappedGlyphRange {
glyph_mapping.push(MappedGlyphRange {
codepoint_start: codepoint_range.start,
glyphs: GlyphRange {
start: MISSING_GLYPH,
@ -170,7 +169,7 @@ impl<'a> CmapTable<'a> {
let segment_index = match segment_index {
Some(segment_index) => segment_index,
None => {
glyph_ranges.ranges.push(MappedGlyphRange {
glyph_mapping.push(MappedGlyphRange {
codepoint_start: codepoint_range.start,
glyphs: GlyphRange {
start: MISSING_GLYPH,
@ -209,7 +208,7 @@ impl<'a> CmapTable<'a> {
// Microsoft's documentation is contradictory as to whether the code offset or
// the actual code is added to the ID delta here. In reality it seems to be the
// latter.
glyph_ranges.ranges.push(MappedGlyphRange {
glyph_mapping.push(MappedGlyphRange {
codepoint_start: start_codepoint_range as u32,
glyphs: GlyphRange {
start: (start_codepoint_range as i16).wrapping_add(id_delta) as u16,
@ -226,7 +225,7 @@ impl<'a> CmapTable<'a> {
id_range_offset as usize).map_err(Error::eof));
let mut glyph_id = try!(reader.read_u16::<BigEndian>().map_err(Error::eof));
if glyph_id == 0 {
glyph_ranges.ranges.push(MappedGlyphRange {
glyph_mapping.push(MappedGlyphRange {
codepoint_start: start_code as u32 + code_offset as u32,
glyphs: GlyphRange {
start: MISSING_GLYPH,
@ -235,7 +234,7 @@ impl<'a> CmapTable<'a> {
})
} else {
glyph_id = (glyph_id as i16).wrapping_add(id_delta) as u16;
glyph_ranges.ranges.push(MappedGlyphRange {
glyph_mapping.push(MappedGlyphRange {
codepoint_start: start_code as u32 + code_offset as u32,
glyphs: GlyphRange {
start: glyph_id,
@ -247,20 +246,20 @@ impl<'a> CmapTable<'a> {
}
}
Ok(glyph_ranges)
Ok(glyph_mapping)
}
fn glyph_ranges_for_codepoint_ranges_segmented_coverage(&self,
mut cmap_reader: &[u8],
codepoint_ranges: &[CodepointRange])
-> Result<GlyphRanges, Error> {
fn glyph_mapping_for_codepoint_ranges_segmented_coverage(&self,
mut cmap_reader: &[u8],
codepoint_ranges: &[CodepointRange])
-> Result<GlyphMapping, Error> {
let _reserved = try!(cmap_reader.read_u16::<BigEndian>().map_err(Error::eof));
let _length = try!(cmap_reader.read_u32::<BigEndian>().map_err(Error::eof));
let _language = try!(cmap_reader.read_u32::<BigEndian>().map_err(Error::eof));
let num_groups = try!(cmap_reader.read_u32::<BigEndian>().map_err(Error::eof));
// Now perform the lookups.
let mut glyph_ranges = GlyphRanges::new();
let mut glyph_mapping = GlyphMapping::new();
for codepoint_range in codepoint_ranges {
let mut codepoint_range = *codepoint_range;
while codepoint_range.end >= codepoint_range.start {
@ -291,7 +290,7 @@ impl<'a> CmapTable<'a> {
match found_segment {
None => {
glyph_ranges.ranges.push(MappedGlyphRange {
glyph_mapping.push(MappedGlyphRange {
codepoint_start: codepoint_range.start,
glyphs: GlyphRange {
start: MISSING_GLYPH,
@ -302,7 +301,7 @@ impl<'a> CmapTable<'a> {
}
Some(segment) => {
let end = cmp::min(codepoint_range.end, segment.end_char_code);
glyph_ranges.ranges.push(MappedGlyphRange {
glyph_mapping.push(MappedGlyphRange {
codepoint_start: codepoint_range.start,
glyphs: GlyphRange {
start: (segment.start_glyph_id + codepoint_range.start -
@ -317,7 +316,7 @@ impl<'a> CmapTable<'a> {
}
}
Ok(glyph_ranges)
Ok(glyph_mapping)
}
}

View File

@ -11,8 +11,7 @@
//! OpenType fonts.
use byteorder::{BigEndian, ReadBytesExt};
use charmap::CodepointRange;
use glyph_range::GlyphRanges;
use charmap::{CodepointRange, GlyphMapping};
use otf::cmap::CmapTable;
use otf::glyf::{GlyfTable, Point};
use otf::head::HeadTable;
@ -273,9 +272,9 @@ impl<'a> Font<'a> {
///
/// The returned glyph ranges are in the same order as the codepoints.
#[inline]
pub fn glyph_ranges_for_codepoint_ranges(&self, codepoint_ranges: &[CodepointRange])
-> Result<GlyphRanges, Error> {
self.cmap.glyph_ranges_for_codepoint_ranges(codepoint_ranges)
pub fn glyph_mapping_for_codepoint_ranges(&self, codepoint_ranges: &[CodepointRange])
-> Result<GlyphMapping, Error> {
self.cmap.glyph_mapping_for_codepoint_ranges(codepoint_ranges)
}
/// Calls the given callback for each point in the supplied glyph's contour.

View File

@ -24,13 +24,15 @@ static DUMMY_VERTEX: Vertex = Vertex {
glyph_index: 0,
};
/// Packs up outlines for glyphs into a format that the GPU can process.
pub struct OutlineBuilder {
pub vertices: Vec<Vertex>,
pub indices: Vec<u32>,
pub descriptors: Vec<GlyphDescriptor>,
vertices: Vec<Vertex>,
indices: Vec<u32>,
descriptors: Vec<GlyphDescriptor>,
}
impl OutlineBuilder {
/// Creates a new empty set of outlines.
#[inline]
pub fn new() -> OutlineBuilder {
OutlineBuilder {
@ -40,8 +42,8 @@ impl OutlineBuilder {
}
}
/// Adds a new glyph to the outline builder. Returns the glyph index, useful for calls to
/// `Atlas::pack_glyph()`.
/// Adds a new glyph to the outline builder. Returns the glyph index, which is useful for later
/// calls to `Atlas::pack_glyph()`.
pub fn add_glyph(&mut self, font: &Font, glyph_id: u16) -> Result<u16, otf::Error> {
let glyph_index = self.descriptors.len() as u16;
@ -82,6 +84,7 @@ impl OutlineBuilder {
Ok(glyph_index)
}
/// Uploads the outlines to the GPU.
pub fn create_buffers(self) -> Result<Outlines, GlError> {
// TODO(pcwalton): Try using `glMapBuffer` here. Requires precomputing contour types and
// counts.
@ -121,12 +124,13 @@ impl OutlineBuilder {
}
}
/// Resolution-independent glyph vectors uploaded to the GPU.
pub struct Outlines {
pub vertices_buffer: GLuint,
pub indices_buffer: GLuint,
pub descriptors_buffer: GLuint,
pub descriptors: Vec<GlyphDescriptor>,
pub indices_count: usize,
vertices_buffer: GLuint,
indices_buffer: GLuint,
descriptors_buffer: GLuint,
descriptors: Vec<GlyphDescriptor>,
indices_count: usize,
}
impl Drop for Outlines {
@ -140,6 +144,36 @@ impl Drop for Outlines {
}
impl Outlines {
#[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
}
/// Returns the glyph rectangle in font units.
#[inline]
pub fn glyph_bounds(&self, glyph_index: u32) -> GlyphBounds {
@ -190,14 +224,13 @@ impl GlyphDescriptor {
}
}
#[doc(hidden)]
#[derive(Copy, Clone, Debug)]
#[repr(C)]
pub struct Vertex {
pub x: i16,
pub y: i16,
/// TODO(pcwalton): Try omitting this and binary search the glyph descriptors in the vertex
/// shader. Might or might not help.
pub glyph_index: u16,
x: i16,
y: i16,
glyph_index: u16,
}
/// The boundaries of the glyph in fractional pixels.
@ -245,6 +278,7 @@ impl GlyphPixelBounds {
}
}
/// The boundaries of a glyph in font units.
#[derive(Copy, Clone, Debug)]
pub struct GlyphBounds {
pub left: i32,
@ -254,6 +288,8 @@ pub struct GlyphBounds {
}
impl GlyphBounds {
/// Given the units per em of the font and the point size, returns the fractional boundaries of
/// this glyph.
#[inline]
pub fn subpixel_bounds(&self, units_per_em: u16, point_size: f32) -> GlyphSubpixelBounds {
let pixels_per_unit = point_size / units_per_em as f32;

View File

@ -163,7 +163,7 @@ impl Rasterizer {
gl::UseProgram(self.draw_program);
// Set up the buffer layout.
gl::BindBuffer(gl::ARRAY_BUFFER, outlines.vertices_buffer);
gl::BindBuffer(gl::ARRAY_BUFFER, outlines.vertices_buffer());
gl::VertexAttribIPointer(self.draw_position_attribute as GLuint,
2,
gl::SHORT,
@ -177,9 +177,9 @@ impl Rasterizer {
gl::EnableVertexAttribArray(self.draw_position_attribute as GLuint);
gl::EnableVertexAttribArray(self.draw_glyph_index_attribute as GLuint);
gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, outlines.indices_buffer);
gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, outlines.indices_buffer());
gl::BindBufferBase(gl::UNIFORM_BUFFER, 1, outlines.descriptors_buffer);
gl::BindBufferBase(gl::UNIFORM_BUFFER, 1, outlines.descriptors_buffer());
gl::BindBufferBase(gl::UNIFORM_BUFFER, 2, atlas.images_buffer());
gl::UniformBlockBinding(self.draw_program, self.draw_glyph_descriptors_uniform, 1);
gl::UniformBlockBinding(self.draw_program, self.draw_image_descriptors_uniform, 2);

View File

@ -14,7 +14,7 @@
//! ligation, or advanced typography features (`GSUB`, `GPOS`, text morphing). Consider HarfBuzz or
//! the system shaper instead.
use glyph_range::GlyphRanges;
use charmap::GlyphMapping;
use otf::Font;
use std::cmp;
@ -22,11 +22,11 @@ use std::cmp;
///
/// See the description of this module for caveats.
///
/// For proper operation, the given `glyph_ranges` must include all the glyphs necessary to render
/// For proper operation, the given `glyph_mapping` must include all the glyphs necessary to render
/// the string.
pub fn shape_text(font: &Font, glyph_ranges: &GlyphRanges, string: &str) -> Vec<GlyphPos> {
pub fn shape_text(font: &Font, glyph_mapping: &GlyphMapping, string: &str) -> Vec<GlyphPos> {
string.chars().map(|ch| {
let glyph_id = glyph_ranges.glyph_for(ch as u32).unwrap_or(0);
let glyph_id = glyph_mapping.glyph_for(ch as u32).unwrap_or(0);
let metrics = font.metrics_for_glyph(glyph_id);
let advance = match metrics {