aboutsummaryrefslogtreecommitdiff
path: root/src/drawing/backend.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/drawing/backend.rs')
-rw-r--r--src/drawing/backend.rs284
1 files changed, 0 insertions, 284 deletions
diff --git a/src/drawing/backend.rs b/src/drawing/backend.rs
deleted file mode 100644
index a5ba54b..0000000
--- a/src/drawing/backend.rs
+++ /dev/null
@@ -1,284 +0,0 @@
-use crate::style::text_anchor::{HPos, VPos};
-use crate::style::{Color, FontDesc, FontError, RGBAColor, ShapeStyle, TextStyle};
-use std::error::Error;
-
-/// A coordinate in the image
-pub type BackendCoord = (i32, i32);
-
-/// The error produced by a drawing backend
-#[derive(Debug)]
-pub enum DrawingErrorKind<E: Error + Send + Sync>
-where
- FontError: Send + Sync,
-{
- /// A drawing backend error
- DrawingError(E),
- /// A font rendering error
- FontError(FontError),
-}
-
-impl<E: Error + Send + Sync> std::fmt::Display for DrawingErrorKind<E> {
- fn fmt(&self, fmt: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
- match self {
- DrawingErrorKind::DrawingError(e) => write!(fmt, "Drawing backend error: {}", e),
- DrawingErrorKind::FontError(e) => write!(fmt, "Font loading error: {}", e),
- }
- }
-}
-
-impl<E: Error + Send + Sync> Error for DrawingErrorKind<E> {}
-
-/// The style data for the backend drawing API
-pub trait BackendStyle {
- /// The underlying type represents the color for this style
- type ColorType: Color;
-
- /// Convert the style into the underlying color
- fn as_color(&self) -> RGBAColor;
-
- // TODO: In the future we should support stroke width, line shape, etc....
- fn stroke_width(&self) -> u32 {
- 1
- }
-}
-
-impl<T: Color> BackendStyle for T {
- type ColorType = T;
- fn as_color(&self) -> RGBAColor {
- self.to_rgba()
- }
-}
-
-impl BackendStyle for ShapeStyle {
- type ColorType = RGBAColor;
- fn as_color(&self) -> RGBAColor {
- self.color.clone()
- }
- fn stroke_width(&self) -> u32 {
- self.stroke_width
- }
-}
-
-/// The drawing backend trait, which implements the low-level drawing APIs.
-/// This trait has a set of default implementation. And the minimal requirement of
-/// implementing a drawing backend is implementing the `draw_pixel` function.
-///
-/// If the drawing backend supports vector graphics, the other drawing APIs should be
-/// override by the backend specific implementation. Otherwise, the default implementation
-/// will use the pixel-based approach to draw other types of low-level shapes.
-pub trait DrawingBackend: Sized {
- /// The error type reported by the backend
- type ErrorType: Error + Send + Sync;
-
- /// Get the dimension of the drawing backend in pixels
- fn get_size(&self) -> (u32, u32);
-
- /// Ensure the backend is ready to draw
- fn ensure_prepared(&mut self) -> Result<(), DrawingErrorKind<Self::ErrorType>>;
-
- /// Finalize the drawing step and present all the changes.
- /// This is used as the real-time rendering support.
- /// The backend may implement in the following way, when `ensure_prepared` is called
- /// it checks if it needs a fresh buffer and `present` is called rendering all the
- /// pending changes on the screen.
- fn present(&mut self) -> Result<(), DrawingErrorKind<Self::ErrorType>>;
-
- /// Draw a pixel on the drawing backend
- /// - `point`: The backend pixel-based coordinate to draw
- /// - `color`: The color of the pixel
- fn draw_pixel(
- &mut self,
- point: BackendCoord,
- color: &RGBAColor,
- ) -> Result<(), DrawingErrorKind<Self::ErrorType>>;
-
- /// Draw a line on the drawing backend
- /// - `from`: The start point of the line
- /// - `to`: The end point of the line
- /// - `style`: The style of the line
- fn draw_line<S: BackendStyle>(
- &mut self,
- from: BackendCoord,
- to: BackendCoord,
- style: &S,
- ) -> Result<(), DrawingErrorKind<Self::ErrorType>> {
- super::rasterizer::draw_line(self, from, to, style)
- }
-
- /// Draw a rectangle on the drawing backend
- /// - `upper_left`: The coordinate of the upper-left corner of the rect
- /// - `bottom_right`: The coordinate of the bottom-right corner of the rect
- /// - `style`: The style
- /// - `fill`: If the rectangle should be filled
- fn draw_rect<S: BackendStyle>(
- &mut self,
- upper_left: BackendCoord,
- bottom_right: BackendCoord,
- style: &S,
- fill: bool,
- ) -> Result<(), DrawingErrorKind<Self::ErrorType>> {
- super::rasterizer::draw_rect(self, upper_left, bottom_right, style, fill)
- }
-
- /// Draw a path on the drawing backend
- /// - `path`: The iterator of key points of the path
- /// - `style`: The style of the path
- fn draw_path<S: BackendStyle, I: IntoIterator<Item = BackendCoord>>(
- &mut self,
- path: I,
- style: &S,
- ) -> Result<(), DrawingErrorKind<Self::ErrorType>> {
- if style.as_color().alpha() == 0.0 {
- return Ok(());
- }
-
- if style.stroke_width() == 1 {
- let mut begin: Option<BackendCoord> = None;
- for end in path.into_iter() {
- if let Some(begin) = begin {
- let result = self.draw_line(begin, end, style);
- if result.is_err() {
- return result;
- }
- }
- begin = Some(end);
- }
- } else {
- let p: Vec<_> = path.into_iter().collect();
- let v = super::rasterizer::polygonize(&p[..], style.stroke_width());
- return self.fill_polygon(v, &style.as_color());
- }
- Ok(())
- }
-
- /// Draw a circle on the drawing backend
- /// - `center`: The center coordinate of the circle
- /// - `radius`: The radius of the circle
- /// - `style`: The style of the shape
- /// - `fill`: If the circle should be filled
- fn draw_circle<S: BackendStyle>(
- &mut self,
- center: BackendCoord,
- radius: u32,
- style: &S,
- fill: bool,
- ) -> Result<(), DrawingErrorKind<Self::ErrorType>> {
- super::rasterizer::draw_circle(self, center, radius, style, fill)
- }
-
- fn fill_polygon<S: BackendStyle, I: IntoIterator<Item = BackendCoord>>(
- &mut self,
- vert: I,
- style: &S,
- ) -> Result<(), DrawingErrorKind<Self::ErrorType>> {
- let vert_buf: Vec<_> = vert.into_iter().collect();
-
- super::rasterizer::fill_polygon(self, &vert_buf[..], style)
- }
-
- /// Draw a text on the drawing backend
- /// - `text`: The text to draw
- /// - `style`: The text style
- /// - `pos` : The text anchor point
- fn draw_text(
- &mut self,
- text: &str,
- style: &TextStyle,
- pos: BackendCoord,
- ) -> Result<(), DrawingErrorKind<Self::ErrorType>> {
- let font = &style.font;
- let color = &style.color;
- if color.alpha() == 0.0 {
- return Ok(());
- }
-
- let layout = font.layout_box(text).map_err(DrawingErrorKind::FontError)?;
- let ((min_x, min_y), (max_x, max_y)) = layout;
- let width = (max_x - min_x) as i32;
- let height = (max_y - min_y) as i32;
- let dx = match style.pos.h_pos {
- HPos::Left => 0,
- HPos::Right => -width,
- HPos::Center => -width / 2,
- };
- let dy = match style.pos.v_pos {
- VPos::Top => 0,
- VPos::Center => -height / 2,
- VPos::Bottom => -height,
- };
- let trans = font.get_transform();
- let (w, h) = self.get_size();
- match font.draw(text, (0, 0), |x, y, v| {
- let (x, y) = trans.transform(x + dx - min_x, y + dy - min_y);
- let (x, y) = (pos.0 + x, pos.1 + y);
- if x >= 0 && x < w as i32 && y >= 0 && y < h as i32 {
- self.draw_pixel((x, y), &color.mix(f64::from(v)))
- } else {
- Ok(())
- }
- }) {
- Ok(drawing_result) => drawing_result,
- Err(font_error) => Err(DrawingErrorKind::FontError(font_error)),
- }
- }
-
- /// Estimate the size of the horizontal text if rendered on this backend.
- /// This is important because some of the backend may not have font ability.
- /// Thus this allows those backend reports proper value rather than ask the
- /// font rasterizer for that.
- ///
- /// - `text`: The text to estimate
- /// - `font`: The font to estimate
- /// - *Returns* The estimated text size
- fn estimate_text_size<'a>(
- &self,
- text: &str,
- font: &FontDesc<'a>,
- ) -> Result<(u32, u32), DrawingErrorKind<Self::ErrorType>> {
- let layout = font.layout_box(text).map_err(DrawingErrorKind::FontError)?;
- Ok((
- ((layout.1).0 - (layout.0).0) as u32,
- ((layout.1).1 - (layout.0).1) as u32,
- ))
- }
-
- /// Blit a bitmap on to the backend.
- ///
- /// - `text`: pos the left upper conner of the bitmap to blit
- /// - `src`: The source of the image
- ///
- /// TODO: The default implementation of bitmap blitting assumes that the bitmap is RGB, but
- /// this may not be the case. But for bitmap backend it's actually ok if we use the bitmap
- /// element that matches the pixel format, but we need to fix this.
- fn blit_bitmap<'a>(
- &mut self,
- pos: BackendCoord,
- (iw, ih): (u32, u32),
- src: &'a [u8],
- ) -> Result<(), DrawingErrorKind<Self::ErrorType>> {
- let (w, h) = self.get_size();
-
- for dx in 0..iw {
- if pos.0 + dx as i32 >= w as i32 {
- break;
- }
- for dy in 0..ih {
- if pos.1 + dy as i32 >= h as i32 {
- break;
- }
- // FIXME: This assume we have RGB image buffer
- let r = src[(dx + dy * iw) as usize * 3];
- let g = src[(dx + dy * iw) as usize * 3 + 1];
- let b = src[(dx + dy * iw) as usize * 3 + 2];
- let color = crate::style::RGBColor(r, g, b);
- let result =
- self.draw_pixel((pos.0 + dx as i32, pos.1 + dy as i32), &color.to_rgba());
- if result.is_err() {
- return result;
- }
- }
- }
-
- Ok(())
- }
-}