mirror of
https://github.com/saymrwulf/xous-core.git
synced 2026-11-15 08:30:02 +00:00
harmonize blitstr2 and graphics-server to an i16 pixel representation
previously blitstr2 is using usize for x/y coords, which means that for layout purposes points could not go to the top or left boundary without causing arithmetic overflow. Of course, you want to render everything on-screen, but, as we have multi-line text with overflow possibility, it's reasonable to be able to use negative coordinates to locate text boxes that flow into the visible region. This of course means that occassionally you can come out with things like "negative widths", but even then, there can be reasonable uses for this as an intermediate in calculations that ultimately arrive at a positive result.
This commit is contained in:
parent
287aea90b6
commit
5452fae33c
10 changed files with 49 additions and 49 deletions
|
|
@ -29,8 +29,8 @@ pub use blitstr2::*;
|
|||
|
||||
use std::hash::{Hash, Hasher};
|
||||
|
||||
pub const LINES: usize = 536;
|
||||
pub const WIDTH: usize = 336;
|
||||
pub const LINES: i16 = 536;
|
||||
pub const WIDTH: i16 = 336;
|
||||
|
||||
//////////////// IPC APIs
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
|
||||
|
|
|
|||
|
|
@ -42,9 +42,9 @@ pub(crate) struct TypesetWord {
|
|||
/// top left origin point for rendering of the glyphs
|
||||
pub origin: Pt,
|
||||
/// width of the word
|
||||
pub width: usize,
|
||||
pub width: i16,
|
||||
/// overall height for the word
|
||||
pub height: usize,
|
||||
pub height: i16,
|
||||
/// set if this `word` is not drawable, e.g. a newline placeholder.
|
||||
/// *however* the Vec<GlyphSprite> should still be checked for an insertion point, so that
|
||||
/// successive newlines properly get their insertion point drawn
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ pub struct ClipRect {
|
|||
#[allow(dead_code)]
|
||||
impl ClipRect {
|
||||
/// Initialize a rectangle using automatic min/max fixup for corner points
|
||||
pub fn new(min_x: usize, min_y: usize, max_x: usize, max_y: usize) -> ClipRect {
|
||||
pub fn new(min_x: i16, min_y: i16, max_x: i16, max_y: i16) -> ClipRect {
|
||||
// Make sure min_x <= max_x && min_y <= max_y
|
||||
let mut min = Pt { x: min_x, y: min_y };
|
||||
let mut max = Pt { x: max_x, y: max_y };
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ pub struct Cursor {
|
|||
#[allow(dead_code)]
|
||||
impl Cursor {
|
||||
// Make a new Cursor. When in doubt, set line_height = 0.
|
||||
pub fn new(x: usize, y: usize, line_height: usize) -> Cursor {
|
||||
pub fn new(x: i16, y: i16, line_height: usize) -> Cursor {
|
||||
Cursor {
|
||||
pt: Pt { x, y },
|
||||
line_height,
|
||||
|
|
@ -33,13 +33,13 @@ impl Cursor {
|
|||
}
|
||||
|
||||
pub fn update_glyph(&mut self, glyph: &GlyphSprite) {
|
||||
self.pt.x += glyph.wide as usize;
|
||||
self.pt.x += glyph.wide as i16;
|
||||
self.line_height = self.line_height.max(glyph.high as usize);
|
||||
}
|
||||
|
||||
pub(crate) fn update_word(&mut self, word: &TypesetWord) {
|
||||
self.pt.x += word.width;
|
||||
self.line_height = self.line_height.max(word.height);
|
||||
self.line_height = self.line_height.max(word.height as usize);
|
||||
}
|
||||
|
||||
pub fn add(&self, other: Cursor) -> Cursor {
|
||||
|
|
|
|||
|
|
@ -5,13 +5,13 @@
|
|||
/// Point specifies a pixel coordinate
|
||||
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
|
||||
pub struct Pt {
|
||||
pub x: usize,
|
||||
pub y: usize,
|
||||
pub x: i16,
|
||||
pub y: i16,
|
||||
}
|
||||
|
||||
impl Pt {
|
||||
/// Make a new point
|
||||
pub fn new(x: usize, y: usize) -> Pt {
|
||||
pub fn new(x: i16, y: i16) -> Pt {
|
||||
Pt { x, y }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,14 +4,14 @@ use crate::api::Point;
|
|||
use minifb::{Key, Window, WindowOptions};
|
||||
use crate::api::{LINES, WIDTH};
|
||||
|
||||
const HEIGHT: usize = LINES;
|
||||
const HEIGHT: i16 = LINES;
|
||||
|
||||
/// Width of the screen in 32-bit words
|
||||
const WIDTH_WORDS: usize = 11;
|
||||
pub const FB_WIDTH_WORDS: usize = WIDTH_WORDS;
|
||||
pub const FB_WIDTH_PIXELS: usize = WIDTH;
|
||||
pub const FB_LINES: usize = HEIGHT;
|
||||
pub const FB_SIZE: usize = WIDTH_WORDS * HEIGHT; // 44 bytes by 536 lines
|
||||
pub const FB_WIDTH_PIXELS: usize = WIDTH as usize;
|
||||
pub const FB_LINES: usize = HEIGHT as usize;
|
||||
pub const FB_SIZE: usize = WIDTH_WORDS * HEIGHT as usize; // 44 bytes by 536 lines
|
||||
|
||||
const MAX_FPS: u64 = 60;
|
||||
const DARK_COLOUR: u32 = 0xB5B5AD;
|
||||
|
|
@ -34,8 +34,8 @@ impl XousDisplay {
|
|||
pub fn new() -> XousDisplay {
|
||||
let mut window = Window::new(
|
||||
"Precursor",
|
||||
WIDTH,
|
||||
HEIGHT,
|
||||
WIDTH as usize,
|
||||
HEIGHT as usize,
|
||||
WindowOptions {
|
||||
scale_mode: minifb::ScaleMode::AspectRatioStretch,
|
||||
resize: true,
|
||||
|
|
@ -51,9 +51,9 @@ impl XousDisplay {
|
|||
// 1000 * 1000 / MAX_FPS,
|
||||
// )));
|
||||
|
||||
let native_buffer = vec![DARK_COLOUR; WIDTH * HEIGHT];
|
||||
let native_buffer = vec![DARK_COLOUR; WIDTH as usize * HEIGHT as usize];
|
||||
window
|
||||
.update_with_buffer(&native_buffer, WIDTH, HEIGHT)
|
||||
.update_with_buffer(&native_buffer, WIDTH as usize, HEIGHT as usize)
|
||||
.unwrap();
|
||||
|
||||
let xns = xous_names::XousNames::new().unwrap();
|
||||
|
|
@ -102,7 +102,7 @@ impl XousDisplay {
|
|||
pub fn redraw(&mut self) {
|
||||
self.emulated_to_native();
|
||||
self.window
|
||||
.update_with_buffer(&self.native_buffer, WIDTH, HEIGHT)
|
||||
.update_with_buffer(&self.native_buffer, WIDTH as usize, HEIGHT as usize)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,10 +5,10 @@ pub use cliprect::*;
|
|||
pub(crate) mod fonts;
|
||||
pub(crate) use fonts::*;
|
||||
|
||||
const LINES: usize = crate::backend::FB_LINES;
|
||||
const WIDTH: usize = crate::backend::FB_WIDTH_PIXELS;
|
||||
const LINES: i16 = crate::backend::FB_LINES as i16;
|
||||
const WIDTH: i16 = crate::backend::FB_WIDTH_PIXELS as i16;
|
||||
const WORDS_PER_LINE: usize = crate::backend::FB_WIDTH_WORDS;
|
||||
pub type FrBuf = [u32; WORDS_PER_LINE * LINES];
|
||||
pub type FrBuf = [u32; WORDS_PER_LINE * LINES as usize];
|
||||
|
||||
// add more fonts (an example):
|
||||
// https://github.com/samblenny/blitstr2/commit/bb7d4ab6a2d8913dcb520895a3c242c933413aae
|
||||
|
|
@ -17,7 +17,7 @@ pub struct ClipRect {
|
|||
#[allow(dead_code)]
|
||||
impl ClipRect {
|
||||
/// Initialize a rectangle using automatic min/max fixup for corner points
|
||||
pub fn new(min_x: usize, min_y: usize, max_x: usize, max_y: usize) -> ClipRect {
|
||||
pub fn new(min_x: i16, min_y: i16, max_x: i16, max_y: i16) -> ClipRect {
|
||||
// Make sure min_x <= max_x && min_y <= max_y
|
||||
let mut min = Pt { x: min_x, y: min_y };
|
||||
let mut max = Pt { x: max_x, y: max_y };
|
||||
|
|
|
|||
|
|
@ -230,15 +230,15 @@ fn xmain() -> ! {
|
|||
|
||||
let typeset_extent = match tv.bounds_hint {
|
||||
TextBounds::BoundingBox(r) =>
|
||||
Pt::new((r.br().x - r.tl().x - tv.margin.x * 2) as usize, (r.br().y - r.tl().y - tv.margin.y * 2) as usize),
|
||||
Pt::new(r.br().x - r.tl().x - tv.margin.x * 2, r.br().y - r.tl().y - tv.margin.y * 2),
|
||||
TextBounds::GrowableFromBr(br, width) =>
|
||||
Pt::new(width as usize - tv.margin.x as usize * 2, br.y as usize - tv.margin.y as usize * 2),
|
||||
Pt::new(width as i16 - tv.margin.x * 2, br.y - tv.margin.y * 2),
|
||||
TextBounds::GrowableFromBl(bl, width) =>
|
||||
Pt::new(width as usize - tv.margin.x as usize * 2, bl.y as usize - tv.margin.y as usize * 2),
|
||||
Pt::new(width as i16 - tv.margin.x * 2, bl.y - tv.margin.y * 2),
|
||||
TextBounds::GrowableFromTl(tl, width) =>
|
||||
Pt::new(width as usize - tv.margin.x as usize * 2, (clip_rect.br().y - clip_rect.tl().y - tl.y) as usize - tv.margin.y as usize * 2),
|
||||
Pt::new(width as i16 - tv.margin.x * 2, (clip_rect.br().y - clip_rect.tl().y - tl.y) - tv.margin.y * 2),
|
||||
TextBounds::GrowableFromTr(tr, width) =>
|
||||
Pt::new(width as usize - tv.margin.x as usize * 2, (clip_rect.br().y - clip_rect.tl().y - tr.y) as usize - tv.margin.y as usize * 2),
|
||||
Pt::new(width as i16 - tv.margin.x * 2, (clip_rect.br().y - clip_rect.tl().y - tr.y) - tv.margin.y * 2),
|
||||
};
|
||||
let mut typesetter = Typesetter::setup(
|
||||
tv.to_str(),
|
||||
|
|
|
|||
|
|
@ -46,21 +46,21 @@ impl TypesetWord {
|
|||
TypesetWord {
|
||||
gs: vec![gs],
|
||||
origin,
|
||||
width: gs.wide as usize,
|
||||
height: gs.high as usize,
|
||||
width: gs.wide as i16,
|
||||
height: gs.high as i16,
|
||||
non_drawable: false,
|
||||
strpos,
|
||||
}
|
||||
}
|
||||
pub fn push(&mut self, gs: GlyphSprite) {
|
||||
self.width += (gs.wide + gs.kern) as usize;
|
||||
self.height = self.height.max(gs.high as usize);
|
||||
self.width += (gs.wide + gs.kern) as i16;
|
||||
self.height = self.height.max(gs.high as i16);
|
||||
self.gs.push(gs);
|
||||
}
|
||||
/// if the pop is invalid, we'll return an invalid character. Just...don't do that. k?
|
||||
pub fn pop(&mut self) -> GlyphSprite {
|
||||
let gs = self.gs.pop().unwrap_or(NULL_GLYPH_SPRITE);
|
||||
self.width -= (gs.wide + gs.kern) as usize;
|
||||
self.width -= (gs.wide + gs.kern) as i16;
|
||||
// we can't undo any height transformations, unfortunately, because we don't know what the previous state was
|
||||
// but it's fairly minor if text is set funny on a line because text overflowed and had e.g. emoji buried amongst
|
||||
// small font text...
|
||||
|
|
@ -102,10 +102,10 @@ impl ComposedType {
|
|||
cursor,
|
||||
}
|
||||
}
|
||||
pub fn bb_width(&self) -> usize {
|
||||
pub fn bb_width(&self) -> i16 {
|
||||
self.bounding_box.max.x - self.bounding_box.min.x
|
||||
}
|
||||
pub fn bb_height(&self) -> usize {
|
||||
pub fn bb_height(&self) -> i16 {
|
||||
self.bounding_box.max.y - self.bounding_box.min.y
|
||||
}
|
||||
/// Note: it is up to the caller to ensure that clip_rect is within the renderable screen area. We do no
|
||||
|
|
@ -132,14 +132,14 @@ impl ComposedType {
|
|||
log::trace!("not renderable maybe_y: {}, {:?}", maybe_y, clip_rect);
|
||||
renderable = false;
|
||||
}
|
||||
point.x += (glyph.wide + glyph.kern) as usize; // keep scorekeeping on this, because it could eventually become renderable
|
||||
point.x += (glyph.wide + glyph.kern) as i16; // keep scorekeeping on this, because it could eventually become renderable
|
||||
if !renderable {
|
||||
// quickly short circuit over any text that is definitely outside of our clipping rectangle
|
||||
continue;
|
||||
} else {
|
||||
let cr = ClipRect::new(
|
||||
clip_rect.tl().x as usize, clip_rect.tl().y as usize,
|
||||
clip_rect.br().x as usize, clip_rect.br().y as usize
|
||||
clip_rect.tl().x, clip_rect.tl().y,
|
||||
clip_rect.br().x, clip_rect.br().y
|
||||
);
|
||||
if !glyph.double {
|
||||
blitstr2::xor_glyph(
|
||||
|
|
@ -211,7 +211,7 @@ pub(crate) struct Typesetter {
|
|||
s: String,
|
||||
base_style: GlyphStyle,
|
||||
overflow: bool,
|
||||
max_width: usize,
|
||||
max_width: i16,
|
||||
last_line_height: usize, // scorecarding for the very last line on the loop exit
|
||||
}
|
||||
impl Typesetter {
|
||||
|
|
@ -261,7 +261,7 @@ impl Typesetter {
|
|||
// going out of scope at the end of the call.
|
||||
let mut composition = Vec::<TypesetWord>::new();
|
||||
|
||||
if self.bb.max.x - self.bb.min.y < glyph_to_height_hint(GlyphStyle::Regular) {
|
||||
if self.bb.max.x - self.bb.min.y < glyph_to_height_hint(GlyphStyle::Regular) as i16 {
|
||||
// we flag this because the typesetter algorithm may never converge if it can't set any characters
|
||||
// because the region is just too narrow.
|
||||
log::error!("Words cannot be typset because the width of the typset region is too narrow.");
|
||||
|
|
@ -420,7 +420,7 @@ impl Typesetter {
|
|||
let ret = ComposedType::new(composition,
|
||||
ClipRect::new(
|
||||
self.bb.min.x, self.bb.min.y,
|
||||
self.max_width, self.cursor.pt.y + self.last_line_height,
|
||||
self.max_width as i16, self.cursor.pt.y + self.last_line_height as i16,
|
||||
),
|
||||
self.cursor
|
||||
);
|
||||
|
|
@ -439,12 +439,12 @@ impl Typesetter {
|
|||
fn is_newline_available(&self) -> bool {
|
||||
// repeated, bare newlines will have a candidate height of 0, as it contains no glyphs. correct for that.
|
||||
let corrected_height = if self.candidate.height == 0 {
|
||||
self.cursor.line_height
|
||||
self.cursor.line_height as i16
|
||||
} else {
|
||||
self.candidate.height
|
||||
};
|
||||
log::trace!("{} < {}", corrected_height + self.cursor.pt.y + self.cursor.line_height, self.bb.max.y);
|
||||
corrected_height + self.cursor.pt.y + self.cursor.line_height < self.bb.max.y
|
||||
log::trace!("{} < {}", corrected_height + self.cursor.pt.y + self.cursor.line_height as i16, self.bb.max.y);
|
||||
corrected_height + self.cursor.pt.y + (self.cursor.line_height as i16) < self.bb.max.y
|
||||
}
|
||||
fn does_word_fit_on_line(&self) -> bool {
|
||||
self.candidate.width + self.cursor.pt.x < self.bb.max.x
|
||||
|
|
@ -467,7 +467,7 @@ impl Typesetter {
|
|||
if !self.candidate.non_drawable { // this is mainly for "non-drawable spaces" at the beginning of a line
|
||||
self.max_width = self.max_width.max(self.candidate.width + self.candidate.origin.x);
|
||||
self.cursor.pt.x += self.candidate.width;
|
||||
self.cursor.line_height = self.cursor.line_height.max(self.candidate.height);
|
||||
self.cursor.line_height = self.cursor.line_height.max(self.candidate.height as usize);
|
||||
self.last_line_height = self.cursor.line_height;
|
||||
}
|
||||
if false {tsw_debug(&self.candidate)};
|
||||
|
|
@ -493,9 +493,9 @@ impl Typesetter {
|
|||
fn move_candidate_to_newline(&mut self) {
|
||||
// advance the rendering line, without inserting a newline placeholder
|
||||
self.last_line_height = self.cursor.line_height;
|
||||
self.cursor.pt.y += self.cursor.line_height;
|
||||
self.cursor.pt.y += self.cursor.line_height as i16;
|
||||
self.cursor.pt.x = self.bb.min.x;
|
||||
self.cursor.line_height = self.candidate.height;
|
||||
self.cursor.line_height = self.candidate.height as usize;
|
||||
// now set the current candidate word's origin to the beginning of this new line
|
||||
self.candidate.origin = self.cursor.pt;
|
||||
}
|
||||
|
|
@ -524,7 +524,7 @@ impl Typesetter {
|
|||
/// set to our space point, because the caller will have already stashed the previously formed word
|
||||
fn try_append_space(&mut self, composition: &mut Vec::<TypesetWord>) -> bool {
|
||||
assert!(self.candidate.gs.len() == 0, "self.candidate was not set to a new state prior to this call");
|
||||
if (self.cursor.pt.x + self.space.wide as usize) < self.bb.max.x {
|
||||
if (self.cursor.pt.x + self.space.wide as i16) < self.bb.max.x {
|
||||
// our candidate word is "just as space"
|
||||
let mut candidate_space = self.space.clone();
|
||||
if self.is_insert_point() {
|
||||
|
|
|
|||
Loading…
Reference in a new issue