use alloc::vec::Vec;
use gfx::{Dc, Surface};
use crate::glyphcache::GcEntry;
use crate::lcd::{self, Lut};
use crate::{bitmap_blit, mask_blit, Text};
const K_MASK: u8 = 0;
const K_BITMAP: u8 = 1;
const K_LCD_RGB: u8 = 2;
const K_LCD_BGR: u8 = 3;
#[derive(Clone, Copy)]
struct Op {
key: u64,
x: i32,
y: i32,
b: [i32; 4],
color: u32,
kind: u8,
adj: u16,
}
#[derive(Default)]
pub struct GlyphRec {
ops: Vec<Op>,
adj: Vec<(u32, [u8; 256])>,
epoch: u32,
ok: bool,
}
impl GlyphRec {
pub fn begin(&mut self, t: &Text) {
self.ops.clear();
self.adj.clear();
self.epoch = t.gc.epoch;
self.ok = true;
}
pub fn len(&self) -> usize {
self.ops.len()
}
pub fn is_empty(&self) -> bool {
self.ops.is_empty()
}
pub fn valid(&self, t: &Text) -> bool {
self.epoch == t.gc.epoch
}
fn push(&mut self, key: u64, e: &GcEntry, x: i32, y: i32, color: u32, kind: u8, adj: u16) {
if e.w <= 0 || e.h <= 0 {
return; }
let (x0, y0) = (x.wrapping_add(e.left), y.wrapping_add(e.top));
let b = [x0, y0, x0.wrapping_add(e.w), y0.wrapping_add(e.h)];
self.ops.push(Op { key, x, y, b, color, kind, adj });
}
pub(crate) fn mask(&mut self, key: u64, e: &GcEntry, x: i32, y: i32, color: u32) {
self.push(key, e, x, y, color, K_MASK, 0);
}
pub(crate) fn bitmap(&mut self, key: u64, e: &GcEntry, x: i32, y: i32, color: u32) {
self.push(key, e, x, y, color, K_BITMAP, 0);
}
#[allow(clippy::too_many_arguments)]
pub(crate) fn lcd(&mut self, key: u64, e: &GcEntry, x: i32, y: i32, color: u32, bgr: bool, adj: &[u8; 256]) {
let rgb = color & 0xFF_FFFF;
let i = match self.adj.iter().position(|a| a.0 == rgb) {
Some(i) => i,
None => {
self.adj.push((rgb, *adj));
self.adj.len() - 1
}
};
self.push(key, e, x, y, color, if bgr { K_LCD_BGR } else { K_LCD_RGB }, i as u16);
}
pub(crate) fn fail(&mut self) {
self.ok = false;
}
}
impl Text {
#[allow(clippy::too_many_arguments)]
pub fn record_n(&mut self, rec: &mut GlyphRec, dc: &mut Dc, sf: &mut Surface, x: i32, y: i32, s: &[u8], len: usize) -> bool {
rec.ok = true;
self.rec = Some(core::mem::take(rec));
self.draw_n(dc, sf, x, y, s, len);
self.rec_end(rec)
}
#[allow(clippy::too_many_arguments)]
pub fn record_icon(&mut self, rec: &mut GlyphRec, dc: &mut Dc, sf: &mut Surface, cp: u32, x: i32, y: i32, size_fx: i32) -> bool {
rec.ok = true;
self.rec = Some(core::mem::take(rec));
self.icon_draw(dc, sf, cp, x, y, size_fx);
self.rec_end(rec)
}
fn rec_end(&mut self, rec: &mut GlyphRec) -> bool {
*rec = self.rec.take().unwrap_or_default();
rec.ok
}
pub fn glyphs(&self) -> GlyphView<'_> {
GlyphView { map: &self.gc.map, lut: self.lcd_lut.as_deref() }
}
}
#[derive(Clone, Copy)]
pub struct GlyphView<'a> {
map: &'a alloc::collections::BTreeMap<u64, GcEntry>,
lut: Option<&'a Lut>,
}
impl GlyphView<'_> {
pub fn draw(&self, rec: &GlyphRec, from: usize, to: usize, dc: &mut Dc, sf: &mut Surface) {
let Some(ops) = rec.ops.get(from..to) else { return };
for op in ops {
let c = dc.clip;
if op.b[0] >= c[2] || op.b[2] <= c[0] || op.b[1] >= c[3] || op.b[3] <= c[1] {
continue;
}
let Some(e) = self.map.get(&op.key) else { continue };
if dc.color != op.color {
dc.set_color(op.color);
}
match op.kind {
K_MASK => mask_blit(dc, sf, op.x, op.y, e),
K_BITMAP => bitmap_blit(dc, sf, op.x, op.y, e),
_ => {
if let (Some(lut), Some(a)) = (self.lut, rec.adj.get(op.adj as usize)) {
lcd::blit(dc, sf, op.x, op.y, e, op.kind == K_LCD_BGR, lut, &a.1);
}
}
}
}
}
}