1use alloc::vec::Vec;
23
24use gfx::{Dc, Surface};
25
26use crate::glyphcache::GcEntry;
27use crate::lcd::{self, Lut};
28use crate::{bitmap_blit, mask_blit, Text};
29
30const K_MASK: u8 = 0;
31const K_BITMAP: u8 = 1;
32const K_LCD_RGB: u8 = 2;
33const K_LCD_BGR: u8 = 3;
34
35#[derive(Clone, Copy)]
37struct Op {
38 key: u64,
39 x: i32,
40 y: i32,
41 b: [i32; 4],
43 color: u32,
44 kind: u8,
45 adj: u16,
47}
48
49#[derive(Default)]
51pub struct GlyphRec {
52 ops: Vec<Op>,
53 adj: Vec<(u32, [u8; 256])>,
55 epoch: u32,
56 ok: bool,
57}
58
59impl GlyphRec {
60 pub fn begin(&mut self, t: &Text) {
62 self.ops.clear();
63 self.adj.clear();
64 self.epoch = t.gc.epoch;
65 self.ok = true;
66 }
67
68 pub fn len(&self) -> usize {
70 self.ops.len()
71 }
72
73 pub fn is_empty(&self) -> bool {
74 self.ops.is_empty()
75 }
76
77 pub fn valid(&self, t: &Text) -> bool {
79 self.epoch == t.gc.epoch
80 }
81
82 fn push(&mut self, key: u64, e: &GcEntry, x: i32, y: i32, color: u32, kind: u8, adj: u16) {
83 if e.w <= 0 || e.h <= 0 {
84 return; }
86 let (x0, y0) = (x.wrapping_add(e.left), y.wrapping_add(e.top));
87 let b = [x0, y0, x0.wrapping_add(e.w), y0.wrapping_add(e.h)];
88 self.ops.push(Op { key, x, y, b, color, kind, adj });
89 }
90
91 pub(crate) fn mask(&mut self, key: u64, e: &GcEntry, x: i32, y: i32, color: u32) {
92 self.push(key, e, x, y, color, K_MASK, 0);
93 }
94
95 pub(crate) fn bitmap(&mut self, key: u64, e: &GcEntry, x: i32, y: i32, color: u32) {
96 self.push(key, e, x, y, color, K_BITMAP, 0);
97 }
98
99 #[allow(clippy::too_many_arguments)]
100 pub(crate) fn lcd(&mut self, key: u64, e: &GcEntry, x: i32, y: i32, color: u32, bgr: bool, adj: &[u8; 256]) {
101 let rgb = color & 0xFF_FFFF;
102 let i = match self.adj.iter().position(|a| a.0 == rgb) {
103 Some(i) => i,
104 None => {
105 self.adj.push((rgb, *adj));
106 self.adj.len() - 1
107 }
108 };
109 self.push(key, e, x, y, color, if bgr { K_LCD_BGR } else { K_LCD_RGB }, i as u16);
110 }
111
112 pub(crate) fn fail(&mut self) {
114 self.ok = false;
115 }
116}
117
118impl Text {
119 #[allow(clippy::too_many_arguments)]
122 pub fn record_n(&mut self, rec: &mut GlyphRec, dc: &mut Dc, sf: &mut Surface, x: i32, y: i32, s: &[u8], len: usize) -> bool {
123 rec.ok = true;
124 self.rec = Some(core::mem::take(rec));
125 self.draw_n(dc, sf, x, y, s, len);
126 self.rec_end(rec)
127 }
128
129 #[allow(clippy::too_many_arguments)]
131 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 {
132 rec.ok = true;
133 self.rec = Some(core::mem::take(rec));
134 self.icon_draw(dc, sf, cp, x, y, size_fx);
135 self.rec_end(rec)
136 }
137
138 fn rec_end(&mut self, rec: &mut GlyphRec) -> bool {
139 *rec = self.rec.take().unwrap_or_default();
140 rec.ok
141 }
142
143 pub fn glyphs(&self) -> GlyphView<'_> {
145 GlyphView { map: &self.gc.map, lut: self.lcd_lut.as_deref() }
146 }
147}
148
149#[derive(Clone, Copy)]
151pub struct GlyphView<'a> {
152 map: &'a alloc::collections::BTreeMap<u64, GcEntry>,
153 lut: Option<&'a Lut>,
154}
155
156impl GlyphView<'_> {
157 pub fn draw(&self, rec: &GlyphRec, from: usize, to: usize, dc: &mut Dc, sf: &mut Surface) {
160 let Some(ops) = rec.ops.get(from..to) else { return };
161 for op in ops {
162 let c = dc.clip;
163 if op.b[0] >= c[2] || op.b[2] <= c[0] || op.b[1] >= c[3] || op.b[3] <= c[1] {
164 continue;
165 }
166 let Some(e) = self.map.get(&op.key) else { continue };
167 if dc.color != op.color {
168 dc.set_color(op.color);
169 }
170 match op.kind {
171 K_MASK => mask_blit(dc, sf, op.x, op.y, e),
172 K_BITMAP => bitmap_blit(dc, sf, op.x, op.y, e),
173 _ => {
174 if let (Some(lut), Some(a)) = (self.lut, rec.adj.get(op.adj as usize)) {
175 lcd::blit(dc, sf, op.x, op.y, e, op.kind == K_LCD_BGR, lut, &a.1);
176 }
177 }
178 }
179 }
180 }
181}