Skip to main content

i_slint_core/
renderer.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
4use alloc::boxed::Box;
5use alloc::rc::Rc;
6use core::pin::Pin;
7
8use crate::api::PlatformError;
9use crate::graphics::{Rgba8Pixel, SharedPixelBuffer};
10use crate::item_tree::ItemTreeRef;
11use crate::items::{ItemRc, TextWrap};
12use crate::lengths::{LogicalLength, LogicalPoint, LogicalRect, LogicalSize, ScaleFactor};
13use crate::window::WindowAdapter;
14
15/// Result of a single rendering attempt. WGPU-backed renderers can report `Occluded` or
16/// `Timeout` instead of rendering a frame; in those cases the caller should re-arm a
17/// redraw rather than wait for the next external event.
18#[must_use]
19#[derive(Debug, Clone, Copy, PartialEq, Eq)]
20pub enum DrawOutcome {
21    Success,
22    Occluded,
23    Timeout,
24}
25
26/// This trait represents a Renderer that can render a slint scene.
27///
28/// This trait is [sealed](https://rust-lang.github.io/api-guidelines/future-proofing.html#sealed-traits-protect-against-downstream-implementations-c-sealed),
29/// meaning that you are not expected to implement this trait
30/// yourself, but you should use the provided ones from Slint.
31pub trait Renderer: RendererSealed {}
32impl<T: RendererSealed> Renderer for T {}
33
34/// Implementation details behind [`Renderer`], but since this
35/// trait is not exported in the public API, it is not possible for the
36/// users to re-implement these functions.
37pub trait RendererSealed {
38    /// Returns the size of the given text in logical pixels.
39    /// When set, `max_width` means that one need to wrap the text, so it does not go further than that,
40    /// using the wrapping type passed by `text_wrap`.
41    fn text_size(
42        &self,
43        text_item: Pin<&dyn crate::item_rendering::RenderString>,
44        item_rc: &crate::item_tree::ItemRc,
45        max_width: Option<LogicalLength>,
46        text_wrap: TextWrap,
47    ) -> LogicalSize;
48
49    /// Returns the size of the individual character in logical pixels.
50    fn char_size(
51        &self,
52        text_item: Pin<&dyn crate::item_rendering::HasFont>,
53        item_rc: &crate::item_tree::ItemRc,
54        ch: char,
55    ) -> LogicalSize;
56
57    /// Returns the metrics of the given font.
58    fn font_metrics(&self, font_request: crate::graphics::FontRequest)
59    -> crate::items::FontMetrics;
60
61    /// Returns the (UTF-8) byte offset in the text property that refers to the character that contributed to
62    /// the glyph cluster that's visually nearest to the given coordinate. This is used for hit-testing,
63    /// for example when receiving a mouse click into a text field. Then this function returns the "cursor"
64    /// position.
65    fn text_input_byte_offset_for_position(
66        &self,
67        text_input: Pin<&crate::items::TextInput>,
68        item_rc: &ItemRc,
69        pos: LogicalPoint,
70    ) -> usize;
71
72    /// That's the opposite of [`Self::text_input_byte_offset_for_position`]
73    /// It takes a (UTF-8) byte offset in the text property, and returns a Rectangle
74    /// left to the char. It is one logical pixel wide and ends at the baseline.
75    fn text_input_cursor_rect_for_byte_offset(
76        &self,
77        text_input: Pin<&crate::items::TextInput>,
78        item_rc: &ItemRc,
79        byte_offset: usize,
80    ) -> LogicalRect;
81
82    /// Clear the caches for the items that are being removed
83    fn free_graphics_resources(
84        &self,
85        _component: ItemTreeRef,
86        _items: &mut dyn Iterator<Item = Pin<crate::items::ItemRef<'_>>>,
87    ) -> Result<(), crate::platform::PlatformError> {
88        Ok(())
89    }
90
91    /// Mark a given region as dirty regardless whether the items actually are dirty.
92    ///
93    /// Example: when a PopupWindow disappears, the region under the popup needs to be redrawn
94    fn mark_dirty_region(&self, _region: crate::partial_renderer::DirtyRegion) {}
95
96    #[cfg(feature = "std")] // FIXME: just because of the Error
97    /// This function can be used to register a custom TrueType font with Slint,
98    /// for use with the `font-family` property. The provided slice must be a valid TrueType
99    /// font.
100    fn register_font_from_memory(
101        &self,
102        _data: &'static [u8],
103    ) -> Result<(), Box<dyn std::error::Error>> {
104        Err("This renderer does not support registering custom fonts.".into())
105    }
106
107    #[cfg(feature = "std")]
108    /// This function can be used to register a custom TrueType font with Slint,
109    /// for use with the `font-family` property. The provided path must refer to a valid TrueType
110    /// font.
111    fn register_font_from_path(
112        &self,
113        _path: &std::path::Path,
114    ) -> Result<(), Box<dyn std::error::Error>> {
115        Err("This renderer does not support registering custom fonts.".into())
116    }
117
118    fn register_bitmap_font(&self, _font_data: &'static crate::graphics::BitmapFont) {
119        crate::debug_log!(
120            "Internal error: The current renderer cannot load fonts build with the `EmbedForSoftwareRenderer` option. Please use the software Renderer, or disable that option when building your slint files"
121        );
122    }
123
124    /// This function is called through the public API to register a callback that the backend needs to invoke during
125    /// different phases of rendering.
126    fn set_rendering_notifier(
127        &self,
128        _callback: Box<dyn crate::api::RenderingNotifier>,
129    ) -> Result<(), crate::api::SetRenderingNotifierError> {
130        Err(crate::api::SetRenderingNotifierError::Unsupported)
131    }
132
133    fn set_window_adapter(&self, _window_adapter: &Rc<dyn WindowAdapter>);
134
135    fn window_adapter(&self) -> Option<Rc<dyn WindowAdapter>>;
136
137    fn scale_factor(&self) -> Option<ScaleFactor> {
138        self.window_adapter()
139            .map(|window_adapter| ScaleFactor::new(window_adapter.window().scale_factor()))
140    }
141
142    #[cfg(feature = "shared-parley")]
143    fn slint_context(&self) -> Option<crate::SlintContext> {
144        self.window_adapter()
145            .map(|wa| crate::window::WindowInner::from_pub(wa.window()).context().clone())
146    }
147
148    fn resize(&self, _size: crate::api::PhysicalSize) -> Result<(), PlatformError> {
149        Ok(())
150    }
151
152    /// Re-implement this function to support Window::take_snapshot(), i.e. return
153    /// the contents of the window in an image buffer.
154    fn take_snapshot(&self) -> Result<SharedPixelBuffer<Rgba8Pixel>, PlatformError> {
155        Err("WindowAdapter::take_snapshot is not implemented by the platform".into())
156    }
157
158    /// Whether the renderer supports transformations such as rotations and scaling or not.
159    fn supports_transformations(&self) -> bool;
160}