diff --git a/src/atlas.rs b/src/atlas.rs index dbfeb619..a4c16be8 100644 --- a/src/atlas.rs +++ b/src/atlas.rs @@ -8,6 +8,10 @@ // option. This file may not be copied, modified, or distributed // 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 euclid::{Point2D, Rect, Size2D}; use gl::types::{GLenum, GLsizei, GLsizeiptr, GLuint, GLvoid}; @@ -18,14 +22,32 @@ use std::mem; use std::os::raw::c_void; 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 rect_packer: RectPacker, + rect_packer: RectPacker, image_descriptors: Vec, image_metadata: Vec, } 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] pub fn new(available_width: u32, shelf_height: u32) -> 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, outline_builder: &OutlineBuilder, glyph_index: u32, @@ -74,6 +104,10 @@ impl AtlasBuilder { 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 { self.image_metadata.sort_by(|a, b| a.glyph_index.cmp(&b.glyph_index)); diff --git a/src/otf/mod.rs b/src/otf/mod.rs index b2828159..053ce5b8 100644 --- a/src/otf/mod.rs +++ b/src/otf/mod.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +//! OpenType fonts. + use byteorder::{BigEndian, ReadBytesExt}; use charmap::CodepointRange; 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), ]; +/// 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 bytes: &'a [u8], @@ -84,12 +90,17 @@ pub struct Font<'a> { loca: Option>, } +#[doc(hidden)] #[derive(Clone, Copy, Debug)] pub struct FontTable<'a> { pub bytes: &'a [u8], } 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, Error> { // Check magic number. let mut reader = bytes; @@ -123,7 +134,7 @@ impl<'a> Font<'a> { } } - pub fn from_otf<'b>(bytes: &'b [u8], offset: u32) -> Result, Error> { + fn from_otf<'b>(bytes: &'b [u8], offset: u32) -> Result, Error> { let mut reader = bytes; 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 - pub fn from_dfont<'b>(bytes: &'b [u8]) -> Result, Error> { + fn from_dfont<'b>(bytes: &'b [u8]) -> Result, Error> { let mut reader = bytes; // Read the Mac resource file header. @@ -258,12 +269,18 @@ impl<'a> Font<'a> { 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] pub fn glyph_ranges_for_codepoint_ranges(&self, codepoint_ranges: &[CodepointRange]) -> Result { 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] pub fn for_each_point(&self, glyph_id: u16, callback: F) -> Result<(), Error> where F: FnMut(&Point) { @@ -280,6 +297,7 @@ impl<'a> Font<'a> { } } + /// Returns the boundaries of the given glyph in font units. #[inline] pub fn glyph_bounds(&self, glyph_id: u16) -> Result { 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] pub fn shelf_height(&self, point_size: f32) -> u32 { // Add 2 to account for the border. @@ -306,11 +325,20 @@ impl<'a> Font<'a> { .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] pub fn units_per_em(&self) -> u16 { 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] pub fn metrics_for_glyph(&self, glyph_id: u16) -> Result { self.hmtx.metrics_for_glyph(&self.hhea, glyph_id) @@ -351,6 +379,7 @@ pub enum Error { } impl Error { + #[doc(hidden)] #[inline] pub fn eof(_: T) -> Error { Error::UnexpectedEof diff --git a/src/outline.rs b/src/outline.rs index 5c3458b7..37eb4dea 100644 --- a/src/outline.rs +++ b/src/outline.rs @@ -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 { let glyph_index = self.descriptors.len() as u16; let mut point_index = self.vertices.len() as u32; @@ -75,7 +77,7 @@ impl OutlineBuilder { glyph_id: glyph_id, }); - Ok(()) + Ok(glyph_index) } /// Returns the glyph rectangle in units. diff --git a/src/shaper.rs b/src/shaper.rs index 5dad2cb2..1f37a271 100644 --- a/src/shaper.rs +++ b/src/shaper.rs @@ -18,6 +18,12 @@ use glyph_range::GlyphRanges; use otf::Font; 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 { string.chars().map(|ch| { 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() } +/// The position of a glyph after shaping. #[derive(Clone, Copy, Debug)] pub struct GlyphPos { + /// The glyph ID to emit. pub glyph_id: u16, + /// The amount to move the cursor forward *after* emitting this glyph. pub advance: u16, }