1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
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;
fn swash_image(context: &mut ScaleContext, matches: &FontMatches, cache_key: CacheKey) -> Option<SwashImage> {
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;
},
};
let mut scaler = context
.builder(font.as_swash())
.size(cache_key.font_size as f32)
.hint(true)
.build();
let offset =
Vector::new(cache_key.x_bin.as_float(), cache_key.y_bin.as_float());
Render::new(&[
Source::ColorOutline(0),
Source::ColorBitmap(StrikeWith::BestFit),
Source::Outline,
])
.format(Format::Alpha)
.offset(offset)
.render(&mut scaler, cache_key.glyph_id)
}
pub struct SwashCache {
context: ScaleContext,
pub image_cache: HashMap<CacheKey, Option<SwashImage>>,
}
impl SwashCache {
pub fn new() -> Self {
Self {
context: ScaleContext::new(),
image_cache: HashMap::new()
}
}
pub fn get_image_uncached(&mut self, matches: &FontMatches, cache_key: CacheKey) -> Option<SwashImage> {
swash_image(&mut self.context, matches, cache_key)
}
pub fn get_image(&mut self, matches: &FontMatches, cache_key: CacheKey) -> &Option<SwashImage> {
self.image_cache.entry(cache_key).or_insert_with(|| {
swash_image(&mut self.context, matches, cache_key)
})
}
pub fn with_pixels<F: FnMut(i32, i32, u32)>(
&mut self,
matches: &FontMatches<'_>,
cache_key: CacheKey,
base: u32,
mut f: F
) {
if let Some(image) = self.get_image(matches, cache_key) {
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 {
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::SubpixelMask => {
log::warn!("TODO: SubpixelMask");
}
}
}
}
}