blob: 74cf36e7d02334a51d1503ca18ad91e746d13692 [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#![feature(async_await, await_macro)]
#![deny(warnings)]
use carnelian::{
measure_text, Canvas, Color, FontDescription, FontFace, IntSize, Paint, PixelSink, Point, Rect,
Size,
};
use failure::{bail, Error, ResultExt};
use fuchsia_async as fasync;
use fuchsia_framebuffer::{Config, Frame, FrameBuffer, PixelFormat};
use futures::StreamExt;
mod setup;
static FONT_DATA: &'static [u8] =
include_bytes!("../../../../garnet/bin/fonts/third_party/robotoslab/RobotoSlab-Regular.ttf");
struct RecoveryUI<'a, T: PixelSink> {
face: FontFace<'a>,
canvas: Canvas<T>,
config: Config,
text_size: u32,
}
impl<'a, T: PixelSink> RecoveryUI<'a, T> {
fn draw(&mut self, heading: &str, body: &str) {
let r = Rect::new(
Point::new(0.0, 0.0),
Size::new(self.config.width as f32, self.config.height as f32),
);
let bg = Color { r: 255, g: 0, b: 255, a: 255 };
self.canvas.fill_rect(&r, bg);
let mut font_description =
FontDescription { baseline: 0, face: &mut self.face, size: self.text_size };
let size = measure_text(heading, &mut font_description);
let paint = Paint { fg: Color { r: 255, g: 255, b: 255, a: 255 }, bg: bg };
self.canvas.fill_text(
heading,
Point::new(
(self.config.width / 2) as f32 - (size.width / 2.0),
(self.config.height / 4) as f32 - (size.height / 2.0),
),
&mut font_description,
&paint,
);
let size = measure_text(body, &mut font_description);
self.canvas.fill_text(
body,
Point::new(
(self.config.width / 2) as f32 - (size.width / 2.0),
(self.config.height / 2) as f32 + (self.config.height / 4) as f32
- (size.height / 2.0),
),
&mut font_description,
&paint,
);
}
}
struct FramePixelSink {
frame: Frame,
}
impl PixelSink for FramePixelSink {
fn write_pixel_at_offset(&mut self, offset: usize, value: &[u8]) {
self.frame.write_pixel_at_offset(offset, &value);
}
}
async fn run<'a, T: PixelSink>(ui: &'a mut RecoveryUI<'a, T>) -> Result<(), Error> {
ui.draw("Fuchsia System Recovery", "Waiting...");
let mut receiver = setup::start_server()?;
while let Some(_event) = await!(receiver.next()) {
println!("recovery: received request");
ui.draw("Fuchsia System Recovery", "Got event");
}
Ok(())
}
fn main() -> Result<(), Error> {
println!("recovery: started");
let mut executor = fasync::Executor::new().context("Failed to create executor")?;
let fb = FrameBuffer::new(None, &mut executor).context("Failed to create framebuffer")?;
let config = fb.get_config();
if config.format != PixelFormat::Argb8888 && config.format != PixelFormat::Rgb565 {
bail!("Unsupported pixel format {:#?}", config.format);
}
let display_size = IntSize::new(config.width as i32, config.height as i32);
let frame = fb.new_frame(&mut executor)?;
frame.present(&fb)?;
let face = FontFace::new(FONT_DATA).unwrap();
let sink = FramePixelSink { frame };
let canvas = Canvas::new_with_sink(
display_size,
sink,
config.linear_stride_bytes() as u32,
config.pixel_size_bytes,
);
let mut ui = RecoveryUI { face: face, canvas, config, text_size: config.height / 12 };
executor.run_singlethreaded(run(&mut ui))?;
unreachable!();
}
#[cfg(test)]
mod tests {
use super::{RecoveryUI, FONT_DATA};
use carnelian::{Canvas, FontFace, IntSize, PixelSink};
use fuchsia_framebuffer::{Config, PixelFormat};
struct TestPixelSink {}
impl PixelSink for TestPixelSink {
fn write_pixel_at_offset(&mut self, _offset: usize, _value: &[u8]) {}
}
#[test]
fn test_draw() {
const WIDTH: i32 = 800;
const HEIGHT: i32 = 600;
let face = FontFace::new(FONT_DATA).unwrap();
let sink = TestPixelSink {};
let config = Config {
display_id: 0,
width: WIDTH as u32,
height: HEIGHT as u32,
linear_stride_pixels: WIDTH as u32,
format: PixelFormat::Argb8888,
pixel_size_bytes: 4,
};
let canvas = Canvas::new_with_sink(
IntSize::new(WIDTH, HEIGHT),
sink,
config.linear_stride_bytes() as u32,
config.pixel_size_bytes,
);
let mut ui = RecoveryUI { face: face, canvas, config, text_size: 24 };
ui.draw("Heading", "Body");
}
}