backend.rs
raw
//! The trait render backends implement to consume a fragment tree.
use std::error::Error;
use std::fmt;
use crate::display_list::{FragmentId, FragmentStore};
/// A renderer that can rasterize a fragment tree into its current target.
///
/// How a backend acquires its target (a wgpu surface, a pixmap, …) is the
/// backend's own affair, configured outside this trait; "render a fragment
/// tree" is the only portable operation.
pub trait RenderBackend {
/// Render the tree rooted at `root` into the backend's target.
///
/// The target is `width_px` × `height_px` physical pixels; `scale` is the
/// logical-to-physical scale factor and is applied as the root transform,
/// so fragment coordinates are in logical units.
fn render(
&mut self,
root: FragmentId,
store: &FragmentStore,
width_px: u32,
height_px: u32,
scale: f64,
) -> Result<(), RenderError>;
}
/// Failure while rendering a fragment tree.
#[derive(Debug)]
pub enum RenderError {
/// A fragment id in the tree does not exist in the store.
MissingFragment(FragmentId),
/// A fragment's display list has unbalanced push/pop items.
UnbalancedFragment(FragmentId),
/// Fragment nesting exceeded the depth limit, which almost always means
/// the fragment graph contains a cycle.
ExcessiveDepth(FragmentId),
/// A backend-specific failure (device lost, surface error, …).
Backend(Box<dyn Error + Send + Sync>),
}
impl fmt::Display for RenderError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
RenderError::MissingFragment(id) => {
write!(f, "fragment {id:?} is not present in the store")
}
RenderError::UnbalancedFragment(id) => {
write!(f, "fragment {id:?} has unbalanced push/pop display items")
}
RenderError::ExcessiveDepth(id) => {
write!(
f,
"fragment nesting exceeded the depth limit at {id:?}; the fragment graph likely contains a cycle"
)
}
RenderError::Backend(err) => write!(f, "render backend error: {err}"),
}
}
}
impl Error for RenderError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
RenderError::Backend(err) => Some(err.as_ref()),
_ => None,
}
}
}