Add some documentation
This commit is contained in:
parent
0e3aeb782d
commit
9b6e8d1f41
42
src/atlas.rs
42
src/atlas.rs
|
@ -8,6 +8,10 @@
|
||||||
// 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.
|
||||||
|
|
||||||
|
//! Atlases, which hold rendered glyphs on the GPU.
|
||||||
|
//!
|
||||||
|
//! TODO(pcwalton): Make the atlas own the outline builder.
|
||||||
|
|
||||||
use error::GlError;
|
use error::GlError;
|
||||||
use euclid::{Point2D, Rect, Size2D};
|
use euclid::{Point2D, Rect, Size2D};
|
||||||
use gl::types::{GLenum, GLsizei, GLsizeiptr, GLuint, GLvoid};
|
use gl::types::{GLenum, GLsizei, GLsizeiptr, GLuint, GLvoid};
|
||||||
|
@ -18,14 +22,32 @@ use std::mem;
|
||||||
use std::os::raw::c_void;
|
use std::os::raw::c_void;
|
||||||
use std::u16;
|
use std::u16;
|
||||||
|
|
||||||
|
/// Places glyphs in an atlas.
|
||||||
|
///
|
||||||
|
/// Atlases are composed of vertically-stacked "shelves" of uniform height. No glyphs may cross
|
||||||
|
/// shelves. Therefore, the shelf height must be tall enough to encompass all of the glyphs you
|
||||||
|
/// wish to render into the atlas.
|
||||||
|
///
|
||||||
|
/// Typically, when using Pathfinder, you first create an atlas builder, place all the glyphs into
|
||||||
|
/// it, generate the atlas, and then pass that glyph to a rasterizer for rendering on the GPU.
|
||||||
|
/// Afterward, you can retrieve the positions of each glyph in the atlas for final composition to
|
||||||
|
/// the screen.
|
||||||
pub struct AtlasBuilder {
|
pub struct AtlasBuilder {
|
||||||
pub rect_packer: RectPacker,
|
rect_packer: RectPacker,
|
||||||
image_descriptors: Vec<ImageDescriptor>,
|
image_descriptors: Vec<ImageDescriptor>,
|
||||||
image_metadata: Vec<ImageMetadata>,
|
image_metadata: Vec<ImageMetadata>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AtlasBuilder {
|
impl AtlasBuilder {
|
||||||
/// FIXME(pcwalton): Including the shelf height here may be a bad API.
|
/// Constructs a new atlas builder with the given width in pixels and shelf height.
|
||||||
|
///
|
||||||
|
/// The width can be any value at least as large as all glyphs in the font. It is recommended
|
||||||
|
/// to keep it fairly large in order to make efficient use of the space: 1024 or 2048 is a good
|
||||||
|
/// choice on modern GPUs.
|
||||||
|
///
|
||||||
|
/// The shelf height should be the maximum of all minimum shelf heights for all fonts you wish
|
||||||
|
/// to render into the atlas. You can retrive the minimum shelf height for a font with the
|
||||||
|
/// `Font::shelf_height()` method.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new(available_width: u32, shelf_height: u32) -> AtlasBuilder {
|
pub fn new(available_width: u32, shelf_height: u32) -> AtlasBuilder {
|
||||||
AtlasBuilder {
|
AtlasBuilder {
|
||||||
|
@ -35,9 +57,17 @@ impl AtlasBuilder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns an error if there is no space left for the glyph in the atlas.
|
/// Places a glyph rendered in the outline builder into the atlas.
|
||||||
///
|
///
|
||||||
/// FIXME(pcwalton): Support the same glyph drawn at multiple point sizes.
|
/// The outline builder must contain the outlines for the glyph at the given index. Note that
|
||||||
|
/// this is a glyph *index* in the outline builder, not a glyph *ID*. Glyph indices are
|
||||||
|
/// assigned sequentially starting from 0 each time you call `OutlineBuilder::add_glyph()`.
|
||||||
|
///
|
||||||
|
/// You may not use multiple outline builders in the same
|
||||||
|
///
|
||||||
|
/// Returns an error if there is no space left for the glyph.
|
||||||
|
///
|
||||||
|
/// TODO(pcwalton): Support the same glyph drawn at multiple point sizes.
|
||||||
pub fn pack_glyph(&mut self,
|
pub fn pack_glyph(&mut self,
|
||||||
outline_builder: &OutlineBuilder,
|
outline_builder: &OutlineBuilder,
|
||||||
glyph_index: u32,
|
glyph_index: u32,
|
||||||
|
@ -74,6 +104,10 @@ impl AtlasBuilder {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates an atlas by uploading the atlas info to the GPU.
|
||||||
|
///
|
||||||
|
/// The supplied outline builder must be the same as the outline builder passed to
|
||||||
|
/// `Atlas::pack_glyph()`.
|
||||||
pub fn create_atlas(&mut self, outline_builder: &OutlineBuilder) -> Result<Atlas, GlError> {
|
pub fn create_atlas(&mut self, outline_builder: &OutlineBuilder) -> Result<Atlas, GlError> {
|
||||||
self.image_metadata.sort_by(|a, b| a.glyph_index.cmp(&b.glyph_index));
|
self.image_metadata.sort_by(|a, b| a.glyph_index.cmp(&b.glyph_index));
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,8 @@
|
||||||
// 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.
|
||||||
|
|
||||||
|
//! OpenType fonts.
|
||||||
|
|
||||||
use byteorder::{BigEndian, ReadBytesExt};
|
use byteorder::{BigEndian, ReadBytesExt};
|
||||||
use charmap::CodepointRange;
|
use charmap::CodepointRange;
|
||||||
use glyph_range::GlyphRanges;
|
use glyph_range::GlyphRanges;
|
||||||
|
@ -72,6 +74,10 @@ static SFNT_VERSIONS: [u32; 2] = [
|
||||||
((b't' as u32) << 24) | ((b'r' as u32) << 16) | ((b'u' as u32) << 8) | (b'e' as u32),
|
((b't' as u32) << 24) | ((b'r' as u32) << 16) | ((b'u' as u32) << 8) | (b'e' as u32),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/// A handle to a font backed by a byte buffer containing the contents of the file (`.ttf`,
|
||||||
|
/// `.otf`), etc.
|
||||||
|
///
|
||||||
|
/// For optimum performance, consider using the `memmap` crate to provide the byte buffer.
|
||||||
pub struct Font<'a> {
|
pub struct Font<'a> {
|
||||||
pub bytes: &'a [u8],
|
pub bytes: &'a [u8],
|
||||||
|
|
||||||
|
@ -84,12 +90,17 @@ pub struct Font<'a> {
|
||||||
loca: Option<LocaTable<'a>>,
|
loca: Option<LocaTable<'a>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub struct FontTable<'a> {
|
pub struct FontTable<'a> {
|
||||||
pub bytes: &'a [u8],
|
pub bytes: &'a [u8],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Font<'a> {
|
impl<'a> Font<'a> {
|
||||||
|
/// Creates a new font from a byte buffer containing the contents of a file (`.ttf`, `.otf`,
|
||||||
|
/// etc.)
|
||||||
|
///
|
||||||
|
/// Returns the font on success or an error on failure.
|
||||||
pub fn new<'b>(bytes: &'b [u8]) -> Result<Font<'b>, Error> {
|
pub fn new<'b>(bytes: &'b [u8]) -> Result<Font<'b>, Error> {
|
||||||
// Check magic number.
|
// Check magic number.
|
||||||
let mut reader = bytes;
|
let mut reader = bytes;
|
||||||
|
@ -123,7 +134,7 @@ impl<'a> Font<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_otf<'b>(bytes: &'b [u8], offset: u32) -> Result<Font<'b>, Error> {
|
fn from_otf<'b>(bytes: &'b [u8], offset: u32) -> Result<Font<'b>, Error> {
|
||||||
let mut reader = bytes;
|
let mut reader = bytes;
|
||||||
try!(reader.jump(offset as usize).map_err(Error::eof));
|
try!(reader.jump(offset as usize).map_err(Error::eof));
|
||||||
|
|
||||||
|
@ -192,7 +203,7 @@ impl<'a> Font<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// https://github.com/kreativekorp/ksfl/wiki/Macintosh-Resource-File-Format
|
/// https://github.com/kreativekorp/ksfl/wiki/Macintosh-Resource-File-Format
|
||||||
pub fn from_dfont<'b>(bytes: &'b [u8]) -> Result<Font<'b>, Error> {
|
fn from_dfont<'b>(bytes: &'b [u8]) -> Result<Font<'b>, Error> {
|
||||||
let mut reader = bytes;
|
let mut reader = bytes;
|
||||||
|
|
||||||
// Read the Mac resource file header.
|
// Read the Mac resource file header.
|
||||||
|
@ -258,12 +269,18 @@ impl<'a> Font<'a> {
|
||||||
Font::from_otf(&reader[0..sfnt_size as usize], 0)
|
Font::from_otf(&reader[0..sfnt_size as usize], 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the glyph IDs that map to the given ranges of Unicode codepoints.
|
||||||
|
///
|
||||||
|
/// The returned glyph ranges are in the same order as the codepoints.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn glyph_ranges_for_codepoint_ranges(&self, codepoint_ranges: &[CodepointRange])
|
pub fn glyph_ranges_for_codepoint_ranges(&self, codepoint_ranges: &[CodepointRange])
|
||||||
-> Result<GlyphRanges, Error> {
|
-> Result<GlyphRanges, Error> {
|
||||||
self.cmap.glyph_ranges_for_codepoint_ranges(codepoint_ranges)
|
self.cmap.glyph_ranges_for_codepoint_ranges(codepoint_ranges)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Calls the given callback for each point in the supplied glyph's contour.
|
||||||
|
///
|
||||||
|
/// This function is the primary method for accessing a glyph's outline.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn for_each_point<F>(&self, glyph_id: u16, callback: F) -> Result<(), Error>
|
pub fn for_each_point<F>(&self, glyph_id: u16, callback: F) -> Result<(), Error>
|
||||||
where F: FnMut(&Point) {
|
where F: FnMut(&Point) {
|
||||||
|
@ -280,6 +297,7 @@ impl<'a> Font<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the boundaries of the given glyph in font units.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn glyph_bounds(&self, glyph_id: u16) -> Result<GlyphBoundsI, Error> {
|
pub fn glyph_bounds(&self, glyph_id: u16) -> Result<GlyphBoundsI, Error> {
|
||||||
match self.glyf {
|
match self.glyf {
|
||||||
|
@ -295,6 +313,7 @@ impl<'a> Font<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the minimum shelf height that an atlas containing glyphs from this font will need.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn shelf_height(&self, point_size: f32) -> u32 {
|
pub fn shelf_height(&self, point_size: f32) -> u32 {
|
||||||
// Add 2 to account for the border.
|
// Add 2 to account for the border.
|
||||||
|
@ -306,11 +325,20 @@ impl<'a> Font<'a> {
|
||||||
.height as u32 + 2
|
.height as u32 + 2
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the number of font units per em.
|
||||||
|
///
|
||||||
|
/// An em is traditionally the width of the lowercase letter "m". A typical point size of a
|
||||||
|
/// font is expressed in number of pixels per em. Thus, in order to convert font units to
|
||||||
|
/// pixels, you can use an expression like `units * font_size / font.units_per_em()`.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn units_per_em(&self) -> u16 {
|
pub fn units_per_em(&self) -> u16 {
|
||||||
self.head.units_per_em
|
self.head.units_per_em
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the horizontal metrics for the glyph with the given ID.
|
||||||
|
///
|
||||||
|
/// Horizontal metrics are important for text shaping, as they specify the number of units to
|
||||||
|
/// advance the pen after typesetting a glyph.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn metrics_for_glyph(&self, glyph_id: u16) -> Result<HorizontalMetrics, Error> {
|
pub fn metrics_for_glyph(&self, glyph_id: u16) -> Result<HorizontalMetrics, Error> {
|
||||||
self.hmtx.metrics_for_glyph(&self.hhea, glyph_id)
|
self.hmtx.metrics_for_glyph(&self.hhea, glyph_id)
|
||||||
|
@ -351,6 +379,7 @@ pub enum Error {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Error {
|
impl Error {
|
||||||
|
#[doc(hidden)]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn eof<T>(_: T) -> Error {
|
pub fn eof<T>(_: T) -> Error {
|
||||||
Error::UnexpectedEof
|
Error::UnexpectedEof
|
||||||
|
|
|
@ -38,7 +38,9 @@ impl OutlineBuilder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_glyph(&mut self, font: &Font, glyph_id: u16) -> Result<(), otf::Error> {
|
/// Adds a new glyph to the outline builder. Returns the glyph index, useful for 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;
|
let glyph_index = self.descriptors.len() as u16;
|
||||||
|
|
||||||
let mut point_index = self.vertices.len() as u32;
|
let mut point_index = self.vertices.len() as u32;
|
||||||
|
@ -75,7 +77,7 @@ impl OutlineBuilder {
|
||||||
glyph_id: glyph_id,
|
glyph_id: glyph_id,
|
||||||
});
|
});
|
||||||
|
|
||||||
Ok(())
|
Ok(glyph_index)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the glyph rectangle in units.
|
/// Returns the glyph rectangle in units.
|
||||||
|
|
|
@ -18,6 +18,12 @@ use glyph_range::GlyphRanges;
|
||||||
use otf::Font;
|
use otf::Font;
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
|
|
||||||
|
/// Shapes the given Unicode text in the given font, returning the proper position for each glyph.
|
||||||
|
///
|
||||||
|
/// See the description of this module for caveats.
|
||||||
|
///
|
||||||
|
/// For proper operation, the given `glyph_ranges` 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_ranges: &GlyphRanges, string: &str) -> Vec<GlyphPos> {
|
||||||
string.chars().map(|ch| {
|
string.chars().map(|ch| {
|
||||||
let glyph_id = glyph_ranges.glyph_for(ch as u32).unwrap_or(0);
|
let glyph_id = glyph_ranges.glyph_for(ch as u32).unwrap_or(0);
|
||||||
|
@ -35,9 +41,12 @@ pub fn shape_text(font: &Font, glyph_ranges: &GlyphRanges, string: &str) -> Vec<
|
||||||
}).collect()
|
}).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The position of a glyph after shaping.
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub struct GlyphPos {
|
pub struct GlyphPos {
|
||||||
|
/// The glyph ID to emit.
|
||||||
pub glyph_id: u16,
|
pub glyph_id: u16,
|
||||||
|
/// The amount to move the cursor forward *after* emitting this glyph.
|
||||||
pub advance: u16,
|
pub advance: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue