Merge branch 'master' into beacon
This commit is contained in:
commit
aaf396256e
284 changed files with 18747 additions and 15450 deletions
|
|
@ -10,19 +10,24 @@ homepage.workspace = true
|
|||
categories.workspace = true
|
||||
keywords.workspace = true
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[features]
|
||||
wgpu = ["iced_wgpu"]
|
||||
image = ["iced_tiny_skia/image", "iced_wgpu?/image"]
|
||||
svg = ["iced_tiny_skia/svg", "iced_wgpu?/svg"]
|
||||
geometry = ["iced_graphics/geometry", "iced_tiny_skia/geometry", "iced_wgpu?/geometry"]
|
||||
tracing = ["iced_wgpu?/tracing"]
|
||||
tiny-skia = ["iced_tiny_skia"]
|
||||
image = ["iced_tiny_skia?/image", "iced_wgpu?/image"]
|
||||
svg = ["iced_tiny_skia?/svg", "iced_wgpu?/svg"]
|
||||
geometry = ["iced_graphics/geometry", "iced_tiny_skia?/geometry", "iced_wgpu?/geometry"]
|
||||
web-colors = ["iced_wgpu?/web-colors"]
|
||||
webgl = ["iced_wgpu?/webgl"]
|
||||
fira-sans = ["iced_graphics/fira-sans"]
|
||||
|
||||
[dependencies]
|
||||
iced_graphics.workspace = true
|
||||
|
||||
iced_tiny_skia.workspace = true
|
||||
iced_tiny_skia.optional = true
|
||||
|
||||
iced_wgpu.workspace = true
|
||||
iced_wgpu.optional = true
|
||||
|
|
|
|||
|
|
@ -1,259 +0,0 @@
|
|||
use crate::core::Color;
|
||||
use crate::graphics::compositor::{Information, SurfaceError, Window};
|
||||
use crate::graphics::{Error, Viewport};
|
||||
use crate::{Renderer, Settings};
|
||||
|
||||
use std::env;
|
||||
|
||||
pub enum Compositor {
|
||||
TinySkia(iced_tiny_skia::window::Compositor),
|
||||
#[cfg(feature = "wgpu")]
|
||||
Wgpu(iced_wgpu::window::Compositor),
|
||||
}
|
||||
|
||||
pub enum Surface {
|
||||
TinySkia(iced_tiny_skia::window::Surface),
|
||||
#[cfg(feature = "wgpu")]
|
||||
Wgpu(iced_wgpu::window::Surface<'static>),
|
||||
}
|
||||
|
||||
impl crate::graphics::Compositor for Compositor {
|
||||
type Settings = Settings;
|
||||
type Renderer = Renderer;
|
||||
type Surface = Surface;
|
||||
|
||||
fn new<W: Window + Clone>(
|
||||
settings: Self::Settings,
|
||||
compatible_window: W,
|
||||
) -> Result<Self, Error> {
|
||||
let candidates =
|
||||
Candidate::list_from_env().unwrap_or(Candidate::default_list());
|
||||
|
||||
let mut error = Error::GraphicsAdapterNotFound;
|
||||
|
||||
for candidate in candidates {
|
||||
match candidate.build(settings, compatible_window.clone()) {
|
||||
Ok(compositor) => return Ok(compositor),
|
||||
Err(new_error) => {
|
||||
error = new_error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Err(error)
|
||||
}
|
||||
|
||||
fn create_renderer(&self) -> Self::Renderer {
|
||||
match self {
|
||||
Compositor::TinySkia(compositor) => {
|
||||
Renderer::TinySkia(compositor.create_renderer())
|
||||
}
|
||||
#[cfg(feature = "wgpu")]
|
||||
Compositor::Wgpu(compositor) => {
|
||||
Renderer::Wgpu(compositor.create_renderer())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn create_surface<W: Window + Clone>(
|
||||
&mut self,
|
||||
window: W,
|
||||
width: u32,
|
||||
height: u32,
|
||||
) -> Surface {
|
||||
match self {
|
||||
Self::TinySkia(compositor) => Surface::TinySkia(
|
||||
compositor.create_surface(window, width, height),
|
||||
),
|
||||
#[cfg(feature = "wgpu")]
|
||||
Self::Wgpu(compositor) => {
|
||||
Surface::Wgpu(compositor.create_surface(window, width, height))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn configure_surface(
|
||||
&mut self,
|
||||
surface: &mut Surface,
|
||||
width: u32,
|
||||
height: u32,
|
||||
) {
|
||||
match (self, surface) {
|
||||
(Self::TinySkia(compositor), Surface::TinySkia(surface)) => {
|
||||
compositor.configure_surface(surface, width, height);
|
||||
}
|
||||
#[cfg(feature = "wgpu")]
|
||||
(Self::Wgpu(compositor), Surface::Wgpu(surface)) => {
|
||||
compositor.configure_surface(surface, width, height);
|
||||
}
|
||||
#[allow(unreachable_patterns)]
|
||||
_ => panic!(
|
||||
"The provided surface is not compatible with the compositor."
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
fn fetch_information(&self) -> Information {
|
||||
match self {
|
||||
Self::TinySkia(compositor) => compositor.fetch_information(),
|
||||
#[cfg(feature = "wgpu")]
|
||||
Self::Wgpu(compositor) => compositor.fetch_information(),
|
||||
}
|
||||
}
|
||||
|
||||
fn present(
|
||||
&mut self,
|
||||
renderer: &mut Self::Renderer,
|
||||
surface: &mut Self::Surface,
|
||||
viewport: &Viewport,
|
||||
background_color: Color,
|
||||
) -> Result<(), SurfaceError> {
|
||||
match (self, renderer, surface) {
|
||||
(
|
||||
Self::TinySkia(_compositor),
|
||||
crate::Renderer::TinySkia(renderer),
|
||||
Surface::TinySkia(surface),
|
||||
) => renderer.with_primitives(|backend, primitives| {
|
||||
iced_tiny_skia::window::compositor::present(
|
||||
backend,
|
||||
surface,
|
||||
primitives,
|
||||
viewport,
|
||||
background_color,
|
||||
)
|
||||
}),
|
||||
#[cfg(feature = "wgpu")]
|
||||
(
|
||||
Self::Wgpu(compositor),
|
||||
crate::Renderer::Wgpu(renderer),
|
||||
Surface::Wgpu(surface),
|
||||
) => renderer.with_primitives(|backend, primitives| {
|
||||
iced_wgpu::window::compositor::present(
|
||||
compositor,
|
||||
backend,
|
||||
surface,
|
||||
primitives,
|
||||
viewport,
|
||||
background_color,
|
||||
)
|
||||
}),
|
||||
#[allow(unreachable_patterns)]
|
||||
_ => panic!(
|
||||
"The provided renderer or surface are not compatible \
|
||||
with the compositor."
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
fn screenshot(
|
||||
&mut self,
|
||||
renderer: &mut Self::Renderer,
|
||||
surface: &mut Self::Surface,
|
||||
viewport: &Viewport,
|
||||
background_color: Color,
|
||||
) -> Vec<u8> {
|
||||
match (self, renderer, surface) {
|
||||
(
|
||||
Self::TinySkia(_compositor),
|
||||
Renderer::TinySkia(renderer),
|
||||
Surface::TinySkia(surface),
|
||||
) => renderer.with_primitives(|backend, primitives| {
|
||||
iced_tiny_skia::window::compositor::screenshot(
|
||||
surface,
|
||||
backend,
|
||||
primitives,
|
||||
viewport,
|
||||
background_color,
|
||||
)
|
||||
}),
|
||||
#[cfg(feature = "wgpu")]
|
||||
(
|
||||
Self::Wgpu(compositor),
|
||||
Renderer::Wgpu(renderer),
|
||||
Surface::Wgpu(_),
|
||||
) => renderer.with_primitives(|backend, primitives| {
|
||||
iced_wgpu::window::compositor::screenshot(
|
||||
compositor,
|
||||
backend,
|
||||
primitives,
|
||||
viewport,
|
||||
background_color,
|
||||
)
|
||||
}),
|
||||
#[allow(unreachable_patterns)]
|
||||
_ => panic!(
|
||||
"The provided renderer or backend are not compatible \
|
||||
with the compositor."
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum Candidate {
|
||||
Wgpu,
|
||||
TinySkia,
|
||||
}
|
||||
|
||||
impl Candidate {
|
||||
fn default_list() -> Vec<Self> {
|
||||
vec![
|
||||
#[cfg(feature = "wgpu")]
|
||||
Self::Wgpu,
|
||||
Self::TinySkia,
|
||||
]
|
||||
}
|
||||
|
||||
fn list_from_env() -> Option<Vec<Self>> {
|
||||
let backends = env::var("ICED_BACKEND").ok()?;
|
||||
|
||||
Some(
|
||||
backends
|
||||
.split(',')
|
||||
.map(str::trim)
|
||||
.map(|backend| match backend {
|
||||
"wgpu" => Self::Wgpu,
|
||||
"tiny-skia" => Self::TinySkia,
|
||||
_ => panic!("unknown backend value: \"{backend}\""),
|
||||
})
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
|
||||
fn build<W: Window>(
|
||||
self,
|
||||
settings: Settings,
|
||||
_compatible_window: W,
|
||||
) -> Result<Compositor, Error> {
|
||||
match self {
|
||||
Self::TinySkia => {
|
||||
let compositor = iced_tiny_skia::window::compositor::new(
|
||||
iced_tiny_skia::Settings {
|
||||
default_font: settings.default_font,
|
||||
default_text_size: settings.default_text_size,
|
||||
},
|
||||
_compatible_window,
|
||||
);
|
||||
|
||||
Ok(Compositor::TinySkia(compositor))
|
||||
}
|
||||
#[cfg(feature = "wgpu")]
|
||||
Self::Wgpu => {
|
||||
let compositor = iced_wgpu::window::compositor::new(
|
||||
iced_wgpu::Settings {
|
||||
default_font: settings.default_font,
|
||||
default_text_size: settings.default_text_size,
|
||||
antialiasing: settings.antialiasing,
|
||||
..iced_wgpu::Settings::from_env()
|
||||
},
|
||||
_compatible_window,
|
||||
)?;
|
||||
|
||||
Ok(Compositor::Wgpu(compositor))
|
||||
}
|
||||
#[cfg(not(feature = "wgpu"))]
|
||||
Self::Wgpu => {
|
||||
panic!("`wgpu` feature was not enabled in `iced_renderer`")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
631
renderer/src/fallback.rs
Normal file
631
renderer/src/fallback.rs
Normal file
|
|
@ -0,0 +1,631 @@
|
|||
//! Compose existing renderers and create type-safe fallback strategies.
|
||||
use crate::core::image;
|
||||
use crate::core::renderer;
|
||||
use crate::core::svg;
|
||||
use crate::core::{
|
||||
self, Background, Color, Point, Radians, Rectangle, Size, Transformation,
|
||||
};
|
||||
use crate::graphics;
|
||||
use crate::graphics::compositor;
|
||||
use crate::graphics::mesh;
|
||||
|
||||
use std::borrow::Cow;
|
||||
|
||||
/// A renderer `A` with a fallback strategy `B`.
|
||||
///
|
||||
/// This type can be used to easily compose existing renderers and
|
||||
/// create custom, type-safe fallback strategies.
|
||||
#[derive(Debug)]
|
||||
pub enum Renderer<A, B> {
|
||||
/// The primary rendering option.
|
||||
Primary(A),
|
||||
/// The secondary (or fallback) rendering option.
|
||||
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 clear(&mut self) {
|
||||
delegate!(self, renderer, renderer.clear());
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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> image::Renderer for Renderer<A, B>
|
||||
where
|
||||
A: image::Renderer,
|
||||
B: image::Renderer<Handle = A::Handle>,
|
||||
{
|
||||
type Handle = A::Handle;
|
||||
|
||||
fn measure_image(&self, handle: &Self::Handle) -> Size<u32> {
|
||||
delegate!(self, renderer, renderer.measure_image(handle))
|
||||
}
|
||||
|
||||
fn draw_image(
|
||||
&mut self,
|
||||
handle: Self::Handle,
|
||||
filter_method: image::FilterMethod,
|
||||
bounds: Rectangle,
|
||||
rotation: Radians,
|
||||
opacity: f32,
|
||||
) {
|
||||
delegate!(
|
||||
self,
|
||||
renderer,
|
||||
renderer.draw_image(
|
||||
handle,
|
||||
filter_method,
|
||||
bounds,
|
||||
rotation,
|
||||
opacity
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
handle: svg::Handle,
|
||||
color: Option<Color>,
|
||||
bounds: Rectangle,
|
||||
rotation: Radians,
|
||||
opacity: f32,
|
||||
) {
|
||||
delegate!(
|
||||
self,
|
||||
renderer,
|
||||
renderer.draw_svg(handle, color, bounds, rotation, opacity)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
/// A compositor `A` with a fallback strategy `B`.
|
||||
///
|
||||
/// It works analogously to [`Renderer`].
|
||||
#[derive(Debug)]
|
||||
pub enum Compositor<A, B>
|
||||
where
|
||||
A: graphics::Compositor,
|
||||
B: graphics::Compositor,
|
||||
{
|
||||
/// The primary compositing option.
|
||||
Primary(A),
|
||||
/// The secondary (or fallback) compositing option.
|
||||
Secondary(B),
|
||||
}
|
||||
|
||||
/// A surface `A` with a fallback strategy `B`.
|
||||
///
|
||||
/// It works analogously to [`Renderer`].
|
||||
#[derive(Debug)]
|
||||
pub enum Surface<A, B> {
|
||||
/// The primary surface option.
|
||||
Primary(A),
|
||||
/// The secondary (or fallback) surface option.
|
||||
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<W: compositor::Window + Clone>(
|
||||
settings: graphics::Settings,
|
||||
compatible_window: W,
|
||||
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, compatible_window.clone(), backend)
|
||||
.await
|
||||
{
|
||||
Ok(compositor) => return Ok(Self::Primary(compositor)),
|
||||
Err(error) => {
|
||||
errors.push(error);
|
||||
}
|
||||
}
|
||||
|
||||
match B::with_backend(settings, compatible_window.clone(), backend)
|
||||
.await
|
||||
{
|
||||
Ok(compositor) => return Ok(Self::Secondary(compositor)),
|
||||
Err(error) => {
|
||||
errors.push(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Err(graphics::Error::List(errors))
|
||||
}
|
||||
|
||||
fn create_renderer(&self) -> Self::Renderer {
|
||||
match self {
|
||||
Self::Primary(compositor) => {
|
||||
Renderer::Primary(compositor.create_renderer())
|
||||
}
|
||||
Self::Secondary(compositor) => {
|
||||
Renderer::Secondary(compositor.create_renderer())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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]>) {
|
||||
delegate!(self, compositor, compositor.load_font(font));
|
||||
}
|
||||
|
||||
fn fetch_information(&self) -> compositor::Information {
|
||||
delegate!(self, compositor, compositor.fetch_information())
|
||||
}
|
||||
|
||||
fn present(
|
||||
&mut self,
|
||||
renderer: &mut Self::Renderer,
|
||||
surface: &mut Self::Surface,
|
||||
viewport: &graphics::Viewport,
|
||||
background_color: Color,
|
||||
) -> Result<(), compositor::SurfaceError> {
|
||||
match (self, renderer, surface) {
|
||||
(
|
||||
Self::Primary(compositor),
|
||||
Renderer::Primary(renderer),
|
||||
Surface::Primary(surface),
|
||||
) => compositor.present(
|
||||
renderer,
|
||||
surface,
|
||||
viewport,
|
||||
background_color,
|
||||
),
|
||||
(
|
||||
Self::Secondary(compositor),
|
||||
Renderer::Secondary(renderer),
|
||||
Surface::Secondary(surface),
|
||||
) => compositor.present(
|
||||
renderer,
|
||||
surface,
|
||||
viewport,
|
||||
background_color,
|
||||
),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn screenshot(
|
||||
&mut self,
|
||||
renderer: &mut Self::Renderer,
|
||||
surface: &mut Self::Surface,
|
||||
viewport: &graphics::Viewport,
|
||||
background_color: Color,
|
||||
) -> Vec<u8> {
|
||||
match (self, renderer, surface) {
|
||||
(
|
||||
Self::Primary(compositor),
|
||||
Renderer::Primary(renderer),
|
||||
Surface::Primary(surface),
|
||||
) => compositor.screenshot(
|
||||
renderer,
|
||||
surface,
|
||||
viewport,
|
||||
background_color,
|
||||
),
|
||||
(
|
||||
Self::Secondary(compositor),
|
||||
Renderer::Secondary(renderer),
|
||||
Surface::Secondary(surface),
|
||||
) => compositor.screenshot(
|
||||
renderer,
|
||||
surface,
|
||||
viewport,
|
||||
background_color,
|
||||
),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "wgpu")]
|
||||
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, Vector};
|
||||
use crate::graphics::cache::{self, Cached};
|
||||
use crate::graphics::geometry::{self, Fill, 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, size: iced_graphics::core::Size) -> Self::Frame {
|
||||
match self {
|
||||
Self::Primary(renderer) => {
|
||||
Frame::Primary(renderer.new_frame(size))
|
||||
}
|
||||
Self::Secondary(renderer) => {
|
||||
Frame::Secondary(renderer.new_frame(size))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 fill_text(&mut self, text: impl Into<Text>) {
|
||||
delegate!(self, frame, frame.fill_text(text));
|
||||
}
|
||||
|
||||
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, at: Point) {
|
||||
match (self, frame) {
|
||||
(Self::Primary(target), Self::Primary(source)) => {
|
||||
target.paste(source, at);
|
||||
}
|
||||
(Self::Secondary(target), Self::Secondary(source)) => {
|
||||
target.paste(source, at);
|
||||
}
|
||||
_ => 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> compositor::Default for Renderer<A, B>
|
||||
where
|
||||
A: compositor::Default,
|
||||
B: compositor::Default,
|
||||
{
|
||||
type Compositor = Compositor<A::Compositor, B::Compositor>;
|
||||
}
|
||||
|
|
@ -1,210 +0,0 @@
|
|||
mod cache;
|
||||
|
||||
pub use cache::Cache;
|
||||
|
||||
use crate::core::{Point, Rectangle, Size, Transformation, Vector};
|
||||
use crate::graphics::geometry::{Fill, Path, Stroke, Text};
|
||||
use crate::Renderer;
|
||||
|
||||
macro_rules! delegate {
|
||||
($frame:expr, $name:ident, $body:expr) => {
|
||||
match $frame {
|
||||
Self::TinySkia($name) => $body,
|
||||
#[cfg(feature = "wgpu")]
|
||||
Self::Wgpu($name) => $body,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub enum Geometry {
|
||||
TinySkia(iced_tiny_skia::Primitive),
|
||||
#[cfg(feature = "wgpu")]
|
||||
Wgpu(iced_wgpu::Primitive),
|
||||
}
|
||||
|
||||
impl Geometry {
|
||||
pub fn transform(self, transformation: Transformation) -> Self {
|
||||
match self {
|
||||
Self::TinySkia(primitive) => {
|
||||
Self::TinySkia(primitive.transform(transformation))
|
||||
}
|
||||
#[cfg(feature = "wgpu")]
|
||||
Self::Wgpu(primitive) => {
|
||||
Self::Wgpu(primitive.transform(transformation))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub enum Frame {
|
||||
TinySkia(iced_tiny_skia::geometry::Frame),
|
||||
#[cfg(feature = "wgpu")]
|
||||
Wgpu(iced_wgpu::geometry::Frame),
|
||||
}
|
||||
|
||||
impl Frame {
|
||||
pub fn new(renderer: &Renderer, size: Size) -> Self {
|
||||
match renderer {
|
||||
Renderer::TinySkia(_) => {
|
||||
Frame::TinySkia(iced_tiny_skia::geometry::Frame::new(size))
|
||||
}
|
||||
#[cfg(feature = "wgpu")]
|
||||
Renderer::Wgpu(_) => {
|
||||
Frame::Wgpu(iced_wgpu::geometry::Frame::new(size))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the width of the [`Frame`].
|
||||
#[inline]
|
||||
pub fn width(&self) -> f32 {
|
||||
delegate!(self, frame, frame.width())
|
||||
}
|
||||
|
||||
/// Returns the height of the [`Frame`].
|
||||
#[inline]
|
||||
pub fn height(&self) -> f32 {
|
||||
delegate!(self, frame, frame.height())
|
||||
}
|
||||
|
||||
/// Returns the dimensions of the [`Frame`].
|
||||
#[inline]
|
||||
pub fn size(&self) -> Size {
|
||||
delegate!(self, frame, frame.size())
|
||||
}
|
||||
|
||||
/// Returns the coordinate of the center of the [`Frame`].
|
||||
#[inline]
|
||||
pub fn center(&self) -> Point {
|
||||
delegate!(self, frame, frame.center())
|
||||
}
|
||||
|
||||
/// Draws the given [`Path`] on the [`Frame`] by filling it with the
|
||||
/// provided style.
|
||||
pub fn fill(&mut self, path: &Path, fill: impl Into<Fill>) {
|
||||
delegate!(self, frame, frame.fill(path, fill));
|
||||
}
|
||||
|
||||
/// Draws an axis-aligned rectangle given its top-left corner coordinate and
|
||||
/// its `Size` on the [`Frame`] by filling it with the provided style.
|
||||
pub fn fill_rectangle(
|
||||
&mut self,
|
||||
top_left: Point,
|
||||
size: Size,
|
||||
fill: impl Into<Fill>,
|
||||
) {
|
||||
delegate!(self, frame, frame.fill_rectangle(top_left, size, fill));
|
||||
}
|
||||
|
||||
/// Draws the stroke of the given [`Path`] on the [`Frame`] with the
|
||||
/// provided style.
|
||||
pub fn stroke<'a>(&mut self, path: &Path, stroke: impl Into<Stroke<'a>>) {
|
||||
delegate!(self, frame, frame.stroke(path, stroke));
|
||||
}
|
||||
|
||||
/// Draws the characters of the given [`Text`] on the [`Frame`], filling
|
||||
/// them with the given color.
|
||||
///
|
||||
/// __Warning:__ Text currently does not work well with rotations and scale
|
||||
/// transforms! The position will be correctly transformed, but the
|
||||
/// resulting glyphs will not be rotated or scaled properly.
|
||||
///
|
||||
/// Additionally, all text will be rendered on top of all the layers of
|
||||
/// a `Canvas`. Therefore, it is currently only meant to be used for
|
||||
/// overlays, which is the most common use case.
|
||||
///
|
||||
/// Support for vectorial text is planned, and should address all these
|
||||
/// limitations.
|
||||
pub fn fill_text(&mut self, text: impl Into<Text>) {
|
||||
delegate!(self, frame, frame.fill_text(text));
|
||||
}
|
||||
|
||||
/// Stores the current transform of the [`Frame`] and executes the given
|
||||
/// drawing operations, restoring the transform afterwards.
|
||||
///
|
||||
/// This method is useful to compose transforms and perform drawing
|
||||
/// operations in different coordinate systems.
|
||||
#[inline]
|
||||
pub fn with_save<R>(&mut self, f: impl FnOnce(&mut Frame) -> R) -> R {
|
||||
delegate!(self, frame, frame.push_transform());
|
||||
|
||||
let result = f(self);
|
||||
|
||||
delegate!(self, frame, frame.pop_transform());
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
/// Executes the given drawing operations within a [`Rectangle`] region,
|
||||
/// clipping any geometry that overflows its bounds. Any transformations
|
||||
/// performed are local to the provided closure.
|
||||
///
|
||||
/// This method is useful to perform drawing operations that need to be
|
||||
/// clipped.
|
||||
#[inline]
|
||||
pub fn with_clip<R>(
|
||||
&mut self,
|
||||
region: Rectangle,
|
||||
f: impl FnOnce(&mut Frame) -> R,
|
||||
) -> R {
|
||||
let mut frame = match self {
|
||||
Self::TinySkia(_) => Self::TinySkia(
|
||||
iced_tiny_skia::geometry::Frame::new(region.size()),
|
||||
),
|
||||
#[cfg(feature = "wgpu")]
|
||||
Self::Wgpu(_) => {
|
||||
Self::Wgpu(iced_wgpu::geometry::Frame::new(region.size()))
|
||||
}
|
||||
};
|
||||
|
||||
let result = f(&mut frame);
|
||||
|
||||
let origin = Point::new(region.x, region.y);
|
||||
|
||||
match (self, frame) {
|
||||
(Self::TinySkia(target), Self::TinySkia(frame)) => {
|
||||
target.clip(frame, origin);
|
||||
}
|
||||
#[cfg(feature = "wgpu")]
|
||||
(Self::Wgpu(target), Self::Wgpu(frame)) => {
|
||||
target.clip(frame, origin);
|
||||
}
|
||||
#[allow(unreachable_patterns)]
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
/// Applies a translation to the current transform of the [`Frame`].
|
||||
#[inline]
|
||||
pub fn translate(&mut self, translation: Vector) {
|
||||
delegate!(self, frame, frame.translate(translation));
|
||||
}
|
||||
|
||||
/// Applies a rotation in radians to the current transform of the [`Frame`].
|
||||
#[inline]
|
||||
pub fn rotate(&mut self, angle: f32) {
|
||||
delegate!(self, frame, frame.rotate(angle));
|
||||
}
|
||||
|
||||
/// Applies a uniform scaling to the current transform of the [`Frame`].
|
||||
#[inline]
|
||||
pub fn scale(&mut self, scale: impl Into<f32>) {
|
||||
delegate!(self, frame, frame.scale(scale));
|
||||
}
|
||||
|
||||
/// Applies a non-uniform scaling to the current transform of the [`Frame`].
|
||||
#[inline]
|
||||
pub fn scale_nonuniform(&mut self, scale: impl Into<Vector>) {
|
||||
delegate!(self, frame, frame.scale_nonuniform(scale));
|
||||
}
|
||||
|
||||
pub fn into_geometry(self) -> Geometry {
|
||||
match self {
|
||||
Self::TinySkia(frame) => Geometry::TinySkia(frame.into_primitive()),
|
||||
#[cfg(feature = "wgpu")]
|
||||
Self::Wgpu(frame) => Geometry::Wgpu(frame.into_primitive()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,125 +0,0 @@
|
|||
use crate::core::Size;
|
||||
use crate::geometry::{Frame, Geometry};
|
||||
use crate::Renderer;
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::sync::Arc;
|
||||
|
||||
/// A simple cache that stores generated [`Geometry`] to avoid recomputation.
|
||||
///
|
||||
/// A [`Cache`] will not redraw its geometry unless the dimensions of its layer
|
||||
/// change or it is explicitly cleared.
|
||||
#[derive(Debug, Default)]
|
||||
pub struct Cache {
|
||||
state: RefCell<State>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
enum State {
|
||||
#[default]
|
||||
Empty,
|
||||
Filled {
|
||||
bounds: Size,
|
||||
primitive: Internal,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
enum Internal {
|
||||
TinySkia(Arc<iced_tiny_skia::Primitive>),
|
||||
#[cfg(feature = "wgpu")]
|
||||
Wgpu(Arc<iced_wgpu::Primitive>),
|
||||
}
|
||||
|
||||
impl Cache {
|
||||
/// Creates a new empty [`Cache`].
|
||||
pub fn new() -> Self {
|
||||
Cache {
|
||||
state: RefCell::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Clears the [`Cache`], forcing a redraw the next time it is used.
|
||||
pub fn clear(&self) {
|
||||
*self.state.borrow_mut() = State::Empty;
|
||||
}
|
||||
|
||||
/// Draws [`Geometry`] using the provided closure and stores it in the
|
||||
/// [`Cache`].
|
||||
///
|
||||
/// The closure will only be called when
|
||||
/// - the bounds have changed since the previous draw call.
|
||||
/// - the [`Cache`] is empty or has been explicitly cleared.
|
||||
///
|
||||
/// Otherwise, the previously stored [`Geometry`] will be returned. The
|
||||
/// [`Cache`] is not cleared in this case. In other words, it will keep
|
||||
/// returning the stored [`Geometry`] if needed.
|
||||
pub fn draw(
|
||||
&self,
|
||||
renderer: &Renderer,
|
||||
bounds: Size,
|
||||
draw_fn: impl FnOnce(&mut Frame),
|
||||
) -> Geometry {
|
||||
use std::ops::Deref;
|
||||
|
||||
if let State::Filled {
|
||||
bounds: cached_bounds,
|
||||
primitive,
|
||||
} = self.state.borrow().deref()
|
||||
{
|
||||
if *cached_bounds == bounds {
|
||||
match primitive {
|
||||
Internal::TinySkia(primitive) => {
|
||||
return Geometry::TinySkia(
|
||||
iced_tiny_skia::Primitive::Cache {
|
||||
content: primitive.clone(),
|
||||
},
|
||||
);
|
||||
}
|
||||
#[cfg(feature = "wgpu")]
|
||||
Internal::Wgpu(primitive) => {
|
||||
return Geometry::Wgpu(iced_wgpu::Primitive::Cache {
|
||||
content: primitive.clone(),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut frame = Frame::new(renderer, bounds);
|
||||
draw_fn(&mut frame);
|
||||
|
||||
let primitive = {
|
||||
let geometry = frame.into_geometry();
|
||||
|
||||
match geometry {
|
||||
Geometry::TinySkia(primitive) => {
|
||||
Internal::TinySkia(Arc::new(primitive))
|
||||
}
|
||||
#[cfg(feature = "wgpu")]
|
||||
Geometry::Wgpu(primitive) => {
|
||||
Internal::Wgpu(Arc::new(primitive))
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
*self.state.borrow_mut() = State::Filled {
|
||||
bounds,
|
||||
primitive: primitive.clone(),
|
||||
};
|
||||
|
||||
match primitive {
|
||||
Internal::TinySkia(primitive) => {
|
||||
Geometry::TinySkia(iced_tiny_skia::Primitive::Cache {
|
||||
content: primitive,
|
||||
})
|
||||
}
|
||||
#[cfg(feature = "wgpu")]
|
||||
Internal::Wgpu(primitive) => {
|
||||
Geometry::Wgpu(iced_wgpu::Primitive::Cache {
|
||||
content: primitive,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,302 +1,53 @@
|
|||
#![forbid(rust_2018_idioms)]
|
||||
#![deny(unsafe_code, unused_results, rustdoc::broken_intra_doc_links)]
|
||||
//! The official renderer for iced.
|
||||
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
|
||||
#[cfg(feature = "wgpu")]
|
||||
pub use iced_wgpu as wgpu;
|
||||
|
||||
pub mod compositor;
|
||||
|
||||
#[cfg(feature = "geometry")]
|
||||
pub mod geometry;
|
||||
|
||||
mod settings;
|
||||
pub mod fallback;
|
||||
|
||||
pub use iced_graphics as graphics;
|
||||
pub use iced_graphics::core;
|
||||
|
||||
pub use compositor::Compositor;
|
||||
pub use settings::Settings;
|
||||
|
||||
#[cfg(feature = "geometry")]
|
||||
pub use geometry::Geometry;
|
||||
|
||||
use crate::core::renderer;
|
||||
use crate::core::text::{self, Text};
|
||||
use crate::core::{
|
||||
Background, Color, Font, Pixels, Point, Rectangle, Transformation,
|
||||
};
|
||||
use crate::graphics::text::Editor;
|
||||
use crate::graphics::text::Paragraph;
|
||||
use crate::graphics::Mesh;
|
||||
|
||||
use std::borrow::Cow;
|
||||
pub use iced_graphics::geometry;
|
||||
|
||||
/// The default graphics renderer for [`iced`].
|
||||
///
|
||||
/// [`iced`]: https://github.com/iced-rs/iced
|
||||
pub enum Renderer {
|
||||
TinySkia(iced_tiny_skia::Renderer),
|
||||
#[cfg(feature = "wgpu")]
|
||||
Wgpu(iced_wgpu::Renderer),
|
||||
pub type Renderer = renderer::Renderer;
|
||||
|
||||
/// The default graphics compositor for [`iced`].
|
||||
///
|
||||
/// [`iced`]: https://github.com/iced-rs/iced
|
||||
pub type Compositor = renderer::Compositor;
|
||||
|
||||
#[cfg(all(feature = "wgpu", feature = "tiny-skia"))]
|
||||
mod renderer {
|
||||
pub type Renderer = crate::fallback::Renderer<
|
||||
iced_wgpu::Renderer,
|
||||
iced_tiny_skia::Renderer,
|
||||
>;
|
||||
|
||||
pub type Compositor = crate::fallback::Compositor<
|
||||
iced_wgpu::window::Compositor,
|
||||
iced_tiny_skia::window::Compositor,
|
||||
>;
|
||||
}
|
||||
|
||||
macro_rules! delegate {
|
||||
($renderer:expr, $name:ident, $body:expr) => {
|
||||
match $renderer {
|
||||
Self::TinySkia($name) => $body,
|
||||
#[cfg(feature = "wgpu")]
|
||||
Self::Wgpu($name) => $body,
|
||||
}
|
||||
};
|
||||
#[cfg(all(feature = "wgpu", not(feature = "tiny-skia")))]
|
||||
mod renderer {
|
||||
pub type Renderer = iced_wgpu::Renderer;
|
||||
pub type Compositor = iced_wgpu::window::Compositor;
|
||||
}
|
||||
|
||||
impl Renderer {
|
||||
pub fn draw_mesh(&mut self, mesh: Mesh) {
|
||||
match self {
|
||||
Self::TinySkia(_) => {
|
||||
log::warn!("Unsupported mesh primitive: {mesh:?}");
|
||||
}
|
||||
#[cfg(feature = "wgpu")]
|
||||
Self::Wgpu(renderer) => {
|
||||
renderer.draw_primitive(iced_wgpu::Primitive::Custom(
|
||||
iced_wgpu::primitive::Custom::Mesh(mesh),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(all(not(feature = "wgpu"), feature = "tiny-skia"))]
|
||||
mod renderer {
|
||||
pub type Renderer = iced_tiny_skia::Renderer;
|
||||
pub type Compositor = iced_tiny_skia::window::Compositor;
|
||||
}
|
||||
|
||||
impl core::Renderer for Renderer {
|
||||
fn with_layer(&mut self, bounds: Rectangle, f: impl FnOnce(&mut Self)) {
|
||||
match self {
|
||||
Self::TinySkia(renderer) => {
|
||||
let primitives = renderer.start_layer();
|
||||
|
||||
f(self);
|
||||
|
||||
match self {
|
||||
Self::TinySkia(renderer) => {
|
||||
renderer.end_layer(primitives, bounds);
|
||||
}
|
||||
#[cfg(feature = "wgpu")]
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "wgpu")]
|
||||
Self::Wgpu(renderer) => {
|
||||
let primitives = renderer.start_layer();
|
||||
|
||||
f(self);
|
||||
|
||||
match self {
|
||||
#[cfg(feature = "wgpu")]
|
||||
Self::Wgpu(renderer) => {
|
||||
renderer.end_layer(primitives, bounds);
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn with_transformation(
|
||||
&mut self,
|
||||
transformation: Transformation,
|
||||
f: impl FnOnce(&mut Self),
|
||||
) {
|
||||
match self {
|
||||
Self::TinySkia(renderer) => {
|
||||
let primitives = renderer.start_transformation();
|
||||
|
||||
f(self);
|
||||
|
||||
match self {
|
||||
Self::TinySkia(renderer) => {
|
||||
renderer.end_transformation(primitives, transformation);
|
||||
}
|
||||
#[cfg(feature = "wgpu")]
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "wgpu")]
|
||||
Self::Wgpu(renderer) => {
|
||||
let primitives = renderer.start_transformation();
|
||||
|
||||
f(self);
|
||||
|
||||
match self {
|
||||
#[cfg(feature = "wgpu")]
|
||||
Self::Wgpu(renderer) => {
|
||||
renderer.end_transformation(primitives, transformation);
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn fill_quad(
|
||||
&mut self,
|
||||
quad: renderer::Quad,
|
||||
background: impl Into<Background>,
|
||||
) {
|
||||
delegate!(self, renderer, renderer.fill_quad(quad, background));
|
||||
}
|
||||
|
||||
fn clear(&mut self) {
|
||||
delegate!(self, renderer, renderer.clear());
|
||||
}
|
||||
}
|
||||
|
||||
impl text::Renderer for Renderer {
|
||||
type Font = Font;
|
||||
type Paragraph = Paragraph;
|
||||
type Editor = Editor;
|
||||
|
||||
const ICON_FONT: Font = iced_tiny_skia::Renderer::ICON_FONT;
|
||||
const CHECKMARK_ICON: char = iced_tiny_skia::Renderer::CHECKMARK_ICON;
|
||||
const ARROW_DOWN_ICON: char = iced_tiny_skia::Renderer::ARROW_DOWN_ICON;
|
||||
|
||||
fn default_font(&self) -> Self::Font {
|
||||
delegate!(self, renderer, renderer.default_font())
|
||||
}
|
||||
|
||||
fn default_size(&self) -> Pixels {
|
||||
delegate!(self, renderer, renderer.default_size())
|
||||
}
|
||||
|
||||
fn load_font(&mut self, bytes: Cow<'static, [u8]>) {
|
||||
delegate!(self, renderer, renderer.load_font(bytes));
|
||||
}
|
||||
|
||||
fn fill_paragraph(
|
||||
&mut self,
|
||||
paragraph: &Self::Paragraph,
|
||||
position: Point,
|
||||
color: Color,
|
||||
clip_bounds: Rectangle,
|
||||
) {
|
||||
delegate!(
|
||||
self,
|
||||
renderer,
|
||||
renderer.fill_paragraph(paragraph, 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: Text<'_, Self::Font>,
|
||||
position: Point,
|
||||
color: Color,
|
||||
clip_bounds: Rectangle,
|
||||
) {
|
||||
delegate!(
|
||||
self,
|
||||
renderer,
|
||||
renderer.fill_text(text, position, color, clip_bounds)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "image")]
|
||||
impl crate::core::image::Renderer for Renderer {
|
||||
type Handle = crate::core::image::Handle;
|
||||
|
||||
fn dimensions(
|
||||
&self,
|
||||
handle: &crate::core::image::Handle,
|
||||
) -> core::Size<u32> {
|
||||
delegate!(self, renderer, renderer.dimensions(handle))
|
||||
}
|
||||
|
||||
fn draw(
|
||||
&mut self,
|
||||
handle: crate::core::image::Handle,
|
||||
filter_method: crate::core::image::FilterMethod,
|
||||
bounds: Rectangle,
|
||||
) {
|
||||
delegate!(self, renderer, renderer.draw(handle, filter_method, bounds));
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "svg")]
|
||||
impl crate::core::svg::Renderer for Renderer {
|
||||
fn dimensions(&self, handle: &crate::core::svg::Handle) -> core::Size<u32> {
|
||||
delegate!(self, renderer, renderer.dimensions(handle))
|
||||
}
|
||||
|
||||
fn draw(
|
||||
&mut self,
|
||||
handle: crate::core::svg::Handle,
|
||||
color: Option<crate::core::Color>,
|
||||
bounds: Rectangle,
|
||||
) {
|
||||
delegate!(self, renderer, renderer.draw(handle, color, bounds));
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "geometry")]
|
||||
impl crate::graphics::geometry::Renderer for Renderer {
|
||||
type Geometry = crate::Geometry;
|
||||
|
||||
fn draw(&mut self, layers: Vec<Self::Geometry>) {
|
||||
match self {
|
||||
Self::TinySkia(renderer) => {
|
||||
for layer in layers {
|
||||
match layer {
|
||||
crate::Geometry::TinySkia(primitive) => {
|
||||
renderer.draw_primitive(primitive);
|
||||
}
|
||||
#[cfg(feature = "wgpu")]
|
||||
crate::Geometry::Wgpu(_) => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "wgpu")]
|
||||
Self::Wgpu(renderer) => {
|
||||
for layer in layers {
|
||||
match layer {
|
||||
crate::Geometry::Wgpu(primitive) => {
|
||||
renderer.draw_primitive(primitive);
|
||||
}
|
||||
crate::Geometry::TinySkia(_) => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "wgpu")]
|
||||
impl iced_wgpu::primitive::pipeline::Renderer for Renderer {
|
||||
fn draw_pipeline_primitive(
|
||||
&mut self,
|
||||
bounds: Rectangle,
|
||||
primitive: impl wgpu::primitive::pipeline::Primitive,
|
||||
) {
|
||||
match self {
|
||||
Self::TinySkia(_renderer) => {
|
||||
log::warn!(
|
||||
"Custom shader primitive is unavailable with tiny-skia."
|
||||
);
|
||||
}
|
||||
Self::Wgpu(renderer) => {
|
||||
renderer.draw_pipeline_primitive(bounds, primitive);
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(not(any(feature = "wgpu", feature = "tiny-skia")))]
|
||||
mod renderer {
|
||||
pub type Renderer = ();
|
||||
pub type Compositor = ();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,29 +0,0 @@
|
|||
use crate::core::{Font, Pixels};
|
||||
use crate::graphics::Antialiasing;
|
||||
|
||||
/// The settings of a Backend.
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub struct Settings {
|
||||
/// The default [`Font`] to use.
|
||||
pub default_font: Font,
|
||||
|
||||
/// The default size of text.
|
||||
///
|
||||
/// By default, it will be set to `16.0`.
|
||||
pub default_text_size: Pixels,
|
||||
|
||||
/// The antialiasing strategy that will be used for triangle primitives.
|
||||
///
|
||||
/// By default, it is `None`.
|
||||
pub antialiasing: Option<Antialiasing>,
|
||||
}
|
||||
|
||||
impl Default for Settings {
|
||||
fn default() -> Settings {
|
||||
Settings {
|
||||
default_font: Font::default(),
|
||||
default_text_size: Pixels(16.0),
|
||||
antialiasing: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue