use std::{
path::Path,
sync::{Arc, Mutex},
};
#[allow(unused_imports)]
use crate::error::CreationError;
use crate::{
gpu_driver::{self, GpuDriver},
string::UlString,
Library,
};
lazy_static::lazy_static! {
static ref LOGGER: InternalPlatform<Box<dyn Logger + Send>> = InternalPlatform::new();
static ref CLIPBOARD: InternalPlatform<Box<dyn Clipboard + Send>> = InternalPlatform::new();
static ref FILESYSTEM: InternalPlatform<Box<dyn FileSystem + Send>> = InternalPlatform::new();
static ref FONTLOADER: InternalPlatform<Box<dyn FontLoader + Send>> = InternalPlatform::new();
pub(crate) static ref GPUDRIVER: InternalPlatform<Box<dyn GpuDriver + Send>> = InternalPlatform::new();
}
pub(crate) struct InternalPlatform<T> {
pub(crate) lib: Mutex<Option<Arc<Library>>>,
pub(crate) obj: Mutex<Option<T>>,
}
impl<T> InternalPlatform<T> {
pub(crate) const fn new() -> Self {
Self {
lib: Mutex::new(None),
obj: Mutex::new(None),
}
}
}
#[derive(Clone, Copy, Debug)]
pub enum LogLevel {
Info = ul_sys::ULLogLevel_kLogLevel_Info as isize,
Warning = ul_sys::ULLogLevel_kLogLevel_Warning as isize,
Error = ul_sys::ULLogLevel_kLogLevel_Error as isize,
}
impl TryFrom<u32> for LogLevel {
type Error = ();
fn try_from(value: u32) -> Result<Self, ()> {
match value {
ul_sys::ULLogLevel_kLogLevel_Info => Ok(LogLevel::Info),
ul_sys::ULLogLevel_kLogLevel_Warning => Ok(LogLevel::Warning),
ul_sys::ULLogLevel_kLogLevel_Error => Ok(LogLevel::Error),
_ => Err(()),
}
}
}
pub trait Logger {
fn log_message(&mut self, log_level: LogLevel, message: String);
}
pub trait Clipboard {
fn clear(&mut self);
fn read_plain_text(&mut self) -> Option<String>;
fn write_plain_text(&mut self, text: &str);
}
pub trait FileSystem {
fn file_exists(&mut self, path: &str) -> bool;
fn get_file_mime_type(&mut self, path: &str) -> String;
fn get_file_charset(&mut self, path: &str) -> String;
fn open_file(&mut self, path: &str) -> Option<Vec<u8>>;
}
pub struct FontFile {
lib: Arc<Library>,
internal: ul_sys::ULFontFile,
}
impl FontFile {
pub fn from_path<P: AsRef<Path>>(lib: Arc<Library>, path: P) -> Option<Self> {
unsafe {
let path = UlString::from_str(lib.clone(), path.as_ref().to_str().unwrap()).unwrap();
let internal = lib.ultralight().ulFontFileCreateFromFilePath(path.to_ul());
if internal.is_null() {
return None;
}
Some(FontFile { lib, internal })
}
}
#[allow(dead_code)]
pub(crate) fn to_ul(&self) -> ul_sys::ULFontFile {
self.internal
}
}
impl Drop for FontFile {
fn drop(&mut self) {
unsafe {
self.lib.ultralight().ulDestroyFontFile(self.internal);
}
}
}
pub trait FontLoader {
fn get_fallback_font(&mut self) -> String;
fn get_fallback_font_for_characters(
&mut self,
characters: &str,
weight: i32,
italic: bool,
) -> String;
fn load(&mut self, family: &str, weight: i32, italic: bool) -> Option<FontFile>;
}
platform_set_interface_macro! {
pub set_logger<Logger>(lib, logger -> LOGGER) -> ulPlatformSetLogger(ULLogger) {
log_message((ul_log_level: u32, ul_message: ul_sys::ULString)) -> ((log_level: u32, message: String)) {
let log_level = LogLevel::try_from(ul_log_level).unwrap();
let message = UlString::copy_raw_to_string(&lib, ul_message).unwrap();
}
}
}
platform_set_interface_macro! {
pub set_clipboard<Clipboard>(lib, clipboard -> CLIPBOARD) -> ulPlatformSetClipboard(ULClipboard) {
clear() -> () {}
read_plain_text((ul_result: ul_sys::ULString)) -> (() -> result: Option<String>) {
} {
if let Some(result) = result {
let result = UlString::from_str(lib.clone(), &result).unwrap();
lib.ultralight().ulStringAssignString(ul_result, result.to_ul());
}
}
write_plain_text((ul_text: ul_sys::ULString)) -> ((text: &String)) {
let text = UlString::copy_raw_to_string(&lib, ul_text).unwrap();
let text = &text;
}
}
}
platform_set_interface_macro! {
pub set_filesystem<FileSystem>(lib, filesystem -> FILESYSTEM) -> ulPlatformSetFileSystem(ULFileSystem) {
file_exists((ul_path: ul_sys::ULString) -> bool) -> ((path: &str)) {
let path = UlString::copy_raw_to_string(&lib, ul_path).unwrap();
let path = &path;
}
get_file_mime_type((ul_path: ul_sys::ULString) -> ul_sys::ULString) -> ((path: &str) -> result: String) {
let path = UlString::copy_raw_to_string(&lib, ul_path).unwrap();
let path = &path;
} {
UlString::from_str_unmanaged(&lib, &result).unwrap()
}
get_file_charset((ul_path: ul_sys::ULString) -> ul_sys::ULString) -> ((path: &str) -> result: String) {
let path = UlString::copy_raw_to_string(&lib, ul_path).unwrap();
let path = &path;
} {
UlString::from_str_unmanaged(&lib, &result).unwrap()
}
open_file((ul_path: ul_sys::ULString) -> ul_sys::ULBuffer) -> ((path: &str) -> result: Option<Vec<u8>>) {
let path = UlString::copy_raw_to_string(&lib, ul_path).unwrap();
let path = &path;
} {
if let Some(result) = result {
lib.ultralight().ulCreateBufferFromCopy(result.as_ptr() as _, result.len())
} else{
std::ptr::null_mut()
}
}
}
}
pub fn set_gpu_driver<G: GpuDriver + Send + 'static>(lib: Arc<Library>, driver: G) {
gpu_driver::set_gpu_driver(lib, driver)
}
#[cfg(any(feature = "appcore_linked", feature = "loaded"))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "appcore_linked", feature = "loaded"))))]
pub fn enable_default_logger<P: AsRef<Path>>(
lib: Arc<Library>,
log_path: P,
) -> Result<(), CreationError> {
unsafe {
let log_path = UlString::from_str(lib.clone(), log_path.as_ref().to_str().unwrap())?;
lib.appcore().ulEnableDefaultLogger(log_path.to_ul());
}
Ok(())
}
#[cfg(any(feature = "appcore_linked", feature = "loaded"))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "appcore_linked", feature = "loaded"))))]
pub fn enable_platform_fontloader(lib: Arc<Library>) {
unsafe {
lib.appcore().ulEnablePlatformFontLoader();
}
}
#[cfg(any(feature = "appcore_linked", feature = "loaded"))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "appcore_linked", feature = "loaded"))))]
pub fn enable_platform_filesystem<P: AsRef<Path>>(
lib: Arc<Library>,
base_dir: P,
) -> Result<(), CreationError> {
unsafe {
let base_dir = UlString::from_str(lib.clone(), base_dir.as_ref().to_str().unwrap())?;
lib.appcore().ulEnablePlatformFileSystem(base_dir.to_ul());
}
Ok(())
}