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