Add caching of swash rendering, significantly improves layout speed
This commit is contained in:
parent
0b5050e601
commit
a4959bbe7b
5 changed files with 243 additions and 92 deletions
|
|
@ -1,24 +1,22 @@
|
|||
use core::marker::PhantomData;
|
||||
use super::{CacheKey, Font, FontLineIndex};
|
||||
|
||||
use super::FontLineIndex;
|
||||
|
||||
pub struct FontLayoutGlyph<'a, T: 'a> {
|
||||
pub struct FontLayoutGlyph<'a> {
|
||||
pub start: usize,
|
||||
pub end: usize,
|
||||
pub x: f32,
|
||||
pub w: f32,
|
||||
pub font: &'a Font<'a>,
|
||||
#[cfg(feature = "ab_glyph")]
|
||||
pub inner: Option<ab_glyph::OutlinedGlyph>,
|
||||
#[cfg(feature = "rusttype")]
|
||||
pub inner: rusttype::PositionedGlyph<'a>,
|
||||
#[cfg(feature = "swash")]
|
||||
pub inner: (i32, i32, Option<swash::scale::image::Image>),
|
||||
pub phantom: PhantomData<&'a T>,
|
||||
pub inner: (i32, i32, CacheKey),
|
||||
}
|
||||
|
||||
pub struct FontLayoutLine<'a> {
|
||||
pub line_i: FontLineIndex,
|
||||
pub glyphs: Vec<FontLayoutGlyph<'a, ()>>,
|
||||
pub glyphs: Vec<FontLayoutGlyph<'a>>,
|
||||
}
|
||||
|
||||
impl<'a> FontLayoutLine<'a> {
|
||||
|
|
@ -52,41 +50,81 @@ impl<'a> FontLayoutLine<'a> {
|
|||
}
|
||||
|
||||
#[cfg(feature = "swash")]
|
||||
if let Some(ref image) = glyph.inner.2 {
|
||||
use swash::scale::image::Content;
|
||||
{
|
||||
use swash::scale::{Render, Source, StrikeWith};
|
||||
use swash::zeno::{Format, Vector};
|
||||
|
||||
let x = glyph.inner.0 + image.placement.left;
|
||||
let y = glyph.inner.1 - image.placement.top;
|
||||
let mut cache = glyph.font.cache.lock().unwrap();
|
||||
|
||||
match image.content {
|
||||
Content::Mask => {
|
||||
let mut i = 0;
|
||||
for off_y in 0..image.placement.height as i32 {
|
||||
for off_x in 0..image.placement.width as i32 {
|
||||
let color =
|
||||
(image.data[i] as u32) << 24 |
|
||||
base & 0xFFFFFF;
|
||||
f(x + off_x, y + off_y, color);
|
||||
i += 1;
|
||||
let (x_int, y_int, cache_key) = glyph.inner;
|
||||
|
||||
let image_opt = cache.entry(cache_key).or_insert_with(|| {
|
||||
let mut scale_context = glyph.font.scale_context.lock().unwrap();
|
||||
|
||||
// Build the scaler
|
||||
let mut scaler = scale_context
|
||||
.builder(glyph.font.swash)
|
||||
.size(cache_key.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(cache_key.x_bin.as_float(), cache_key.y_bin.as_float());
|
||||
|
||||
// Select our source order
|
||||
Render::new(&[
|
||||
// Color outline with the first palette
|
||||
Source::ColorOutline(0),
|
||||
// Color bitmap with best fit selection mode
|
||||
Source::ColorBitmap(StrikeWith::BestFit),
|
||||
// Standard scalable outline
|
||||
Source::Outline,
|
||||
])
|
||||
// Select a subpixel format
|
||||
.format(Format::Alpha)
|
||||
// Apply the fractional offset
|
||||
.offset(offset)
|
||||
// Render the image
|
||||
.render(&mut scaler, cache_key.glyph_id)
|
||||
});
|
||||
|
||||
if let Some(ref image) = image_opt {
|
||||
use swash::scale::image::Content;
|
||||
|
||||
let x = x_int + image.placement.left;
|
||||
let y = y_int - image.placement.top;
|
||||
|
||||
match image.content {
|
||||
Content::Mask => {
|
||||
let mut i = 0;
|
||||
for off_y in 0..image.placement.height as i32 {
|
||||
for off_x in 0..image.placement.width as i32 {
|
||||
let color =
|
||||
(image.data[i] as u32) << 24 |
|
||||
base & 0xFFFFFF;
|
||||
f(x + off_x, y + off_y, color);
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
Content::Color => {
|
||||
let mut i = 0;
|
||||
for off_y in 0..image.placement.height as i32 {
|
||||
for off_x in 0..image.placement.width as i32 {
|
||||
let color =
|
||||
(image.data[i + 3] as u32) << 24 |
|
||||
(image.data[i] as u32) << 16 |
|
||||
(image.data[i + 1] as u32) << 8 |
|
||||
(image.data[i + 2] as u32);
|
||||
f(x + off_x, y + off_y, color);
|
||||
i += 4;
|
||||
},
|
||||
Content::Color => {
|
||||
let mut i = 0;
|
||||
for off_y in 0..image.placement.height as i32 {
|
||||
for off_x in 0..image.placement.width as i32 {
|
||||
let color =
|
||||
(image.data[i + 3] as u32) << 24 |
|
||||
(image.data[i] as u32) << 16 |
|
||||
(image.data[i + 1] as u32) << 8 |
|
||||
(image.data[i + 2] as u32);
|
||||
f(x + off_x, y + off_y, color);
|
||||
i += 4;
|
||||
}
|
||||
}
|
||||
},
|
||||
Content::SubpixelMask => {
|
||||
println!("TODO: SubpixelMask");
|
||||
}
|
||||
},
|
||||
Content::SubpixelMask => {
|
||||
println!("TODO: SubpixelMask");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue