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