Skip to main content

i_slint_core/
graphics.rs

1// Copyright © SixtyFPS GmbH <info@slint.dev>
2// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
3
4// cSpell: ignore bitmapfont glversion
5#![allow(unsafe_code)]
6#![warn(missing_docs)]
7/*!
8    Graphics Abstractions.
9
10    This module contains the abstractions and convenience types used for rendering.
11*/
12extern crate alloc;
13use crate::Coord;
14use crate::SharedString;
15use crate::api::PlatformError;
16use crate::lengths::LogicalLength;
17use alloc::boxed::Box;
18
19pub use euclid;
20/// 2D Rectangle
21pub type Rect = euclid::default::Rect<Coord>;
22/// 2D Rectangle with integer coordinates
23pub type IntRect = euclid::default::Rect<i32>;
24/// 2D Point
25pub type Point = euclid::default::Point2D<Coord>;
26/// 2D Size
27pub type Size = euclid::default::Size2D<Coord>;
28/// 2D Size in integer coordinates
29pub type IntSize = euclid::default::Size2D<u32>;
30/// 2D Transform
31pub type Transform = euclid::default::Transform2D<Coord>;
32
33pub(crate) mod color;
34pub use color::*;
35
36#[cfg(feature = "shared-fontique")]
37use i_slint_common::sharedfontique::{self, fontique};
38#[cfg(feature = "path")]
39mod path;
40#[cfg(feature = "path")]
41pub use path::*;
42
43mod brush;
44pub use brush::*;
45
46pub(crate) mod image;
47pub use self::image::*;
48
49pub(crate) mod bitmapfont;
50pub use self::bitmapfont::*;
51
52pub mod rendering_metrics_collector;
53
54#[cfg(feature = "box-shadow-cache")]
55pub mod boxshadowcache;
56
57pub mod border_radius;
58pub use border_radius::*;
59
60#[cfg(feature = "wgpu-28")]
61pub mod wgpu_28;
62#[cfg(feature = "wgpu-29")]
63pub mod wgpu_29;
64
65/// CachedGraphicsData allows the graphics backend to store an arbitrary piece of data associated with
66/// an item, which is typically computed by accessing properties. The dependency_tracker is used to allow
67/// for a lazy computation. Typically, back ends store either compute intensive data or handles that refer to
68/// data that's stored in GPU memory.
69pub struct CachedGraphicsData<T> {
70    /// The backend specific data.
71    pub data: T,
72    /// The property tracker that should be used to evaluate whether the primitive needs to be re-created
73    /// or not.
74    pub dependency_tracker: Option<core::pin::Pin<Box<crate::properties::PropertyTracker>>>,
75}
76
77impl<T> CachedGraphicsData<T> {
78    /// Creates a new TrackingRenderingPrimitive by evaluating the provided update_fn once, storing the returned
79    /// rendering primitive and initializing the dependency tracker.
80    pub fn new(update_fn: impl FnOnce() -> T) -> Self {
81        let dependency_tracker = Box::pin(crate::properties::PropertyTracker::default());
82        let data = dependency_tracker.as_ref().evaluate(update_fn);
83        Self { data, dependency_tracker: Some(dependency_tracker) }
84    }
85}
86
87/// FontRequest collects all the developer-configurable properties for fonts, such as family, weight, etc.
88/// It is submitted as a request to the platform font system (i.e. CoreText on macOS) and in exchange the
89/// backend returns a `Box<dyn Font>`.
90#[derive(Debug, Clone, PartialEq, Default)]
91pub struct FontRequest {
92    /// The name of the font family to be used, such as "Helvetica". An empty family name means the system
93    /// default font family should be used.
94    pub family: Option<SharedString>,
95    /// If the weight is None, the system default font weight should be used.
96    pub weight: Option<i32>,
97    /// If the pixel size is None, the system default font size should be used.
98    pub pixel_size: Option<LogicalLength>,
99    /// The additional spacing (or shrinking if negative) between glyphs. This is usually not submitted to
100    /// the font-subsystem but collected here for API convenience
101    pub letter_spacing: Option<LogicalLength>,
102    /// Whether to select an italic face of the font family.
103    pub italic: bool,
104}
105
106#[cfg(feature = "shared-fontique")]
107impl FontRequest {
108    /// Attempts to query the fontique font collection for a matching font.
109    pub fn query_fontique(
110        &self,
111        collection: &mut fontique::Collection,
112        source_cache: &mut fontique::SourceCache,
113    ) -> Option<fontique::QueryFont> {
114        let mut query = collection.query(source_cache);
115        query.set_families(
116            self.family
117                .as_ref()
118                .map(|family| fontique::QueryFamily::from(family.as_str()))
119                .into_iter()
120                .chain(
121                    sharedfontique::FALLBACK_FAMILIES
122                        .into_iter()
123                        .map(fontique::QueryFamily::Generic),
124                ),
125        );
126
127        query.set_attributes(fontique::Attributes {
128            weight: self
129                .weight
130                .as_ref()
131                .map(|&weight| fontique::FontWeight::new(weight as f32))
132                .unwrap_or_default(),
133            style: if self.italic {
134                fontique::FontStyle::Italic
135            } else {
136                fontique::FontStyle::Normal
137            },
138            ..Default::default()
139        });
140
141        let mut font = None;
142
143        query.matches_with(|queried_font| {
144            font = Some(queried_font.clone());
145            fontique::QueryStatus::Stop
146        });
147
148        font
149    }
150}
151
152/// Internal enum to specify which version of OpenGL to request
153/// from the windowing system.
154#[derive(Debug, Clone, PartialEq)]
155pub enum RequestedOpenGLVersion {
156    /// OpenGL
157    OpenGL(Option<(u8, u8)>),
158    /// OpenGL ES
159    OpenGLES(Option<(u8, u8)>),
160}
161
162/// Internal enum specify which graphics API should be used, when
163/// the backend selector requests that from a built-in backend.
164#[derive(Debug, Clone)]
165#[allow(clippy::large_enum_variant)]
166pub enum RequestedGraphicsAPI {
167    /// OpenGL (ES)
168    OpenGL(RequestedOpenGLVersion),
169    /// Metal
170    Metal,
171    /// Vulkan
172    Vulkan,
173    /// Direct 3D
174    Direct3D,
175    #[cfg(feature = "unstable-wgpu-28")]
176    /// WGPU 28.x
177    WGPU28(wgpu_28::api::WGPUConfiguration),
178    #[cfg(feature = "unstable-wgpu-29")]
179    /// WGPU 29.x
180    WGPU29(wgpu_29::api::WGPUConfiguration),
181}
182
183impl TryFrom<&RequestedGraphicsAPI> for RequestedOpenGLVersion {
184    type Error = PlatformError;
185
186    fn try_from(requested_graphics_api: &RequestedGraphicsAPI) -> Result<Self, Self::Error> {
187        match requested_graphics_api {
188            RequestedGraphicsAPI::OpenGL(requested_open_glversion) => {
189                Ok(requested_open_glversion.clone())
190            }
191            RequestedGraphicsAPI::Metal => {
192                Err("Metal rendering is not supported with an OpenGL renderer".into())
193            }
194            RequestedGraphicsAPI::Vulkan => {
195                Err("Vulkan rendering is not supported with an OpenGL renderer".into())
196            }
197            RequestedGraphicsAPI::Direct3D => {
198                Err("Direct3D rendering is not supported with an OpenGL renderer".into())
199            }
200            #[cfg(feature = "unstable-wgpu-28")]
201            RequestedGraphicsAPI::WGPU28(..) => {
202                Err("WGPU 28.x rendering is not supported with an OpenGL renderer".into())
203            }
204            #[cfg(feature = "unstable-wgpu-29")]
205            RequestedGraphicsAPI::WGPU29(..) => {
206                Err("WGPU 29.x rendering is not supported with an OpenGL renderer".into())
207            }
208        }
209    }
210}
211
212impl From<RequestedOpenGLVersion> for RequestedGraphicsAPI {
213    fn from(version: RequestedOpenGLVersion) -> Self {
214        Self::OpenGL(version)
215    }
216}
217
218/// Private API exposed to just the renderers to create GraphicsAPI instance with
219/// non-exhaustive enum variant.
220#[cfg(feature = "unstable-wgpu-28")]
221pub fn create_graphics_api_wgpu_28(
222    instance: wgpu_28::wgpu::Instance,
223    device: wgpu_28::wgpu::Device,
224    queue: wgpu_28::wgpu::Queue,
225) -> crate::api::GraphicsAPI<'static> {
226    crate::api::GraphicsAPI::WGPU28 { instance, device, queue }
227}
228
229/// Private API exposed to just the renderers to create GraphicsAPI instance with
230/// non-exhaustive enum variant.
231#[cfg(feature = "unstable-wgpu-29")]
232pub fn create_graphics_api_wgpu_29(
233    instance: wgpu_29::wgpu::Instance,
234    device: wgpu_29::wgpu::Device,
235    queue: wgpu_29::wgpu::Queue,
236) -> crate::api::GraphicsAPI<'static> {
237    crate::api::GraphicsAPI::WGPU29 { instance, device, queue }
238}
239
240/// Internal module for use by cbindgen and the C++ platform API layer.
241#[cfg(feature = "ffi")]
242pub mod ffi {
243    #![allow(unsafe_code)]
244
245    /// Expand Rect so that cbindgen can see it. ( is in fact euclid::default::Rect<f32>)
246    #[cfg(cbindgen)]
247    #[repr(C)]
248    struct Rect {
249        x: f32,
250        y: f32,
251        width: f32,
252        height: f32,
253    }
254
255    /// Expand IntRect so that cbindgen can see it. ( is in fact euclid::default::Rect<i32>)
256    #[cfg(cbindgen)]
257    #[repr(C)]
258    struct IntRect {
259        x: i32,
260        y: i32,
261        width: i32,
262        height: i32,
263    }
264
265    /// Expand Point so that cbindgen can see it. ( is in fact euclid::default::Point2D<f32>)
266    #[cfg(cbindgen)]
267    #[repr(C)]
268    struct Point {
269        x: f32,
270        y: f32,
271    }
272
273    /// Expand Box2D so that cbindgen can see it.
274    #[cfg(cbindgen)]
275    #[repr(C)]
276    struct Box2D<T, U> {
277        min: euclid::Point2D<T>,
278        max: euclid::Point2D<T>,
279        _unit: std::marker::PhantomData<U>,
280    }
281
282    #[cfg(feature = "std")]
283    pub use super::path::ffi::*;
284
285    /// Conversion function used by C++ platform API layer to
286    /// convert the PhysicalSize used in the Rust WindowAdapter API
287    /// to the ffi.
288    pub fn physical_size_from_api(
289        size: crate::api::PhysicalSize,
290    ) -> crate::graphics::euclid::default::Size2D<u32> {
291        size.to_euclid()
292    }
293
294    /// Conversion function used by C++ platform API layer to
295    /// convert the PhysicalPosition used in the Rust WindowAdapter API
296    /// to the ffi.
297    pub fn physical_position_from_api(
298        position: crate::api::PhysicalPosition,
299    ) -> crate::graphics::euclid::default::Point2D<i32> {
300        position.to_euclid()
301    }
302
303    /// Conversion function used by C++ platform API layer to
304    /// convert from the ffi to PhysicalPosition.
305    pub fn physical_position_to_api(
306        position: crate::graphics::euclid::default::Point2D<i32>,
307    ) -> crate::api::PhysicalPosition {
308        crate::api::PhysicalPosition::from_euclid(position)
309    }
310}