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}