diff --git a/examples/text/Cargo.toml b/examples/text/Cargo.toml index aa9879d4..fa923d1a 100644 --- a/examples/text/Cargo.toml +++ b/examples/text/Cargo.toml @@ -10,6 +10,7 @@ ab_glyph = { version = "0.2", optional = true } orbclient = "0.3" rusttype = { version = "0.9", optional = true } rustybuzz = "0.5" +swash = { version = "0.1", optional = true } unicode-bidi = "0.3" unicode-linebreak = "0.1" unicode-script = "0.5" diff --git a/examples/text/src/font/layout.rs b/examples/text/src/font/layout.rs index c7661540..7f3101ce 100644 --- a/examples/text/src/font/layout.rs +++ b/examples/text/src/font/layout.rs @@ -11,6 +11,8 @@ pub struct FontLayoutGlyph<'a, T: 'a> { pub inner: Option, #[cfg(feature = "rusttype")] pub inner: rusttype::PositionedGlyph<'a>, + #[cfg(feature = "swash")] + pub inner: Option, pub phantom: PhantomData<&'a T>, } @@ -20,7 +22,7 @@ pub struct FontLayoutLine<'a> { } impl<'a> FontLayoutLine<'a> { - pub fn draw(&self, mut f: F) { + pub fn draw(&self, mut f: F) { for glyph in self.glyphs.iter() { #[cfg(feature = "ab_glyph")] if let Some(ref outline) = glyph.inner { @@ -28,7 +30,7 @@ impl<'a> FontLayoutLine<'a> { let x = bb.min.x as i32; let y = bb.min.y as i32; outline.draw(|off_x, off_y, v| { - f(x + off_x as i32, y + off_y as i32, v); + f(x + off_x as i32, y + off_y as i32, (v * 255.0) as u8); }); } @@ -37,9 +39,25 @@ impl<'a> FontLayoutLine<'a> { let x = bb.min.x; let y = bb.min.y; glyph.inner.draw(|off_x, off_y, v| { - f(x + off_x as i32, y + off_y as i32, v); + f(x + off_x as i32, y + off_y as i32, (v * 255.0) as u8); }); } + + #[cfg(feature = "swash")] + if let Some(ref image) = glyph.inner { + assert_eq!(image.content, swash::scale::image::Content::Mask); + + let x = glyph.x as i32 + image.placement.left; + let y = -image.placement.top; + + let mut i = 0; + for off_y in 0..image.placement.height as i32 { + for off_x in 0..image.placement.width as i32 { + f(x + off_x, y + off_y, image.data[i]); + i += 1; + } + } + } } } } diff --git a/examples/text/src/font/matches.rs b/examples/text/src/font/matches.rs index 80495d55..f6ba9590 100644 --- a/examples/text/src/font/matches.rs +++ b/examples/text/src/font/matches.rs @@ -40,6 +40,9 @@ impl<'a> FontMatches<'a> { #[cfg(feature = "rusttype")] let inner = font.rusttype.glyph(rusttype::GlyphId(info.glyph_id as u16)); + #[cfg(feature = "swash")] + let inner = info.glyph_id as swash::GlyphId; + glyphs.push(FontShapeGlyph { start: start_word + info.cluster as usize, end: end_word, // Set later @@ -49,6 +52,8 @@ impl<'a> FontMatches<'a> { y_offset, #[cfg(feature = "ab_glyph")] font: &font.ab_glyph, + #[cfg(feature = "swash")] + font: &font.swash, inner, }); } diff --git a/examples/text/src/font/mod.rs b/examples/text/src/font/mod.rs index eeafb27f..61bf8468 100644 --- a/examples/text/src/font/mod.rs +++ b/examples/text/src/font/mod.rs @@ -30,6 +30,8 @@ pub struct Font<'a> { pub ab_glyph: ab_glyph::FontRef<'a>, #[cfg(feature = "rusttype")] pub rusttype: rusttype::Font<'a>, + #[cfg(feature = "swash")] + pub swash: swash::FontRef<'a>, } impl<'a> Font<'a> { @@ -41,6 +43,8 @@ impl<'a> Font<'a> { ab_glyph: ab_glyph::FontRef::try_from_slice_and_index(data, index).ok()?, #[cfg(feature = "rusttype")] rusttype: rusttype::Font::try_from_bytes_and_index(data, index)?, + #[cfg(feature = "swash")] + swash: swash::FontRef::from_index(data, index as usize)?, }) } } diff --git a/examples/text/src/font/shape.rs b/examples/text/src/font/shape.rs index f4efb547..70eb3dd7 100644 --- a/examples/text/src/font/shape.rs +++ b/examples/text/src/font/shape.rs @@ -17,6 +17,83 @@ pub struct FontShapeGlyph<'a> { pub inner: ab_glyph::GlyphId, #[cfg(feature = "rusttype")] pub inner: rusttype::Glyph<'a>, + #[cfg(feature = "swash")] + pub font: &'a swash::FontRef<'a>, + #[cfg(feature = "swash")] + pub inner: swash::GlyphId, +} + +impl<'a> FontShapeGlyph<'a> { + fn layout(&self, font_size: i32, x: f32, y: f32) -> FontLayoutGlyph<'a, ()> { + let x_offset = font_size as f32 * self.x_offset; + let y_offset = font_size as f32 * self.y_offset; + let x_advance = font_size as f32 * self.x_advance; + + #[cfg(feature = "ab_glyph")] + let inner = self.font.outline_glyph( + self.inner.with_scale_and_position( + font_size as f32, + ab_glyph::point( + x + x_offset, + y + y_offset, + ) + ) + ); + + #[cfg(feature = "rusttype")] + let inner = self.inner.clone() + .scaled(rusttype::Scale::uniform(font_size as f32)) + .positioned(rusttype::point( + x + x_offset, + y + y_offset, + )); + + #[cfg(feature = "swash")] + let inner = { + use swash::scale::{Render, ScaleContext, Source, StrikeWith}; + use swash::zeno::{Format, Vector}; + + //TODO: store somewhere else + static mut CONTEXT: Option = None; + + unsafe { + if CONTEXT.is_none() { + CONTEXT = Some(ScaleContext::new()); + } + } + + // Build the scaler + let mut scaler = unsafe { CONTEXT.as_mut().unwrap() } + .builder(*self.font) + .size(font_size as f32) + .hint(true) + .build(); + + // Compute the fractional offset-- you'll likely want to quantize this + // in a real renderer + let offset = Vector::new(x_offset, y_offset); + + // Select our source order + Render::new(&[ + Source::Outline, + ]) + // Select a subpixel format + .format(Format::Alpha) + // Apply the fractional offset + .offset(offset) + // Render the image + .render(&mut scaler, self.inner) + }; + + FontLayoutGlyph { + start: self.start, + end: self.end, + x: x, + w: x_advance, + inner, + phantom: PhantomData, + } + } } pub struct FontShapeWord<'a> { @@ -66,36 +143,8 @@ impl<'a> FontShapeLine<'a> { for glyph in word.glyphs.iter() { let x_advance = font_size as f32 * glyph.x_advance; let y_advance = font_size as f32 * glyph.y_advance; - let x_offset = font_size as f32 * glyph.x_offset; - let y_offset = font_size as f32 * glyph.y_offset; - #[cfg(feature = "ab_glyph")] - let inner = glyph.font.outline_glyph( - glyph.inner.with_scale_and_position( - font_size as f32, - ab_glyph::point( - x + x_offset, - y + y_offset, - ) - ) - ); - - #[cfg(feature = "rusttype")] - let inner = glyph.inner.clone() - .scaled(rusttype::Scale::uniform(font_size as f32)) - .positioned(rusttype::point( - x + x_offset, - y + y_offset, - )); - - glyphs.push(FontLayoutGlyph { - start: glyph.start, - end: glyph.end, - x, - w: x_advance, - inner, - phantom: PhantomData, - }); + glyphs.push(glyph.layout(font_size, x, y)); push_line = true; x += x_advance; @@ -142,38 +191,10 @@ impl<'a> FontShapeLine<'a> { for glyph in word.glyphs.iter().rev() { let x_advance = font_size as f32 * glyph.x_advance; let y_advance = font_size as f32 * glyph.y_advance; - let x_offset = font_size as f32 * glyph.x_offset; - let y_offset = font_size as f32 * glyph.y_offset; x -= x_advance; - #[cfg(feature = "ab_glyph")] - let inner = glyph.font.outline_glyph( - glyph.inner.with_scale_and_position( - font_size as f32, - ab_glyph::point( - x + x_offset, - y + y_offset, - ) - ) - ); - - #[cfg(feature = "rusttype")] - let inner = glyph.inner.clone() - .scaled(rusttype::Scale::uniform(font_size as f32)) - .positioned(rusttype::point( - x + x_offset, - y + y_offset, - )); - - glyphs.push(FontLayoutGlyph { - start: glyph.start, - end: glyph.end, - x, - w: x_advance, - inner, - phantom: PhantomData, - }); + glyphs.push(glyph.layout(font_size, x, y)); push_line = true; y += y_advance; diff --git a/examples/text/src/font/system.rs b/examples/text/src/font/system.rs index 5edebc88..19578183 100644 --- a/examples/text/src/font/system.rs +++ b/examples/text/src/font/system.rs @@ -53,7 +53,9 @@ impl<'a> FontSystem<'a> { } } if ! fonts.is_empty() { - Some(FontMatches { fonts }) + Some(FontMatches { + fonts + }) } else { None } diff --git a/examples/text/src/main.rs b/examples/text/src/main.rs index d7052610..eeea267c 100644 --- a/examples/text/src/main.rs +++ b/examples/text/src/main.rs @@ -202,10 +202,9 @@ fn main() { } } - line.draw(|x, y, v| { - let c = (v * 255.0) as u32; - window.pixel(line_x + x, line_y + y, Color{ - data: c << 24 | (font_color.data & 0x00FF_FFFF) + line.draw(|x, y, alpha| { + window.pixel(line_x + x, line_y + y, Color { + data: (alpha as u32) << 24 | (font_color.data & 0x00FF_FFFF) }); });