Skip to content

Commit 0ae1baa

Browse files
committed
Introduce custom backend-specific primitives
1 parent 8d65e40 commit 0ae1baa

28 files changed

Lines changed: 618 additions & 263 deletions

File tree

examples/geometry/Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,3 @@ publish = false
77

88
[dependencies]
99
iced = { path = "../..", features = ["advanced"] }
10-
iced_graphics = { path = "../../graphics" }

examples/geometry/src/main.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
//! This example showcases a simple native custom widget that renders using
22
//! arbitrary low-level geometry.
33
mod rainbow {
4-
use iced_graphics::primitive::{ColoredVertex2D, Primitive};
5-
64
use iced::advanced::graphics::color;
5+
use iced::advanced::graphics::primitive::{ColoredVertex2D, Primitive};
76
use iced::advanced::layout::{self, Layout};
87
use iced::advanced::renderer;
98
use iced::advanced::widget::{self, Widget};
@@ -46,8 +45,8 @@ mod rainbow {
4645
cursor: mouse::Cursor,
4746
_viewport: &Rectangle,
4847
) {
48+
use iced::advanced::graphics::primitive::Mesh2D;
4949
use iced::advanced::Renderer as _;
50-
use iced_graphics::primitive::Mesh2D;
5150

5251
let bounds = layout.bounds();
5352

@@ -135,7 +134,7 @@ mod rainbow {
135134
renderer.with_translation(
136135
Vector::new(bounds.x, bounds.y),
137136
|renderer| {
138-
renderer.draw_primitive(mesh);
137+
renderer.draw_with_wgpu(mesh);
139138
},
140139
);
141140
}

examples/loading_spinners/src/circular.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -358,7 +358,9 @@ where
358358
renderer.with_translation(
359359
Vector::new(bounds.x, bounds.y),
360360
|renderer| {
361-
renderer.draw_primitive(geometry.0);
361+
use iced::advanced::graphics::geometry::Renderer as _;
362+
363+
renderer.draw(vec![geometry]);
362364
},
363365
);
364366
}

graphics/Cargo.toml

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,6 @@ features = ["derive"]
3232
version = "0.9"
3333
path = "../core"
3434

35-
[dependencies.tiny-skia]
36-
version = "0.9"
37-
optional = true
38-
3935
[dependencies.image]
4036
version = "0.24"
4137
optional = true

graphics/src/backend.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,13 @@ use iced_core::{Font, Point, Size};
66

77
use std::borrow::Cow;
88

9+
/// The graphics backend of a [`Renderer`].
10+
///
11+
/// [`Renderer`]: crate::Renderer
12+
pub trait Backend {
13+
type Primitive;
14+
}
15+
916
/// A graphics backend that supports text rendering.
1017
pub trait Text {
1118
/// The icon font of the backend.

graphics/src/damage.rs

Lines changed: 64 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,68 @@
11
//! Track and compute the damage of graphical primitives.
2+
use crate::core::alignment;
23
use crate::core::{Rectangle, Size};
34
use crate::Primitive;
45

56
use std::sync::Arc;
67

7-
/// Computes the damage regions between the two given primitives.
8-
pub fn regions(a: &Primitive, b: &Primitive) -> Vec<Rectangle> {
8+
pub trait Damage: PartialEq {
9+
/// Returns the bounds of the [`Damage`].
10+
fn bounds(&self) -> Rectangle;
11+
}
12+
13+
impl<T: Damage> Damage for Primitive<T> {
14+
fn bounds(&self) -> Rectangle {
15+
match self {
16+
Self::Text {
17+
bounds,
18+
horizontal_alignment,
19+
vertical_alignment,
20+
..
21+
} => {
22+
let mut bounds = *bounds;
23+
24+
bounds.x = match horizontal_alignment {
25+
alignment::Horizontal::Left => bounds.x,
26+
alignment::Horizontal::Center => {
27+
bounds.x - bounds.width / 2.0
28+
}
29+
alignment::Horizontal::Right => bounds.x - bounds.width,
30+
};
31+
32+
bounds.y = match vertical_alignment {
33+
alignment::Vertical::Top => bounds.y,
34+
alignment::Vertical::Center => {
35+
bounds.y - bounds.height / 2.0
36+
}
37+
alignment::Vertical::Bottom => bounds.y - bounds.height,
38+
};
39+
40+
bounds.expand(1.5)
41+
}
42+
Self::Quad { bounds, .. }
43+
| Self::Image { bounds, .. }
44+
| Self::Svg { bounds, .. } => bounds.expand(1.0),
45+
Self::Clip { bounds, .. } => bounds.expand(1.0),
46+
Self::SolidMesh { size, .. } | Self::GradientMesh { size, .. } => {
47+
Rectangle::with_size(*size)
48+
}
49+
Self::Group { primitives } => primitives
50+
.iter()
51+
.map(Self::bounds)
52+
.fold(Rectangle::with_size(Size::ZERO), |a, b| {
53+
Rectangle::union(&a, &b)
54+
}),
55+
Self::Translate {
56+
translation,
57+
content,
58+
} => content.bounds() + *translation,
59+
Self::Cache { content } => content.bounds(),
60+
Self::Custom(custom) => custom.bounds(),
61+
}
62+
}
63+
}
64+
65+
fn regions<T: Damage>(a: &Primitive<T>, b: &Primitive<T>) -> Vec<Rectangle> {
966
match (a, b) {
1067
(
1168
Primitive::Group {
@@ -76,7 +133,10 @@ pub fn regions(a: &Primitive, b: &Primitive) -> Vec<Rectangle> {
76133
}
77134

78135
/// Computes the damage regions between the two given lists of primitives.
79-
pub fn list(previous: &[Primitive], current: &[Primitive]) -> Vec<Rectangle> {
136+
pub fn list<T: Damage>(
137+
previous: &[Primitive<T>],
138+
current: &[Primitive<T>],
139+
) -> Vec<Rectangle> {
80140
let damage = previous
81141
.iter()
82142
.zip(current)
@@ -93,7 +153,7 @@ pub fn list(previous: &[Primitive], current: &[Primitive]) -> Vec<Rectangle> {
93153

94154
// Extend damage by the added/removed primitives
95155
damage
96-
.chain(bigger[smaller.len()..].iter().map(Primitive::bounds))
156+
.chain(bigger[smaller.len()..].iter().map(Damage::bounds))
97157
.collect()
98158
}
99159
}

graphics/src/geometry.rs

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,20 +14,10 @@ pub use text::Text;
1414

1515
pub use crate::gradient::{self, Gradient};
1616

17-
use crate::Primitive;
18-
19-
/// A bunch of shapes that can be drawn.
20-
#[derive(Debug, Clone)]
21-
pub struct Geometry(pub Primitive);
22-
23-
impl From<Geometry> for Primitive {
24-
fn from(geometry: Geometry) -> Self {
25-
geometry.0
26-
}
27-
}
28-
2917
/// A renderer capable of drawing some [`Geometry`].
3018
pub trait Renderer: crate::core::Renderer {
19+
type Geometry;
20+
3121
/// Draws the given layers of [`Geometry`].
32-
fn draw(&mut self, layers: Vec<Geometry>);
22+
fn draw(&mut self, layers: Vec<Self::Geometry>);
3323
}

graphics/src/lib.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88
html_logo_url = "https://raw.githubusercontent.com/iced-rs/iced/9ab6923e943f784985e9ef9ca28b10278297225d/docs/logo.svg"
99
)]
1010
#![deny(
11-
missing_debug_implementations,
12-
missing_docs,
11+
//missing_debug_implementations,
12+
//missing_docs,
1313
unsafe_code,
1414
unused_results,
1515
clippy::extra_unused_lifetimes,
@@ -41,15 +41,14 @@ pub mod geometry;
4141
pub mod image;
4242

4343
pub use antialiasing::Antialiasing;
44+
pub use backend::Backend;
4445
pub use compositor::Compositor;
46+
pub use damage::Damage;
4547
pub use error::Error;
4648
pub use gradient::Gradient;
4749
pub use primitive::Primitive;
4850
pub use renderer::Renderer;
4951
pub use transformation::Transformation;
5052
pub use viewport::Viewport;
5153

52-
#[cfg(feature = "geometry")]
53-
pub use geometry::Geometry;
54-
5554
pub use iced_core as core;

graphics/src/primitive.rs

Lines changed: 8 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,7 @@ use std::sync::Arc;
1212

1313
/// A rendering primitive.
1414
#[derive(Debug, Clone, PartialEq)]
15-
#[non_exhaustive]
16-
pub enum Primitive {
15+
pub enum Primitive<T> {
1716
/// A text primitive
1817
Text {
1918
/// The contents of the text
@@ -90,61 +89,39 @@ pub enum Primitive {
9089
/// Any geometry that falls out of this region will be clipped.
9190
size: Size,
9291
},
93-
/// A [`tiny_skia`] path filled with some paint.
94-
#[cfg(feature = "tiny-skia")]
95-
Fill {
96-
/// The path to fill.
97-
path: tiny_skia::Path,
98-
/// The paint to use.
99-
paint: tiny_skia::Paint<'static>,
100-
/// The fill rule to follow.
101-
rule: tiny_skia::FillRule,
102-
/// The transform to apply to the path.
103-
transform: tiny_skia::Transform,
104-
},
105-
/// A [`tiny_skia`] path stroked with some paint.
106-
#[cfg(feature = "tiny-skia")]
107-
Stroke {
108-
/// The path to stroke.
109-
path: tiny_skia::Path,
110-
/// The paint to use.
111-
paint: tiny_skia::Paint<'static>,
112-
/// The stroke settings.
113-
stroke: tiny_skia::Stroke,
114-
/// The transform to apply to the path.
115-
transform: tiny_skia::Transform,
116-
},
11792
/// A group of primitives
11893
Group {
11994
/// The primitives of the group
120-
primitives: Vec<Primitive>,
95+
primitives: Vec<Primitive<T>>,
12196
},
12297
/// A clip primitive
12398
Clip {
12499
/// The bounds of the clip
125100
bounds: Rectangle,
126101
/// The content of the clip
127-
content: Box<Primitive>,
102+
content: Box<Primitive<T>>,
128103
},
129104
/// A primitive that applies a translation
130105
Translate {
131106
/// The translation vector
132107
translation: Vector,
133108

134109
/// The primitive to translate
135-
content: Box<Primitive>,
110+
content: Box<Primitive<T>>,
136111
},
137112
/// A cached primitive.
138113
///
139114
/// This can be useful if you are implementing a widget where primitive
140115
/// generation is expensive.
141116
Cache {
142117
/// The cached primitive
143-
content: Arc<Primitive>,
118+
content: Arc<Primitive<T>>,
144119
},
120+
/// A backend-specific primitive.
121+
Custom(T),
145122
}
146123

147-
impl Primitive {
124+
impl<T> Primitive<T> {
148125
/// Creates a [`Primitive::Group`].
149126
pub fn group(primitives: Vec<Self>) -> Self {
150127
Self::Group { primitives }
@@ -165,68 +142,6 @@ impl Primitive {
165142
content: Box::new(self),
166143
}
167144
}
168-
169-
/// Returns the bounds of the [`Primitive`].
170-
pub fn bounds(&self) -> Rectangle {
171-
match self {
172-
Self::Text {
173-
bounds,
174-
horizontal_alignment,
175-
vertical_alignment,
176-
..
177-
} => {
178-
let mut bounds = *bounds;
179-
180-
bounds.x = match horizontal_alignment {
181-
alignment::Horizontal::Left => bounds.x,
182-
alignment::Horizontal::Center => {
183-
bounds.x - bounds.width / 2.0
184-
}
185-
alignment::Horizontal::Right => bounds.x - bounds.width,
186-
};
187-
188-
bounds.y = match vertical_alignment {
189-
alignment::Vertical::Top => bounds.y,
190-
alignment::Vertical::Center => {
191-
bounds.y - bounds.height / 2.0
192-
}
193-
alignment::Vertical::Bottom => bounds.y - bounds.height,
194-
};
195-
196-
bounds.expand(1.5)
197-
}
198-
Self::Quad { bounds, .. }
199-
| Self::Image { bounds, .. }
200-
| Self::Svg { bounds, .. } => bounds.expand(1.0),
201-
Self::Clip { bounds, .. } => bounds.expand(1.0),
202-
Self::SolidMesh { size, .. } | Self::GradientMesh { size, .. } => {
203-
Rectangle::with_size(*size)
204-
}
205-
#[cfg(feature = "tiny-skia")]
206-
Self::Fill { path, .. } | Self::Stroke { path, .. } => {
207-
let bounds = path.bounds();
208-
209-
Rectangle {
210-
x: bounds.x(),
211-
y: bounds.y(),
212-
width: bounds.width(),
213-
height: bounds.height(),
214-
}
215-
.expand(1.0)
216-
}
217-
Self::Group { primitives } => primitives
218-
.iter()
219-
.map(Self::bounds)
220-
.fold(Rectangle::with_size(Size::ZERO), |a, b| {
221-
Rectangle::union(&a, &b)
222-
}),
223-
Self::Translate {
224-
translation,
225-
content,
226-
} => content.bounds() + *translation,
227-
Self::Cache { content } => content.bounds(),
228-
}
229-
}
230145
}
231146

232147
/// A set of [`Vertex2D`] and indices representing a list of triangles.
@@ -268,9 +183,3 @@ unsafe impl Zeroable for GradientVertex2D {}
268183

269184
#[allow(unsafe_code)]
270185
unsafe impl Pod for GradientVertex2D {}
271-
272-
impl From<()> for Primitive {
273-
fn from(_: ()) -> Self {
274-
Self::Group { primitives: vec![] }
275-
}
276-
}

0 commit comments

Comments
 (0)