Make swash optional, add swash cache abstraction
This commit is contained in:
parent
efc5108a2d
commit
1c341f3126
7 changed files with 148 additions and 109 deletions
118
src/swash.rs
Normal file
118
src/swash.rs
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
use std::collections::HashMap;
|
||||
use swash::scale::{ScaleContext, image::Content};
|
||||
use swash::scale::{Render, Source, StrikeWith};
|
||||
use swash::zeno::{Format, Vector};
|
||||
|
||||
use crate::{CacheKey, FontMatches};
|
||||
|
||||
pub use swash::scale::image::Image as SwashImage;
|
||||
|
||||
pub struct SwashCache {
|
||||
context: ScaleContext,
|
||||
cache: HashMap<CacheKey, Option<SwashImage>>,
|
||||
}
|
||||
|
||||
impl SwashCache {
|
||||
/// Create a new swash cache
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
context: ScaleContext::new(),
|
||||
cache: HashMap::new()
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a swash Image from a cache key, caching results
|
||||
pub fn with_image<F: FnMut(&Option<SwashImage>)>(
|
||||
&mut self,
|
||||
matches: &FontMatches<'_>,
|
||||
cache_key: CacheKey,
|
||||
mut f: F
|
||||
) {
|
||||
let image_opt = self.cache.entry(cache_key).or_insert_with(|| {
|
||||
let font = match matches.get_font(&cache_key.font_id) {
|
||||
Some(some) => some,
|
||||
None => {
|
||||
log::warn!("did not find font {:?}", cache_key.font_id);
|
||||
return None;
|
||||
},
|
||||
};
|
||||
|
||||
// Build the scaler
|
||||
let mut scaler = self.context
|
||||
.builder(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)
|
||||
});
|
||||
|
||||
f(image_opt);
|
||||
}
|
||||
|
||||
/// Enumerate pixels in an Image, use `with_image` for better performance
|
||||
pub fn with_pixels<F: FnMut(i32, i32, u32)>(
|
||||
&mut self,
|
||||
matches: &FontMatches<'_>,
|
||||
cache_key: CacheKey,
|
||||
base: u32,
|
||||
mut f: F
|
||||
) {
|
||||
self.with_image(matches, cache_key, |image_opt| {
|
||||
if let Some(image) = image_opt {
|
||||
let x = image.placement.left;
|
||||
let y = -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 {
|
||||
//TODO: blend base alpha?
|
||||
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 {
|
||||
//TODO: blend base alpha?
|
||||
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 => {
|
||||
log::warn!("TODO: SubpixelMask");
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue