use crate::memory::MacMemoryBus;
use crate::memory::MemoryBus;
use std::collections::HashSet;
#[derive(Clone, Copy, Debug)]
pub struct Rect {
pub top: i16,
pub left: i16,
pub bottom: i16,
pub right: i16,
}
#[derive(Clone, Copy, Debug)]
pub enum ShapeOp {
Frame,
Paint,
Erase,
Invert,
Fill([u8; 8]),
Glyph(i16), }
pub struct UnderlineInfo {
pub start_x: i16,
pub end_x: i16,
pub breaks: Vec<HashSet<i16>>,
}
#[allow(dead_code)]
pub struct StringBuffer {
pub width: i16,
pub height: i16,
pub baseline_y: i16,
pub pixels: Vec<u8>,
}
pub(crate) use crate::mac_roman::{
decode_mac_roman, decode_mac_roman_for_render, encode_mac_roman_lossy,
};
#[allow(dead_code)]
impl StringBuffer {
pub fn new(width: i16, height: i16, baseline_y: i16) -> Self {
let w = width.max(1) as usize;
let h = height.max(1) as usize;
Self {
width,
height,
baseline_y,
pixels: vec![0; w * h],
}
}
#[allow(dead_code)]
pub fn get(&self, x: i16, y: i16) -> bool {
if x < 0 || x >= self.width || y < 0 || y >= self.height {
return false;
}
self.pixels[y as usize * self.width as usize + x as usize] != 0
}
#[allow(dead_code)]
pub fn set(&mut self, x: i16, y: i16, val: bool) {
if x >= 0 && x < self.width && y >= 0 && y < self.height {
self.pixels[y as usize * self.width as usize + x as usize] = if val { 1 } else { 0 };
}
}
#[allow(dead_code)]
pub fn clear(&mut self) {
self.pixels.fill(0);
}
#[allow(dead_code)]
pub fn any_neighbor_set(&self, x: i16, y: i16) -> bool {
for dy in -1..=1i16 {
for dx in -1..=1i16 {
if dx == 0 && dy == 0 {
continue;
}
if self.get(x + dx, y + dy) {
return true;
}
}
}
false
}
}
pub fn read_rect(bus: &MacMemoryBus, ptr: u32) -> Rect {
Rect {
top: bus.read_word(ptr) as i16,
left: bus.read_word(ptr + 2) as i16,
bottom: bus.read_word(ptr + 4) as i16,
right: bus.read_word(ptr + 6) as i16,
}
}
pub fn read_fsspec_name(bus: &MacMemoryBus, spec_ptr: u32) -> String {
let bytes = bus.read_pstring(spec_ptr + 6);
let n = bytes.len().min(63);
let name = decode_mac_roman(&bytes[..n]);
name.strip_prefix("Unix:").unwrap_or(&name).to_string()
}
#[cfg(test)]
mod tests {
use super::{decode_mac_roman, decode_mac_roman_for_render, encode_mac_roman_lossy};
#[test]
fn mac_roman_round_trips_classic_filename_symbols() {
let bytes = b"MORE\xAA Library";
let decoded = decode_mac_roman(bytes);
assert_eq!(decoded, "MORE\u{2122} Library");
assert_eq!(encode_mac_roman_lossy(&decoded), bytes);
}
#[test]
fn mac_roman_render_decode_expands_classic_punctuation() {
assert_eq!(
decode_mac_roman_for_render(b"Choose Monitor\xC9"),
"Choose Monitor..."
);
assert_eq!(decode_mac_roman_for_render(b"Marathon\xD5s"), "Marathon's");
}
}