Add support for swash
This commit is contained in:
parent
51639e53cb
commit
cf43655357
7 changed files with 116 additions and 66 deletions
|
|
@ -10,6 +10,7 @@ ab_glyph = { version = "0.2", optional = true }
|
||||||
orbclient = "0.3"
|
orbclient = "0.3"
|
||||||
rusttype = { version = "0.9", optional = true }
|
rusttype = { version = "0.9", optional = true }
|
||||||
rustybuzz = "0.5"
|
rustybuzz = "0.5"
|
||||||
|
swash = { version = "0.1", optional = true }
|
||||||
unicode-bidi = "0.3"
|
unicode-bidi = "0.3"
|
||||||
unicode-linebreak = "0.1"
|
unicode-linebreak = "0.1"
|
||||||
unicode-script = "0.5"
|
unicode-script = "0.5"
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,8 @@ pub struct FontLayoutGlyph<'a, T: 'a> {
|
||||||
pub inner: Option<ab_glyph::OutlinedGlyph>,
|
pub inner: Option<ab_glyph::OutlinedGlyph>,
|
||||||
#[cfg(feature = "rusttype")]
|
#[cfg(feature = "rusttype")]
|
||||||
pub inner: rusttype::PositionedGlyph<'a>,
|
pub inner: rusttype::PositionedGlyph<'a>,
|
||||||
|
#[cfg(feature = "swash")]
|
||||||
|
pub inner: Option<swash::scale::image::Image>,
|
||||||
pub phantom: PhantomData<&'a T>,
|
pub phantom: PhantomData<&'a T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -20,7 +22,7 @@ pub struct FontLayoutLine<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> FontLayoutLine<'a> {
|
impl<'a> FontLayoutLine<'a> {
|
||||||
pub fn draw<F: FnMut(i32, i32, f32)>(&self, mut f: F) {
|
pub fn draw<F: FnMut(i32, i32, u8)>(&self, mut f: F) {
|
||||||
for glyph in self.glyphs.iter() {
|
for glyph in self.glyphs.iter() {
|
||||||
#[cfg(feature = "ab_glyph")]
|
#[cfg(feature = "ab_glyph")]
|
||||||
if let Some(ref outline) = glyph.inner {
|
if let Some(ref outline) = glyph.inner {
|
||||||
|
|
@ -28,7 +30,7 @@ impl<'a> FontLayoutLine<'a> {
|
||||||
let x = bb.min.x as i32;
|
let x = bb.min.x as i32;
|
||||||
let y = bb.min.y as i32;
|
let y = bb.min.y as i32;
|
||||||
outline.draw(|off_x, off_y, v| {
|
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 x = bb.min.x;
|
||||||
let y = bb.min.y;
|
let y = bb.min.y;
|
||||||
glyph.inner.draw(|off_x, off_y, v| {
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,9 @@ impl<'a> FontMatches<'a> {
|
||||||
#[cfg(feature = "rusttype")]
|
#[cfg(feature = "rusttype")]
|
||||||
let inner = font.rusttype.glyph(rusttype::GlyphId(info.glyph_id as u16));
|
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 {
|
glyphs.push(FontShapeGlyph {
|
||||||
start: start_word + info.cluster as usize,
|
start: start_word + info.cluster as usize,
|
||||||
end: end_word, // Set later
|
end: end_word, // Set later
|
||||||
|
|
@ -49,6 +52,8 @@ impl<'a> FontMatches<'a> {
|
||||||
y_offset,
|
y_offset,
|
||||||
#[cfg(feature = "ab_glyph")]
|
#[cfg(feature = "ab_glyph")]
|
||||||
font: &font.ab_glyph,
|
font: &font.ab_glyph,
|
||||||
|
#[cfg(feature = "swash")]
|
||||||
|
font: &font.swash,
|
||||||
inner,
|
inner,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,8 @@ pub struct Font<'a> {
|
||||||
pub ab_glyph: ab_glyph::FontRef<'a>,
|
pub ab_glyph: ab_glyph::FontRef<'a>,
|
||||||
#[cfg(feature = "rusttype")]
|
#[cfg(feature = "rusttype")]
|
||||||
pub rusttype: rusttype::Font<'a>,
|
pub rusttype: rusttype::Font<'a>,
|
||||||
|
#[cfg(feature = "swash")]
|
||||||
|
pub swash: swash::FontRef<'a>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Font<'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()?,
|
ab_glyph: ab_glyph::FontRef::try_from_slice_and_index(data, index).ok()?,
|
||||||
#[cfg(feature = "rusttype")]
|
#[cfg(feature = "rusttype")]
|
||||||
rusttype: rusttype::Font::try_from_bytes_and_index(data, index)?,
|
rusttype: rusttype::Font::try_from_bytes_and_index(data, index)?,
|
||||||
|
#[cfg(feature = "swash")]
|
||||||
|
swash: swash::FontRef::from_index(data, index as usize)?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,83 @@ pub struct FontShapeGlyph<'a> {
|
||||||
pub inner: ab_glyph::GlyphId,
|
pub inner: ab_glyph::GlyphId,
|
||||||
#[cfg(feature = "rusttype")]
|
#[cfg(feature = "rusttype")]
|
||||||
pub inner: rusttype::Glyph<'a>,
|
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<ScaleContext> = 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> {
|
pub struct FontShapeWord<'a> {
|
||||||
|
|
@ -66,36 +143,8 @@ impl<'a> FontShapeLine<'a> {
|
||||||
for glyph in word.glyphs.iter() {
|
for glyph in word.glyphs.iter() {
|
||||||
let x_advance = font_size as f32 * glyph.x_advance;
|
let x_advance = font_size as f32 * glyph.x_advance;
|
||||||
let y_advance = font_size as f32 * glyph.y_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")]
|
glyphs.push(glyph.layout(font_size, x, y));
|
||||||
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,
|
|
||||||
});
|
|
||||||
push_line = true;
|
push_line = true;
|
||||||
|
|
||||||
x += x_advance;
|
x += x_advance;
|
||||||
|
|
@ -142,38 +191,10 @@ impl<'a> FontShapeLine<'a> {
|
||||||
for glyph in word.glyphs.iter().rev() {
|
for glyph in word.glyphs.iter().rev() {
|
||||||
let x_advance = font_size as f32 * glyph.x_advance;
|
let x_advance = font_size as f32 * glyph.x_advance;
|
||||||
let y_advance = font_size as f32 * glyph.y_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;
|
x -= x_advance;
|
||||||
|
|
||||||
#[cfg(feature = "ab_glyph")]
|
glyphs.push(glyph.layout(font_size, x, y));
|
||||||
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,
|
|
||||||
});
|
|
||||||
push_line = true;
|
push_line = true;
|
||||||
|
|
||||||
y += y_advance;
|
y += y_advance;
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,9 @@ impl<'a> FontSystem<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ! fonts.is_empty() {
|
if ! fonts.is_empty() {
|
||||||
Some(FontMatches { fonts })
|
Some(FontMatches {
|
||||||
|
fonts
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -202,10 +202,9 @@ fn main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
line.draw(|x, y, v| {
|
line.draw(|x, y, alpha| {
|
||||||
let c = (v * 255.0) as u32;
|
window.pixel(line_x + x, line_y + y, Color {
|
||||||
window.pixel(line_x + x, line_y + y, Color{
|
data: (alpha as u32) << 24 | (font_color.data & 0x00FF_FFFF)
|
||||||
data: c << 24 | (font_color.data & 0x00FF_FFFF)
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue