#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Rgba {
pub r: u8,
pub g: u8,
pub b: u8,
pub a: u8,
}
impl Rgba {
pub const fn rgb(r: u8, g: u8, b: u8) -> Self {
Self { r, g, b, a: 255 }
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Frame {
width: u32,
height: u32,
pixels: Vec<Rgba>,
}
impl Frame {
pub fn new(width: u32, height: u32, color: Rgba) -> Self {
let len = width.saturating_mul(height) as usize;
Self {
width,
height,
pixels: vec![color; len],
}
}
#[cfg(feature = "servo-native")]
pub fn from_rgba_bytes(width: u32, height: u32, bytes: &[u8]) -> Option<Self> {
if bytes.len() != width.saturating_mul(height).saturating_mul(4) as usize {
return None;
}
let pixels = bytes
.chunks_exact(4)
.map(|chunk| Rgba {
r: chunk[0],
g: chunk[1],
b: chunk[2],
a: chunk[3],
})
.collect();
Some(Self {
width,
height,
pixels,
})
}
pub fn width(&self) -> u32 {
self.width
}
pub fn height(&self) -> u32 {
self.height
}
pub fn pixels(&self) -> &[Rgba] {
&self.pixels
}
pub fn set(&mut self, x: i32, y: i32, color: Rgba) {
if x < 0 || y < 0 {
return;
}
let x = x as u32;
let y = y as u32;
if x >= self.width || y >= self.height {
return;
}
self.pixels[(y * self.width + x) as usize] = color;
}
pub fn fill_rect(&mut self, x: i32, y: i32, width: u32, height: u32, color: Rgba) {
for yy in y..y + height as i32 {
for xx in x..x + width as i32 {
self.set(xx, yy, color);
}
}
}
pub fn stroke_rect(&mut self, x: i32, y: i32, width: u32, height: u32, color: Rgba) {
if width == 0 || height == 0 {
return;
}
for xx in x..x + width as i32 {
self.set(xx, y, color);
self.set(xx, y + height as i32 - 1, color);
}
for yy in y..y + height as i32 {
self.set(x, yy, color);
self.set(x + width as i32 - 1, yy, color);
}
}
pub fn draw_text(&mut self, x: i32, y: i32, text: &str, color: Rgba) {
let mut cursor = x;
for ch in text.chars() {
draw_char(self, cursor, y, ch, color);
cursor += 8;
}
}
}
fn draw_char(frame: &mut Frame, x: i32, y: i32, ch: char, color: Rgba) {
let glyph = glyph(ch);
for (row, bits) in glyph.iter().enumerate() {
for col in 0..5 {
if bits & (1 << (4 - col)) != 0 {
frame.set(x + col + 1, y + row as i32 + 1, color);
}
}
}
}
fn glyph(ch: char) -> [u8; 7] {
match ch.to_ascii_uppercase() {
'A' => [
0b01110, 0b10001, 0b10001, 0b11111, 0b10001, 0b10001, 0b10001,
],
'B' => [
0b11110, 0b10001, 0b10001, 0b11110, 0b10001, 0b10001, 0b11110,
],
'C' => [
0b01111, 0b10000, 0b10000, 0b10000, 0b10000, 0b10000, 0b01111,
],
'D' => [
0b11110, 0b10001, 0b10001, 0b10001, 0b10001, 0b10001, 0b11110,
],
'E' => [
0b11111, 0b10000, 0b10000, 0b11110, 0b10000, 0b10000, 0b11111,
],
'F' => [
0b11111, 0b10000, 0b10000, 0b11110, 0b10000, 0b10000, 0b10000,
],
'G' => [
0b01111, 0b10000, 0b10000, 0b10111, 0b10001, 0b10001, 0b01111,
],
'H' => [
0b10001, 0b10001, 0b10001, 0b11111, 0b10001, 0b10001, 0b10001,
],
'I' => [
0b11111, 0b00100, 0b00100, 0b00100, 0b00100, 0b00100, 0b11111,
],
'J' => [
0b00111, 0b00010, 0b00010, 0b00010, 0b10010, 0b10010, 0b01100,
],
'K' => [
0b10001, 0b10010, 0b10100, 0b11000, 0b10100, 0b10010, 0b10001,
],
'L' => [
0b10000, 0b10000, 0b10000, 0b10000, 0b10000, 0b10000, 0b11111,
],
'M' => [
0b10001, 0b11011, 0b10101, 0b10101, 0b10001, 0b10001, 0b10001,
],
'N' => [
0b10001, 0b11001, 0b10101, 0b10011, 0b10001, 0b10001, 0b10001,
],
'O' => [
0b01110, 0b10001, 0b10001, 0b10001, 0b10001, 0b10001, 0b01110,
],
'P' => [
0b11110, 0b10001, 0b10001, 0b11110, 0b10000, 0b10000, 0b10000,
],
'Q' => [
0b01110, 0b10001, 0b10001, 0b10001, 0b10101, 0b10010, 0b01101,
],
'R' => [
0b11110, 0b10001, 0b10001, 0b11110, 0b10100, 0b10010, 0b10001,
],
'S' => [
0b01111, 0b10000, 0b10000, 0b01110, 0b00001, 0b00001, 0b11110,
],
'T' => [
0b11111, 0b00100, 0b00100, 0b00100, 0b00100, 0b00100, 0b00100,
],
'U' => [
0b10001, 0b10001, 0b10001, 0b10001, 0b10001, 0b10001, 0b01110,
],
'V' => [
0b10001, 0b10001, 0b10001, 0b10001, 0b10001, 0b01010, 0b00100,
],
'W' => [
0b10001, 0b10001, 0b10001, 0b10101, 0b10101, 0b10101, 0b01010,
],
'X' => [
0b10001, 0b10001, 0b01010, 0b00100, 0b01010, 0b10001, 0b10001,
],
'Y' => [
0b10001, 0b10001, 0b01010, 0b00100, 0b00100, 0b00100, 0b00100,
],
'Z' => [
0b11111, 0b00001, 0b00010, 0b00100, 0b01000, 0b10000, 0b11111,
],
'0' => [
0b01110, 0b10001, 0b10011, 0b10101, 0b11001, 0b10001, 0b01110,
],
'1' => [
0b00100, 0b01100, 0b00100, 0b00100, 0b00100, 0b00100, 0b01110,
],
'2' => [
0b01110, 0b10001, 0b00001, 0b00010, 0b00100, 0b01000, 0b11111,
],
'3' => [
0b11110, 0b00001, 0b00001, 0b01110, 0b00001, 0b00001, 0b11110,
],
'4' => [
0b00010, 0b00110, 0b01010, 0b10010, 0b11111, 0b00010, 0b00010,
],
'5' => [
0b11111, 0b10000, 0b10000, 0b11110, 0b00001, 0b00001, 0b11110,
],
'6' => [
0b01110, 0b10000, 0b10000, 0b11110, 0b10001, 0b10001, 0b01110,
],
'7' => [
0b11111, 0b00001, 0b00010, 0b00100, 0b01000, 0b01000, 0b01000,
],
'8' => [
0b01110, 0b10001, 0b10001, 0b01110, 0b10001, 0b10001, 0b01110,
],
'9' => [
0b01110, 0b10001, 0b10001, 0b01111, 0b00001, 0b00001, 0b01110,
],
'.' => [
0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b01100, 0b01100,
],
':' => [
0b00000, 0b01100, 0b01100, 0b00000, 0b01100, 0b01100, 0b00000,
],
'/' => [
0b00001, 0b00010, 0b00010, 0b00100, 0b01000, 0b01000, 0b10000,
],
'-' => [
0b00000, 0b00000, 0b00000, 0b11111, 0b00000, 0b00000, 0b00000,
],
'_' => [
0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b11111,
],
'|' => [
0b00100, 0b00100, 0b00100, 0b00100, 0b00100, 0b00100, 0b00100,
],
';' => [
0b00000, 0b01100, 0b01100, 0b00000, 0b01100, 0b00100, 0b01000,
],
',' => [
0b00000, 0b00000, 0b00000, 0b00000, 0b01100, 0b00100, 0b01000,
],
' ' => [0; 7],
_ => [
0b01110, 0b10001, 0b00001, 0b00010, 0b00100, 0b00000, 0b00100,
],
}
}