use crate::core::font;
use crate::core::image;
use crate::core::renderer;
use crate::core::svg;
use crate::core::{self, Background, Color, Image, Point, Rectangle, Size, Svg, Transformation};
use crate::graphics::compositor;
use crate::graphics::mesh;
use crate::graphics::text;
use crate::graphics::{self, Shell};
use std::borrow::Cow;
#[derive(Debug)]
pub enum Renderer<A, B> {
Primary(A),
Secondary(B),
}
macro_rules! delegate {
($renderer:expr, $name:ident, $body:expr) => {
match $renderer {
Self::Primary($name) => $body,
Self::Secondary($name) => $body,
}
};
}
impl<A, B> core::Renderer for Renderer<A, B>
where
A: core::Renderer,
B: core::Renderer,
{
fn fill_quad(&mut self, quad: renderer::Quad, background: impl Into<Background>) {
delegate!(self, renderer, renderer.fill_quad(quad, background.into()));
}
fn start_layer(&mut self, bounds: Rectangle) {
delegate!(self, renderer, renderer.start_layer(bounds));
}
fn end_layer(&mut self) {
delegate!(self, renderer, renderer.end_layer());
}
fn start_transformation(&mut self, transformation: Transformation) {
delegate!(
self,
renderer,
renderer.start_transformation(transformation)
);
}
fn end_transformation(&mut self) {
delegate!(self, renderer, renderer.end_transformation());
}
fn allocate_image(
&mut self,
handle: &image::Handle,
callback: impl FnOnce(Result<image::Allocation, image::Error>) + Send + 'static,
) {
delegate!(self, renderer, renderer.allocate_image(handle, callback));
}
fn hint(&mut self, scale_factor: f32) {
delegate!(self, renderer, renderer.hint(scale_factor));
}
fn scale_factor(&self) -> Option<f32> {
delegate!(self, renderer, renderer.scale_factor())
}
fn tick(&mut self) {
delegate!(self, renderer, renderer.tick());
}
fn reset(&mut self, new_bounds: Rectangle) {
delegate!(self, renderer, renderer.reset(new_bounds));
}
}
impl<A, B> core::text::Renderer for Renderer<A, B>
where
A: core::text::Renderer,
B: core::text::Renderer<Font = A::Font, Paragraph = A::Paragraph, Editor = A::Editor>,
{
type Font = A::Font;
type Paragraph = A::Paragraph;
type Editor = A::Editor;
const ICON_FONT: Self::Font = A::ICON_FONT;
const CHECKMARK_ICON: char = A::CHECKMARK_ICON;
const ARROW_DOWN_ICON: char = A::ARROW_DOWN_ICON;
const SCROLL_UP_ICON: char = A::SCROLL_UP_ICON;
const SCROLL_DOWN_ICON: char = A::SCROLL_DOWN_ICON;
const SCROLL_LEFT_ICON: char = A::SCROLL_LEFT_ICON;
const SCROLL_RIGHT_ICON: char = A::SCROLL_RIGHT_ICON;
const ICED_LOGO: char = A::ICED_LOGO;
fn default_font(&self) -> Self::Font {
delegate!(self, renderer, renderer.default_font())
}
fn default_size(&self) -> core::Pixels {
delegate!(self, renderer, renderer.default_size())
}
fn fill_paragraph(
&mut self,
text: &Self::Paragraph,
position: Point,
color: Color,
clip_bounds: Rectangle,
) {
delegate!(
self,
renderer,
renderer.fill_paragraph(text, position, color, clip_bounds)
);
}
fn fill_editor(
&mut self,
editor: &Self::Editor,
position: Point,
color: Color,
clip_bounds: Rectangle,
) {
delegate!(
self,
renderer,
renderer.fill_editor(editor, position, color, clip_bounds)
);
}
fn fill_text(
&mut self,
text: core::Text<String, Self::Font>,
position: Point,
color: Color,
clip_bounds: Rectangle,
) {
delegate!(
self,
renderer,
renderer.fill_text(text, position, color, clip_bounds)
);
}
}
impl<A, B> text::Renderer for Renderer<A, B>
where
A: text::Renderer,
B: text::Renderer,
{
fn fill_raw(&mut self, raw: text::Raw) {
delegate!(self, renderer, renderer.fill_raw(raw));
}
}
impl<A, B> image::Renderer for Renderer<A, B>
where
A: image::Renderer,
B: image::Renderer<Handle = A::Handle>,
{
type Handle = A::Handle;
fn load_image(&self, handle: &Self::Handle) -> Result<image::Allocation, image::Error> {
delegate!(self, renderer, renderer.load_image(handle))
}
fn measure_image(&self, handle: &Self::Handle) -> Option<Size<u32>> {
delegate!(self, renderer, renderer.measure_image(handle))
}
fn draw_image(&mut self, image: Image<A::Handle>, bounds: Rectangle, clip_bounds: Rectangle) {
delegate!(
self,
renderer,
renderer.draw_image(image, bounds, clip_bounds)
);
}
}
impl<A, B> svg::Renderer for Renderer<A, B>
where
A: svg::Renderer,
B: svg::Renderer,
{
fn measure_svg(&self, handle: &svg::Handle) -> Size<u32> {
delegate!(self, renderer, renderer.measure_svg(handle))
}
fn draw_svg(&mut self, svg: Svg, bounds: Rectangle, clip_bounds: Rectangle) {
delegate!(self, renderer, renderer.draw_svg(svg, bounds, clip_bounds));
}
}
impl<A, B> mesh::Renderer for Renderer<A, B>
where
A: mesh::Renderer,
B: mesh::Renderer,
{
fn draw_mesh(&mut self, mesh: graphics::Mesh) {
delegate!(self, renderer, renderer.draw_mesh(mesh));
}
fn draw_mesh_cache(&mut self, cache: mesh::Cache) {
delegate!(self, renderer, renderer.draw_mesh_cache(cache));
}
}
#[derive(Debug)]
pub enum Compositor<A, B>
where
A: graphics::Compositor,
B: graphics::Compositor,
{
Primary(A),
Secondary(B),
}
#[derive(Debug)]
pub enum Surface<A, B> {
Primary(A),
Secondary(B),
}
impl<A, B> graphics::Compositor for Compositor<A, B>
where
A: graphics::Compositor,
B: graphics::Compositor,
{
type Renderer = Renderer<A::Renderer, B::Renderer>;
type Surface = Surface<A::Surface, B::Surface>;
async fn with_backend(
settings: compositor::Settings,
display: impl compositor::Display + Clone,
compatible_window: impl compositor::Window + Clone,
shell: Shell,
backend: Option<&str>,
) -> Result<Self, graphics::Error> {
use std::env;
let backends = backend
.map(str::to_owned)
.or_else(|| env::var("ICED_BACKEND").ok());
let mut candidates: Vec<_> = backends
.map(|backends| {
backends
.split(',')
.filter(|candidate| !candidate.is_empty())
.map(str::to_owned)
.map(Some)
.collect()
})
.unwrap_or_default();
if candidates.is_empty() {
candidates.push(None);
}
let mut errors = vec![];
for backend in candidates.iter().map(Option::as_deref) {
match A::with_backend(
settings,
display.clone(),
compatible_window.clone(),
shell.clone(),
backend,
)
.await
{
Ok(compositor) => return Ok(Self::Primary(compositor)),
Err(error) => {
errors.push(error);
}
}
match B::with_backend(
settings,
display.clone(),
compatible_window.clone(),
shell.clone(),
backend,
)
.await
{
Ok(compositor) => return Ok(Self::Secondary(compositor)),
Err(error) => {
errors.push(error);
}
}
}
Err(graphics::Error::List(errors))
}
fn create_renderer(&self, settings: renderer::Settings) -> Self::Renderer {
match self {
Self::Primary(compositor) => Renderer::Primary(compositor.create_renderer(settings)),
Self::Secondary(compositor) => {
Renderer::Secondary(compositor.create_renderer(settings))
}
}
}
fn create_surface<W: compositor::Window + Clone>(
&mut self,
window: W,
width: u32,
height: u32,
) -> Self::Surface {
match self {
Self::Primary(compositor) => {
Surface::Primary(compositor.create_surface(window, width, height))
}
Self::Secondary(compositor) => {
Surface::Secondary(compositor.create_surface(window, width, height))
}
}
}
fn configure_surface(&mut self, surface: &mut Self::Surface, width: u32, height: u32) {
match (self, surface) {
(Self::Primary(compositor), Surface::Primary(surface)) => {
compositor.configure_surface(surface, width, height);
}
(Self::Secondary(compositor), Surface::Secondary(surface)) => {
compositor.configure_surface(surface, width, height);
}
_ => unreachable!(),
}
}
fn load_font(&mut self, font: Cow<'static, [u8]>) -> Result<(), font::Error> {
delegate!(self, compositor, compositor.load_font(font))
}
fn list_fonts(&mut self) -> Result<Vec<font::Family>, font::Error> {
delegate!(self, compositor, compositor.list_fonts())
}
fn information(&self) -> compositor::Information {
delegate!(self, compositor, compositor.information())
}
fn present(
&mut self,
renderer: &mut Self::Renderer,
surface: &mut Self::Surface,
viewport: &graphics::Viewport,
background_color: Color,
on_pre_present: impl FnOnce(),
) -> Result<(), compositor::SurfaceError> {
match (self, renderer, surface) {
(Self::Primary(compositor), Renderer::Primary(renderer), Surface::Primary(surface)) => {
compositor.present(
renderer,
surface,
viewport,
background_color,
on_pre_present,
)
}
(
Self::Secondary(compositor),
Renderer::Secondary(renderer),
Surface::Secondary(surface),
) => compositor.present(
renderer,
surface,
viewport,
background_color,
on_pre_present,
),
_ => unreachable!(),
}
}
fn screenshot(
&mut self,
renderer: &mut Self::Renderer,
viewport: &graphics::Viewport,
background_color: Color,
) -> Vec<u8> {
match (self, renderer) {
(Self::Primary(compositor), Renderer::Primary(renderer)) => {
compositor.screenshot(renderer, viewport, background_color)
}
(Self::Secondary(compositor), Renderer::Secondary(renderer)) => {
compositor.screenshot(renderer, viewport, background_color)
}
_ => unreachable!(),
}
}
}
#[cfg(feature = "wgpu-bare")]
impl<A, B> iced_wgpu::primitive::Renderer for Renderer<A, B>
where
A: iced_wgpu::primitive::Renderer,
B: core::Renderer,
{
fn draw_primitive(&mut self, bounds: Rectangle, primitive: impl iced_wgpu::Primitive) {
match self {
Self::Primary(renderer) => {
renderer.draw_primitive(bounds, primitive);
}
Self::Secondary(_) => {
log::warn!("Custom shader primitive is not supported with this renderer.");
}
}
}
}
#[cfg(feature = "geometry")]
mod geometry {
use super::Renderer;
use crate::core::{Point, Radians, Rectangle, Size, Svg, Vector};
use crate::graphics::cache::{self, Cached};
use crate::graphics::geometry::{self, Fill, Image, Path, Stroke, Text};
impl<A, B> geometry::Renderer for Renderer<A, B>
where
A: geometry::Renderer,
B: geometry::Renderer,
{
type Geometry = Geometry<A::Geometry, B::Geometry>;
type Frame = Frame<A::Frame, B::Frame>;
fn new_frame(&self, bounds: Rectangle) -> Self::Frame {
match self {
Self::Primary(renderer) => Frame::Primary(renderer.new_frame(bounds)),
Self::Secondary(renderer) => Frame::Secondary(renderer.new_frame(bounds)),
}
}
fn draw_geometry(&mut self, geometry: Self::Geometry) {
match (self, geometry) {
(Self::Primary(renderer), Geometry::Primary(geometry)) => {
renderer.draw_geometry(geometry);
}
(Self::Secondary(renderer), Geometry::Secondary(geometry)) => {
renderer.draw_geometry(geometry);
}
_ => unreachable!(),
}
}
}
#[derive(Debug, Clone)]
pub enum Geometry<A, B> {
Primary(A),
Secondary(B),
}
impl<A, B> Cached for Geometry<A, B>
where
A: Cached,
B: Cached,
{
type Cache = Geometry<A::Cache, B::Cache>;
fn load(cache: &Self::Cache) -> Self {
match cache {
Geometry::Primary(cache) => Self::Primary(A::load(cache)),
Geometry::Secondary(cache) => Self::Secondary(B::load(cache)),
}
}
fn cache(self, group: cache::Group, previous: Option<Self::Cache>) -> Self::Cache {
match (self, previous) {
(Self::Primary(geometry), Some(Geometry::Primary(previous))) => {
Geometry::Primary(geometry.cache(group, Some(previous)))
}
(Self::Primary(geometry), None) => Geometry::Primary(geometry.cache(group, None)),
(Self::Secondary(geometry), Some(Geometry::Secondary(previous))) => {
Geometry::Secondary(geometry.cache(group, Some(previous)))
}
(Self::Secondary(geometry), None) => {
Geometry::Secondary(geometry.cache(group, None))
}
_ => unreachable!(),
}
}
}
#[derive(Debug)]
pub enum Frame<A, B> {
Primary(A),
Secondary(B),
}
impl<A, B> geometry::frame::Backend for Frame<A, B>
where
A: geometry::frame::Backend,
B: geometry::frame::Backend,
{
type Geometry = Geometry<A::Geometry, B::Geometry>;
fn width(&self) -> f32 {
delegate!(self, frame, frame.width())
}
fn height(&self) -> f32 {
delegate!(self, frame, frame.height())
}
fn size(&self) -> Size {
delegate!(self, frame, frame.size())
}
fn center(&self) -> Point {
delegate!(self, frame, frame.center())
}
fn fill(&mut self, path: &Path, fill: impl Into<Fill>) {
delegate!(self, frame, frame.fill(path, fill));
}
fn fill_rectangle(&mut self, top_left: Point, size: Size, fill: impl Into<Fill>) {
delegate!(self, frame, frame.fill_rectangle(top_left, size, fill));
}
fn stroke<'a>(&mut self, path: &Path, stroke: impl Into<Stroke<'a>>) {
delegate!(self, frame, frame.stroke(path, stroke));
}
fn stroke_rectangle<'a>(
&mut self,
top_left: Point,
size: Size,
stroke: impl Into<Stroke<'a>>,
) {
delegate!(self, frame, frame.stroke_rectangle(top_left, size, stroke));
}
fn stroke_text<'a>(&mut self, text: impl Into<Text>, stroke: impl Into<Stroke<'a>>) {
delegate!(self, frame, frame.stroke_text(text, stroke));
}
fn fill_text(&mut self, text: impl Into<Text>) {
delegate!(self, frame, frame.fill_text(text));
}
fn draw_image(&mut self, bounds: Rectangle, image: impl Into<Image>) {
delegate!(self, frame, frame.draw_image(bounds, image));
}
fn draw_svg(&mut self, bounds: Rectangle, svg: impl Into<Svg>) {
delegate!(self, frame, frame.draw_svg(bounds, svg));
}
fn push_transform(&mut self) {
delegate!(self, frame, frame.push_transform());
}
fn pop_transform(&mut self) {
delegate!(self, frame, frame.pop_transform());
}
fn draft(&mut self, bounds: Rectangle) -> Self {
match self {
Self::Primary(frame) => Self::Primary(frame.draft(bounds)),
Self::Secondary(frame) => Self::Secondary(frame.draft(bounds)),
}
}
fn paste(&mut self, frame: Self) {
match (self, frame) {
(Self::Primary(target), Self::Primary(source)) => {
target.paste(source);
}
(Self::Secondary(target), Self::Secondary(source)) => {
target.paste(source);
}
_ => unreachable!(),
}
}
fn translate(&mut self, translation: Vector) {
delegate!(self, frame, frame.translate(translation));
}
fn rotate(&mut self, angle: impl Into<Radians>) {
delegate!(self, frame, frame.rotate(angle));
}
fn scale(&mut self, scale: impl Into<f32>) {
delegate!(self, frame, frame.scale(scale));
}
fn scale_nonuniform(&mut self, scale: impl Into<Vector>) {
delegate!(self, frame, frame.scale_nonuniform(scale));
}
fn into_geometry(self) -> Self::Geometry {
match self {
Frame::Primary(frame) => Geometry::Primary(frame.into_geometry()),
Frame::Secondary(frame) => Geometry::Secondary(frame.into_geometry()),
}
}
}
}
impl<A, B> renderer::Headless for Renderer<A, B>
where
A: renderer::Headless,
B: renderer::Headless,
{
async fn new(settings: renderer::Settings, backend: Option<&str>) -> Option<Self> {
if let Some(renderer) = A::new(settings, backend).await {
return Some(Self::Primary(renderer));
}
B::new(settings, backend).await.map(Self::Secondary)
}
fn name(&self) -> String {
delegate!(self, renderer, renderer.name())
}
fn screenshot(
&mut self,
size: Size<u32>,
scale_factor: f32,
background_color: Color,
) -> Vec<u8> {
match self {
crate::fallback::Renderer::Primary(renderer) => {
renderer.screenshot(size, scale_factor, background_color)
}
crate::fallback::Renderer::Secondary(renderer) => {
renderer.screenshot(size, scale_factor, background_color)
}
}
}
}
impl<A, B> compositor::Default for Renderer<A, B>
where
A: compositor::Default,
B: compositor::Default,
{
type Compositor = Compositor<A::Compositor, B::Compositor>;
}