diff --git a/Cargo.toml b/Cargo.toml index 19443ab..5a46cc0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,4 +8,7 @@ description = "A font renderer written (mostly) in pure, safe Rust" repository = "https://github.com/google/font-rs" [features] +default = ["std"] + sse = [] +std = [] diff --git a/src/accumulate.rs b/src/accumulate.rs index d41c536..8f85f8a 100644 --- a/src/accumulate.rs +++ b/src/accumulate.rs @@ -12,22 +12,29 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::mem; +#[cfg(not(feature = "std"))] +use alloc::vec::Vec; + +#[cfg(all(feature = "sse", not(feature = "std")))] +use core::arch::x86_64::*; -#[cfg(target_arch = "x86_64")] +#[cfg(all(feature = "sse", feature = "std"))] use std::arch::x86_64::*; -#[cfg(target_arch = "x86")] -use std::arch::x86::*; +#[cfg(all(feature = "sse", not(feature = "std")))] +use core::mem; -macro_rules! _mm_shuffle { - ($z:expr, $y:expr, $x:expr, $w:expr) => { - ($z << 6) | ($y << 4) | ($x << 2) | $w - }; -} +#[cfg(all(feature = "sse", feature = "std"))] +use std::mem; #[cfg(feature = "sse")] pub fn accumulate(src: &[f32]) -> Vec { + macro_rules! _mm_shuffle { + ($z:expr, $y:expr, $x:expr, $w:expr) => { + ($z << 6) | ($y << 4) | ($x << 2) | $w + }; + } + // SIMD instructions force us to align data since we iterate each 4 elements // So: // n (0) => 0 @@ -68,9 +75,9 @@ pub fn accumulate(src: &[f32]) -> Vec { #[cfg(not(feature = "sse"))] pub fn accumulate(src: &[f32]) -> Vec { - let mut acc = 0.0; - src.iter() - .map(|c| { + let mut acc = 0.0f32; + src.into_iter() + .map(|&c| { // This would translate really well to SIMD acc += c; let y = acc.abs(); @@ -88,8 +95,8 @@ mod tests { // accumulate fn fn accumulate_simple_impl(src: &[f32]) -> Vec { let mut acc = 0.0; - src.iter() - .map(|c| { + src.into_iter() + .map(|&c| { acc += c; let y = acc.abs(); let y = if y < 1.0 { y } else { 1.0 }; diff --git a/src/float32.rs b/src/float32.rs new file mode 100644 index 0000000..079bda2 --- /dev/null +++ b/src/float32.rs @@ -0,0 +1,28 @@ + +use core::intrinsics::*; + +/// Abstraction for floating point intrinsics in no_std mode +pub trait Float32 { + fn abs(self) -> f32; + fn floor(self) -> f32; + fn ceil(self) -> f32; + fn sqrt(self) -> f32; +} + +impl Float32 for f32 { + fn abs(self) -> f32 { + unsafe { fabsf32(self) } + } + + fn floor(self) -> f32 { + unsafe { floorf32(self) } + } + + fn ceil(self) -> f32 { + unsafe { ceilf32(self) } + } + + fn sqrt(self) -> f32 { + unsafe { sqrtf32(self) } + } +} diff --git a/src/font.rs b/src/font.rs index 8f741fc..d676e62 100644 --- a/src/font.rs +++ b/src/font.rs @@ -14,15 +14,33 @@ //! A simple renderer for TrueType fonts -use std::collections::HashMap; +#[cfg(not(feature = "std"))] +use alloc::collections::BTreeMap; +#[cfg(not(feature = "std"))] +use alloc::vec::Vec; +#[cfg(not(feature = "std"))] +use alloc::str; +#[cfg(not(feature = "std"))] +use alloc::fmt; +#[cfg(not(feature = "std"))] +use alloc::fmt::{Debug, Display, Formatter}; + +#[cfg(feature = "std")] +use std::collections::BTreeMap; +#[cfg(feature = "std")] +use std::str; +#[cfg(feature = "std")] use std::fmt; +#[cfg(feature = "std")] use std::fmt::{Debug, Display, Formatter}; -use std::result::Result; use geom::{affine_pt, Affine, Point}; use raster::Raster; -#[derive(PartialEq, Eq, Hash)] +#[cfg(not(feature = "std"))] +use float32::Float32; + +#[derive(PartialEq, Eq, PartialOrd, Ord)] struct Tag(u32); impl Tag { @@ -34,13 +52,13 @@ impl Tag { impl Display for Tag { fn fmt(&self, f: &mut Formatter) -> fmt::Result { let &Tag(tag) = self; - let buf = vec![ + let buf = [ ((tag >> 24) & 0xff) as u8, ((tag >> 16) & 0xff) as u8, ((tag >> 8) & 0xff) as u8, (tag & 0xff) as u8, ]; - f.write_str(&String::from_utf8(buf).unwrap()) + f.write_str(str::from_utf8(&buf).unwrap()) } } @@ -672,7 +690,7 @@ impl<'a> CompoundGlyph<'a> { pub struct Font<'a> { _version: u32, - _tables: HashMap, + _tables: BTreeMap, head: Head<'a>, maxp: Maxp<'a>, cmap: Option>, @@ -739,7 +757,7 @@ impl<'a> Font<'a> { } } _ => { - println!("unhandled glyph case"); + unreachable!("unhandled glyph case"); } } } @@ -776,8 +794,7 @@ impl<'a> Font<'a> { }) } _ => { - println!("glyph {} error", glyph_id); - None + unreachable!("glyph {} error", glyph_id); } } } @@ -950,7 +967,7 @@ pub fn parse(data: &[u8]) -> Result { let _search_range = get_u16(data, 6).unwrap(); let _entry_selector = get_u16(data, 8).unwrap(); let _range_shift = get_u16(data, 10).unwrap(); - let mut tables = HashMap::new(); + let mut tables = BTreeMap::new(); for i in 0..num_tables { let header = &data[12 + i * 16..12 + (i + 1) * 16]; let tag = get_u32(header, 0).unwrap(); diff --git a/src/geom.rs b/src/geom.rs index c292cad..ac97ca6 100644 --- a/src/geom.rs +++ b/src/geom.rs @@ -14,6 +14,10 @@ //! Geometry primitive data structures and manipulations +#[cfg(not(feature = "std"))] +use alloc::fmt::{Debug, Formatter, Result}; + +#[cfg(feature = "std")] use std::fmt::{Debug, Formatter, Result}; #[derive(Copy, Clone)] diff --git a/src/lib.rs b/src/lib.rs index b7b189f..ca79947 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,9 +14,19 @@ //! A very high performance font renderer. +#![cfg_attr(not(feature = "std"), no_std)] +#![cfg_attr(not(feature = "std"), feature(alloc, core_intrinsics))] + +#[cfg(not(feature = "std"))] +#[macro_use] +extern crate alloc; + #[macro_use] pub mod macros; pub mod accumulate; pub mod font; pub mod geom; pub mod raster; + +#[cfg(not(feature = "std"))] +mod float32; diff --git a/src/raster.rs b/src/raster.rs index 7caaa9d..10d6e80 100644 --- a/src/raster.rs +++ b/src/raster.rs @@ -14,11 +14,15 @@ //! An antialiased rasterizer for quadratic Beziers -use std::cmp::min; +#[cfg(not(feature = "std"))] +use alloc::vec::Vec; use accumulate::accumulate; use geom::Point; +#[cfg(not(feature = "std"))] +use float32::Float32; + // TODO: sort out crate structure. Right now we want this when compiling raster as a binary, // but need it commented out when compiling showttf //mod geom; @@ -59,7 +63,8 @@ impl Raster { if p0.y < 0.0 { x -= p0.y * dxdy; } - for y in y0..min(self.h, p1.y.ceil() as usize) { + let ymin = self.h.min(p1.y.ceil() as usize); + for y in y0..ymin { let linestart = y * self.w; let dy = ((y + 1) as f32).min(p1.y) - (y as f32).max(p0.y); let xnext = x + dxdy * dy;