From 5452fae33c0baeff82dfb056dee433bab2ef687d Mon Sep 17 00:00:00 2001 From: bunnie Date: Mon, 28 Mar 2022 23:17:18 +0800 Subject: [PATCH] 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. --- services/graphics-server/src/api.rs | 4 +- services/graphics-server/src/api/blitstr2.rs | 4 +- .../src/api/blitstr2/cliprect.rs | 2 +- .../src/api/blitstr2/cursor.rs | 6 +-- .../graphics-server/src/api/blitstr2/pt.rs | 6 +-- .../graphics-server/src/backend/minifb.rs | 18 ++++----- services/graphics-server/src/blitstr2.rs | 6 +-- .../graphics-server/src/blitstr2/cliprect.rs | 2 +- services/graphics-server/src/main.rs | 10 ++--- services/graphics-server/src/wordwrap.rs | 40 +++++++++---------- 10 files changed, 49 insertions(+), 49 deletions(-) diff --git a/services/graphics-server/src/api.rs b/services/graphics-server/src/api.rs index 2bee41ed2..f9d3c1490 100644 --- a/services/graphics-server/src/api.rs +++ b/services/graphics-server/src/api.rs @@ -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)] diff --git a/services/graphics-server/src/api/blitstr2.rs b/services/graphics-server/src/api/blitstr2.rs index 84aa9b75f..c1f6a69cb 100644 --- a/services/graphics-server/src/api/blitstr2.rs +++ b/services/graphics-server/src/api/blitstr2.rs @@ -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 should still be checked for an insertion point, so that /// successive newlines properly get their insertion point drawn diff --git a/services/graphics-server/src/api/blitstr2/cliprect.rs b/services/graphics-server/src/api/blitstr2/cliprect.rs index e159f77b7..2712285f4 100644 --- a/services/graphics-server/src/api/blitstr2/cliprect.rs +++ b/services/graphics-server/src/api/blitstr2/cliprect.rs @@ -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 }; diff --git a/services/graphics-server/src/api/blitstr2/cursor.rs b/services/graphics-server/src/api/blitstr2/cursor.rs index 3249af2f2..00f8c1230 100644 --- a/services/graphics-server/src/api/blitstr2/cursor.rs +++ b/services/graphics-server/src/api/blitstr2/cursor.rs @@ -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 { diff --git a/services/graphics-server/src/api/blitstr2/pt.rs b/services/graphics-server/src/api/blitstr2/pt.rs index fb9dab8a8..ee226bb70 100644 --- a/services/graphics-server/src/api/blitstr2/pt.rs +++ b/services/graphics-server/src/api/blitstr2/pt.rs @@ -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 } } } diff --git a/services/graphics-server/src/backend/minifb.rs b/services/graphics-server/src/backend/minifb.rs index c437c8c27..96b121964 100644 --- a/services/graphics-server/src/backend/minifb.rs +++ b/services/graphics-server/src/backend/minifb.rs @@ -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(); } diff --git a/services/graphics-server/src/blitstr2.rs b/services/graphics-server/src/blitstr2.rs index c34d5cf40..ccffdbc30 100644 --- a/services/graphics-server/src/blitstr2.rs +++ b/services/graphics-server/src/blitstr2.rs @@ -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 \ No newline at end of file diff --git a/services/graphics-server/src/blitstr2/cliprect.rs b/services/graphics-server/src/blitstr2/cliprect.rs index beef38933..08083771c 100644 --- a/services/graphics-server/src/blitstr2/cliprect.rs +++ b/services/graphics-server/src/blitstr2/cliprect.rs @@ -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 }; diff --git a/services/graphics-server/src/main.rs b/services/graphics-server/src/main.rs index 6f0be4059..150c450c4 100644 --- a/services/graphics-server/src/main.rs +++ b/services/graphics-server/src/main.rs @@ -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(), diff --git a/services/graphics-server/src/wordwrap.rs b/services/graphics-server/src/wordwrap.rs index ebe7916ae..db89e4105 100644 --- a/services/graphics-server/src/wordwrap.rs +++ b/services/graphics-server/src/wordwrap.rs @@ -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::::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::) -> 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() {