ul_next/lib.rs
1//! A safe Rust wrapper for [`Ultralight`](https://ultralig.ht/) library.
2//!
3//! `Ultralight` is a library for rendering web content using the GPU, it allows
4//! easy integration into games and other applications.
5//!
6//! There are two options to use the library:
7//! - Using the [`App`] struct, which is a managed application that allows
8//! to create [`Window`]s that can contain multiple [`Overlay`]s, you can
9//! control the position and size of the [`Overlay`]s, and the inner [`View`]s.
10//! - The other option is using the [`Renderer`] directly, in that case, if you
11//! want to have GPU rendering in your application you need to supply a custom
12//! [`GpuDriver`] in [`platform::set_gpu_driver`].
13//!
14//! This library also contain a custom [`glium`](crate::gpu_driver::glium)
15//! [`GpuDriver`] implementation that can be used for easier integration.
16#![cfg_attr(docsrs, feature(doc_cfg))]
17
18#[cfg(not(any(feature = "linked", feature = "loaded")))]
19compile_error!(
20 "At least one of the features `linked`, `appcore_linked` or `loaded` must be enabled."
21);
22
23#[macro_use]
24pub(crate) mod config_macros;
25#[macro_use]
26pub(crate) mod callback_macros;
27
28#[cfg(any(feature = "appcore_linked", feature = "loaded"))]
29#[cfg_attr(docsrs, doc(cfg(any(feature = "appcore_linked", feature = "loaded"))))]
30pub mod app;
31pub mod bitmap;
32pub mod config;
33pub mod error;
34pub mod event;
35pub mod gpu_driver;
36pub mod image_source;
37pub mod key_code;
38#[cfg(any(feature = "appcore_linked", feature = "loaded"))]
39#[cfg_attr(docsrs, doc(cfg(any(feature = "appcore_linked", feature = "loaded"))))]
40pub mod overlay;
41pub mod platform;
42pub mod rect;
43pub mod renderer;
44pub(crate) mod string;
45pub mod surface;
46pub mod view;
47#[cfg(any(feature = "appcore_linked", feature = "loaded"))]
48#[cfg_attr(docsrs, doc(cfg(any(feature = "appcore_linked", feature = "loaded"))))]
49pub mod window;
50
51pub mod javascript;
52
53use std::{ffi::CStr, sync::Arc};
54
55#[cfg(any(feature = "appcore_linked", feature = "loaded"))]
56#[cfg_attr(docsrs, doc(cfg(any(feature = "appcore_linked", feature = "loaded"))))]
57pub use app::App;
58pub use config::Config;
59pub use gpu_driver::GpuDriver;
60#[cfg(any(feature = "appcore_linked", feature = "loaded"))]
61#[cfg_attr(docsrs, doc(cfg(any(feature = "appcore_linked", feature = "loaded"))))]
62pub use overlay::Overlay;
63pub use rect::Rect;
64pub use renderer::{Renderer, Session};
65pub use surface::Surface;
66pub use view::View;
67#[cfg(any(feature = "appcore_linked", feature = "loaded"))]
68#[cfg_attr(docsrs, doc(cfg(any(feature = "appcore_linked", feature = "loaded"))))]
69pub use window::Window;
70
71use ul_sys::library::Library as LibrarySys;
72
73#[derive(Clone, Copy, Debug)]
74/// The version of the `Ultralight` library.
75///
76/// Use the [`Library::version`] method to get the current version of the library.
77pub struct Version {
78 pub major: u32,
79 pub minor: u32,
80 pub patch: u32,
81}
82
83/// Convert the version into a string in the format `MAJOR.MINOR.PATCH`.
84impl std::fmt::Display for Version {
85 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
86 write!(f, "{}.{}.{}", self.major, self.minor, self.patch)
87 }
88}
89
90/// A handle to the `Ultralight` library.
91#[derive(Clone)]
92pub struct Library {
93 lib: LibrarySys,
94}
95
96impl Library {
97 /// Creates a new `Library` instance with linked Ultralight and AppCore (if enabled `appcore_linked` feature) functions.
98 #[cfg(any(feature = "linked", feature = "appcore_linked"))]
99 #[cfg_attr(docsrs, doc(cfg(any(feature = "linked", feature = "appcore_linked"))))]
100 pub fn linked() -> Arc<Library> {
101 Arc::new(Library {
102 lib: LibrarySys::linked(),
103 })
104 }
105
106 /// Loads the Ultralight library for the current platform.
107 ///
108 /// The library must be installed in the system library path, or loadable by name.
109 ///
110 /// All the other related libraries (`UltralightCore` and `WebCore`) must be loadable as well.
111 ///
112 /// This is preferred over [`linked()`][Library::linked] when the application
113 /// wants to gracefully handle the absence of the library, or handle loading it dynamically.
114 ///
115 /// This doesn't come with `AppCore` functions, use [`load_with_appcore()`][Library::load_with_appcore]
116 /// if you need `AppCore` functions.
117 ///
118 /// # Safety
119 ///
120 /// `dlopen` native libraries is inherently unsafe. The safety guidelines
121 /// for [`Library::new()`][<https://docs.rs/libloading/latest/libloading/struct.Library.html#method.new>] and
122 /// [`Library::get()`][<https://docs.rs/libloading/latest/libloading/struct.Library.html#method.get>] apply here.
123 ///
124 /// No function loaded directly or indirectly from this [`Library`]
125 /// may be called after it is [dropped][drop()].
126 #[cfg(feature = "loaded")]
127 #[cfg_attr(docsrs, doc(cfg(feature = "loaded")))]
128 pub unsafe fn load() -> Result<Arc<Library>, ul_sys::library::LoadingError> {
129 Ok(Arc::new(Library {
130 lib: LibrarySys::load()?,
131 }))
132 }
133
134 /// Loads the AppCore and Ultralight libraries for the current platform.
135 ///
136 /// The libraries must be installed in the system library path, or loadable by name.
137 ///
138 /// All the other related libraries (`Ultralight`, `UltralightCore` and `WebCore`) must be loadable as well.
139 ///
140 /// This comes with all functions, `Ultralight` and `AppCore`.
141 /// If you are handling your own rendering and windowing,
142 /// you may want to use [`load()`][Library::load] only instead
143 /// which doesn't come with `AppCore` functions.
144 ///
145 /// # Safety
146 ///
147 /// `dlopen` native libraries is inherently unsafe. The safety guidelines
148 /// for [`Library::new()`][<https://docs.rs/libloading/latest/libloading/struct.Library.html#method.new>] and
149 /// [`Library::get()`][<https://docs.rs/libloading/latest/libloading/struct.Library.html#method.get>] apply here.
150 ///
151 /// No function loaded directly or indirectly from this [`Library`]
152 /// may be called after it is [dropped][drop()].
153 #[cfg(feature = "loaded")]
154 #[cfg_attr(docsrs, doc(cfg(feature = "loaded")))]
155 pub unsafe fn load_with_appcore() -> Result<Arc<Library>, ul_sys::library::LoadingError> {
156 Ok(Arc::new(Library {
157 lib: LibrarySys::load_with_appcore()?,
158 }))
159 }
160
161 /// Loads the Ultralight library from the given path/name of the library.
162 ///
163 /// All the other related libraries (`UltralightCore` and `WebCore`) must be loadable as well.
164 ///
165 /// # Safety
166 ///
167 /// `dlopen` native libraries is inherently unsafe. The safety guidelines
168 /// for [`Library::new()`][<https://docs.rs/libloading/latest/libloading/struct.Library.html#method.new>] and
169 /// [`Library::get()`][<https://docs.rs/libloading/latest/libloading/struct.Library.html#method.get>] apply here.
170 ///
171 /// No function loaded directly or indirectly from this [`Library`]
172 /// may be called after it is [dropped][drop()].
173 #[cfg(feature = "loaded")]
174 #[cfg_attr(docsrs, doc(cfg(feature = "loaded")))]
175 pub unsafe fn load_from<P: AsRef<::std::ffi::OsStr>>(
176 ultralight_path: P,
177 ) -> Result<Arc<Library>, ul_sys::library::LoadingError> {
178 Ok(Arc::new(Library {
179 lib: LibrarySys::load_from(ultralight_path.as_ref())?,
180 }))
181 }
182
183 /// Loads the AppCore and Ultralight libraries from the given path/name of the library.
184 ///
185 /// All the other related libraries (`Ultralight`, `UltralightCore` and `WebCore`) must be loadable as well.
186 ///
187 /// This will load all functions, `Ultralight` and `AppCore`.
188 /// If you are handling your own rendering and windowing,
189 /// you may want to use [`load_from()`][Library::load_from] only instead
190 /// which won't load `AppCore` functions.
191 ///
192 /// # Safety
193 ///
194 /// `dlopen` native libraries is inherently unsafe. The safety guidelines
195 /// for [`Library::new()`][<https://docs.rs/libloading/latest/libloading/struct.Library.html#method.new>] and
196 /// [`Library::get()`][<https://docs.rs/libloading/latest/libloading/struct.Library.html#method.get>] apply here.
197 ///
198 /// No function loaded directly or indirectly from this [`Library`]
199 /// may be called after it is [dropped][drop()].
200 #[cfg(feature = "loaded")]
201 #[cfg_attr(docsrs, doc(cfg(feature = "loaded")))]
202 pub unsafe fn load_from_appcore<P>(
203 appcore_path: P,
204 ) -> Result<Arc<Library>, ul_sys::library::LoadingError>
205 where
206 P: AsRef<::std::ffi::OsStr>,
207 {
208 Ok(Arc::new(Library {
209 lib: LibrarySys::load_from_appcore(appcore_path.as_ref())?,
210 }))
211 }
212}
213
214impl Library {
215 pub(crate) fn ultralight(&self) -> &ul_sys::library::Ultralight {
216 self.lib.ultralight()
217 }
218
219 #[cfg(any(feature = "appcore_linked", feature = "loaded"))]
220 pub(crate) fn appcore(&self) -> &ul_sys::library::AppCore {
221 self.lib.appcore()
222 }
223
224 /// Get the current version of the `Ultralight` library.
225 pub fn version(&self) -> Version {
226 unsafe {
227 Version {
228 major: self.lib.ultralight().ulVersionMajor(),
229 minor: self.lib.ultralight().ulVersionMinor(),
230 patch: self.lib.ultralight().ulVersionPatch(),
231 }
232 }
233 }
234
235 /// Get the full WebKit version string
236 pub fn webkit_version(&self) -> String {
237 unsafe {
238 let cstr_ptr = self.lib.ultralight().ulWebKitVersionString();
239 if cstr_ptr.is_null() {
240 return String::new();
241 }
242 let version_cstr = CStr::from_ptr(cstr_ptr);
243 version_cstr.to_string_lossy().into_owned()
244 }
245 }
246}