#![allow(dead_code)]
#[cfg(not(feature = "std"))]
use alloc::string::ToString;
use alloc::{alloc::Layout, boxed::Box, collections::BTreeMap, sync::Arc, vec::Vec};
use core::{
ffi::c_void,
fmt,
sync::atomic::{AtomicUsize, Ordering as AtomicOrdering},
};
#[cfg(feature = "std")]
use std::hash::Hash;
use azul_css::{
css::{CssPath, CssPropertyValue},
props::{
basic::{
AnimationInterpolationFunction, FontRef, InterpolateResolver, LayoutRect, LayoutSize,
},
property::{CssProperty, CssPropertyType},
},
system::SystemStyle,
AzString,
};
use rust_fontconfig::{FcFontCache, FontSource};
use crate::{
dom::{DomId, DomNodeId, EventFilter},
geom::{LogicalPosition, LogicalRect, LogicalSize, OptionLogicalPosition, PhysicalSize},
gl::OptionGlContextPtr,
hit_test::OverflowingScrollNode,
id::{NodeDataContainer, NodeDataContainerRef, NodeDataContainerRefMut, NodeId},
prop_cache::CssPropertyCache,
refany::{OptionRefAny, RefAny},
resources::{
DpiScaleFactor, FontInstanceKey, IdNamespace, ImageCache, ImageMask, ImageRef,
RendererResources,
},
styled_dom::{
NodeHierarchyItemId, NodeHierarchyItemVec, OptionStyledDom, StyledDom, StyledNode,
StyledNodeVec,
},
task::{
Duration as AzDuration, GetSystemTimeCallback, Instant as AzInstant, Instant,
TerminateTimer, ThreadId, ThreadReceiver, ThreadSendMsg, TimerId,
},
window::{
AzStringPair, KeyboardState, MouseState, OptionChar, RawWindowHandle, UpdateFocusWarning,
WindowFlags, WindowSize, WindowTheme,
},
FastBTreeSet, FastHashMap,
};
#[repr(C)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum Update {
DoNothing,
RefreshDom,
RefreshDomAllWindows,
}
impl Update {
pub fn max_self(&mut self, other: Self) {
if *self == Update::DoNothing && other != Update::DoNothing {
*self = other;
} else if *self == Update::RefreshDom && other == Update::RefreshDomAllWindows {
*self = other;
}
}
}
pub type LayoutCallbackType = extern "C" fn(RefAny, LayoutCallbackInfo) -> StyledDom;
extern "C" fn default_layout_callback(_: RefAny, _: LayoutCallbackInfo) -> StyledDom {
StyledDom::default()
}
#[repr(C)]
pub struct LayoutCallback {
pub cb: LayoutCallbackType,
pub ctx: OptionRefAny,
}
impl_callback!(LayoutCallback, LayoutCallbackType);
impl LayoutCallback {
pub fn create<I: Into<Self>>(cb: I) -> Self {
cb.into()
}
}
impl Default for LayoutCallback {
fn default() -> Self {
Self {
cb: default_layout_callback,
ctx: OptionRefAny::None,
}
}
}
pub type IFrameCallbackType = extern "C" fn(RefAny, IFrameCallbackInfo) -> IFrameCallbackReturn;
#[repr(C)]
pub struct IFrameCallback {
pub cb: IFrameCallbackType,
pub ctx: OptionRefAny,
}
impl_callback!(IFrameCallback, IFrameCallbackType);
impl IFrameCallback {
pub fn create(cb: IFrameCallbackType) -> Self {
Self {
cb,
ctx: OptionRefAny::None,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(C, u8)]
pub enum IFrameCallbackReason {
InitialRender,
DomRecreated,
BoundsExpanded,
EdgeScrolled(EdgeType),
ScrollBeyondContent,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(C)]
pub enum EdgeType {
Top,
Bottom,
Left,
Right,
}
#[derive(Debug)]
#[repr(C)]
pub struct IFrameCallbackInfo {
pub reason: IFrameCallbackReason,
pub system_fonts: *const FcFontCache,
pub image_cache: *const ImageCache,
pub window_theme: WindowTheme,
pub bounds: HidpiAdjustedBounds,
pub scroll_size: LogicalSize,
pub scroll_offset: LogicalPosition,
pub virtual_scroll_size: LogicalSize,
pub virtual_scroll_offset: LogicalPosition,
callable_ptr: *const OptionRefAny,
_abi_mut: *mut c_void,
}
impl Clone for IFrameCallbackInfo {
fn clone(&self) -> Self {
Self {
reason: self.reason,
system_fonts: self.system_fonts,
image_cache: self.image_cache,
window_theme: self.window_theme,
bounds: self.bounds,
scroll_size: self.scroll_size,
scroll_offset: self.scroll_offset,
virtual_scroll_size: self.virtual_scroll_size,
virtual_scroll_offset: self.virtual_scroll_offset,
callable_ptr: self.callable_ptr,
_abi_mut: self._abi_mut,
}
}
}
impl IFrameCallbackInfo {
pub fn new<'a>(
reason: IFrameCallbackReason,
system_fonts: &'a FcFontCache,
image_cache: &'a ImageCache,
window_theme: WindowTheme,
bounds: HidpiAdjustedBounds,
scroll_size: LogicalSize,
scroll_offset: LogicalPosition,
virtual_scroll_size: LogicalSize,
virtual_scroll_offset: LogicalPosition,
) -> Self {
Self {
reason,
system_fonts: system_fonts as *const FcFontCache,
image_cache: image_cache as *const ImageCache,
window_theme,
bounds,
scroll_size,
scroll_offset,
virtual_scroll_size,
virtual_scroll_offset,
callable_ptr: core::ptr::null(),
_abi_mut: core::ptr::null_mut(),
}
}
pub fn set_callable_ptr(&mut self, callable: &OptionRefAny) {
self.callable_ptr = callable as *const OptionRefAny;
}
pub fn get_ctx(&self) -> OptionRefAny {
if self.callable_ptr.is_null() {
OptionRefAny::None
} else {
unsafe { (*self.callable_ptr).clone() }
}
}
pub fn get_bounds(&self) -> HidpiAdjustedBounds {
self.bounds
}
fn internal_get_system_fonts<'a>(&'a self) -> &'a FcFontCache {
unsafe { &*self.system_fonts }
}
fn internal_get_image_cache<'a>(&'a self) -> &'a ImageCache {
unsafe { &*self.image_cache }
}
}
#[derive(Debug, Clone, PartialEq)]
#[repr(C)]
pub struct IFrameCallbackReturn {
pub dom: OptionStyledDom,
pub scroll_size: LogicalSize,
pub scroll_offset: LogicalPosition,
pub virtual_scroll_size: LogicalSize,
pub virtual_scroll_offset: LogicalPosition,
}
impl Default for IFrameCallbackReturn {
fn default() -> IFrameCallbackReturn {
IFrameCallbackReturn {
dom: OptionStyledDom::None,
scroll_size: LogicalSize::zero(),
scroll_offset: LogicalPosition::zero(),
virtual_scroll_size: LogicalSize::zero(),
virtual_scroll_offset: LogicalPosition::zero(),
}
}
}
impl IFrameCallbackReturn {
pub fn with_dom(
dom: StyledDom,
scroll_size: LogicalSize,
scroll_offset: LogicalPosition,
virtual_scroll_size: LogicalSize,
virtual_scroll_offset: LogicalPosition,
) -> Self {
Self {
dom: OptionStyledDom::Some(dom),
scroll_size,
scroll_offset,
virtual_scroll_size,
virtual_scroll_offset,
}
}
pub fn keep_current(
scroll_size: LogicalSize,
scroll_offset: LogicalPosition,
virtual_scroll_size: LogicalSize,
virtual_scroll_offset: LogicalPosition,
) -> Self {
Self {
dom: OptionStyledDom::None,
scroll_size,
scroll_offset,
virtual_scroll_size,
virtual_scroll_offset,
}
}
#[deprecated(
since = "1.0.0",
note = "Use `with_dom()` for new content or `keep_current()` for no update"
)]
pub fn new(
dom: StyledDom,
scroll_size: LogicalSize,
scroll_offset: LogicalPosition,
virtual_scroll_size: LogicalSize,
virtual_scroll_offset: LogicalPosition,
) -> Self {
Self::with_dom(
dom,
scroll_size,
scroll_offset,
virtual_scroll_size,
virtual_scroll_offset,
)
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(C)]
pub struct TimerCallbackReturn {
pub should_update: Update,
pub should_terminate: TerminateTimer,
}
impl TimerCallbackReturn {
pub fn create(should_update: Update, should_terminate: TerminateTimer) -> Self {
Self {
should_update,
should_terminate,
}
}
pub fn continue_unchanged() -> Self {
Self {
should_update: Update::DoNothing,
should_terminate: TerminateTimer::Continue,
}
}
pub fn continue_and_update() -> Self {
Self {
should_update: Update::RefreshDom,
should_terminate: TerminateTimer::Continue,
}
}
pub fn terminate_unchanged() -> Self {
Self {
should_update: Update::DoNothing,
should_terminate: TerminateTimer::Terminate,
}
}
pub fn terminate_and_update() -> Self {
Self {
should_update: Update::RefreshDom,
should_terminate: TerminateTimer::Terminate,
}
}
}
impl Default for TimerCallbackReturn {
fn default() -> Self {
Self::continue_unchanged()
}
}
#[derive(Debug)]
#[repr(C)]
pub struct LayoutCallbackInfoRefData<'a> {
pub image_cache: &'a ImageCache,
pub gl_context: &'a OptionGlContextPtr,
pub system_fonts: &'a FcFontCache,
pub system_style: Arc<SystemStyle>,
}
#[repr(C)]
pub struct LayoutCallbackInfo {
ref_data: *const LayoutCallbackInfoRefData<'static>,
pub window_size: WindowSize,
pub theme: WindowTheme,
callable_ptr: *const OptionRefAny,
_abi_mut: *mut core::ffi::c_void,
}
impl Clone for LayoutCallbackInfo {
fn clone(&self) -> Self {
Self {
ref_data: self.ref_data,
window_size: self.window_size,
theme: self.theme,
callable_ptr: self.callable_ptr,
_abi_mut: self._abi_mut,
}
}
}
impl core::fmt::Debug for LayoutCallbackInfo {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("LayoutCallbackInfo")
.field("window_size", &self.window_size)
.field("theme", &self.theme)
.finish_non_exhaustive()
}
}
impl LayoutCallbackInfo {
pub fn new<'a>(
ref_data: &'a LayoutCallbackInfoRefData<'a>,
window_size: WindowSize,
theme: WindowTheme,
) -> Self {
Self {
ref_data: unsafe { core::mem::transmute(ref_data) },
window_size,
theme,
callable_ptr: core::ptr::null(),
_abi_mut: core::ptr::null_mut(),
}
}
pub fn set_callable_ptr(&mut self, callable: &OptionRefAny) {
self.callable_ptr = callable as *const OptionRefAny;
}
pub fn get_ctx(&self) -> OptionRefAny {
if self.callable_ptr.is_null() {
OptionRefAny::None
} else {
unsafe { (*self.callable_ptr).clone() }
}
}
pub fn get_system_style(&self) -> Arc<SystemStyle> {
unsafe { (*self.ref_data).system_style.clone() }
}
fn internal_get_image_cache<'a>(&'a self) -> &'a ImageCache {
unsafe { (*self.ref_data).image_cache }
}
fn internal_get_system_fonts<'a>(&'a self) -> &'a FcFontCache {
unsafe { (*self.ref_data).system_fonts }
}
fn internal_get_gl_context<'a>(&'a self) -> &'a OptionGlContextPtr {
unsafe { (*self.ref_data).gl_context }
}
pub fn get_gl_context(&self) -> OptionGlContextPtr {
self.internal_get_gl_context().clone()
}
pub fn get_system_fonts(&self) -> Vec<AzStringPair> {
let fc_cache = self.internal_get_system_fonts();
fc_cache
.list()
.iter()
.filter_map(|(pattern, font_id)| {
let source = fc_cache.get_font_by_id(font_id)?;
match source {
FontSource::Memory(f) => None,
FontSource::Disk(d) => Some((pattern.name.as_ref()?.clone(), d.path.clone())),
}
})
.map(|(k, v)| AzStringPair {
key: k.into(),
value: v.into(),
})
.collect()
}
pub fn get_image(&self, image_id: &AzString) -> Option<ImageRef> {
self.internal_get_image_cache()
.get_css_image_id(image_id)
.cloned()
}
pub fn window_width_less_than(&self, px: f32) -> bool {
self.window_size.dimensions.width < px
}
pub fn window_width_greater_than(&self, px: f32) -> bool {
self.window_size.dimensions.width > px
}
pub fn window_width_between(&self, min_px: f32, max_px: f32) -> bool {
let width = self.window_size.dimensions.width;
width >= min_px && width <= max_px
}
pub fn window_height_less_than(&self, px: f32) -> bool {
self.window_size.dimensions.height < px
}
pub fn window_height_greater_than(&self, px: f32) -> bool {
self.window_size.dimensions.height > px
}
pub fn window_height_between(&self, min_px: f32, max_px: f32) -> bool {
let height = self.window_size.dimensions.height;
height >= min_px && height <= max_px
}
pub fn get_window_width(&self) -> f32 {
self.window_size.dimensions.width
}
pub fn get_window_height(&self) -> f32 {
self.window_size.dimensions.height
}
pub fn get_dpi_factor(&self) -> f32 {
self.window_size.dpi as f32
}
}
#[derive(Debug, Copy, Clone)]
#[repr(C)]
pub struct HidpiAdjustedBounds {
pub logical_size: LogicalSize,
pub hidpi_factor: DpiScaleFactor,
}
impl HidpiAdjustedBounds {
#[inline(always)]
pub fn from_bounds(bounds: LayoutSize, hidpi_factor: DpiScaleFactor) -> Self {
let logical_size = LogicalSize::new(bounds.width as f32, bounds.height as f32);
Self {
logical_size,
hidpi_factor,
}
}
pub fn get_physical_size(&self) -> PhysicalSize<u32> {
self.get_logical_size()
.to_physical(self.get_hidpi_factor().inner.get())
}
pub fn get_logical_size(&self) -> LogicalSize {
self.logical_size
}
pub fn get_hidpi_factor(&self) -> DpiScaleFactor {
self.hidpi_factor.clone()
}
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(C, u8)]
pub enum FocusTarget {
Id(DomNodeId),
Path(FocusTargetPath),
Previous,
Next,
First,
Last,
NoFocus,
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(C)]
pub struct FocusTargetPath {
pub dom: DomId,
pub css_path: CssPath,
}
pub type CoreCallbackType = usize;
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(C)]
pub struct CoreCallback {
pub cb: CoreCallbackType,
pub ctx: OptionRefAny,
}
impl From<CoreCallbackType> for CoreCallback {
fn from(cb: CoreCallbackType) -> Self {
CoreCallback {
cb,
ctx: OptionRefAny::None,
}
}
}
impl_option!(
CoreCallback,
OptionCoreCallback,
[Debug, Eq, Clone, PartialEq, PartialOrd, Ord, Hash]
);
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(C)]
pub struct CoreCallbackData {
pub event: EventFilter,
pub callback: CoreCallback,
pub refany: RefAny,
}
impl_option!(
CoreCallbackData,
OptionCoreCallbackData,
copy = false,
[Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
);
impl_vec!(CoreCallbackData, CoreCallbackDataVec, CoreCallbackDataVecDestructor, CoreCallbackDataVecDestructorType, CoreCallbackDataVecSlice, OptionCoreCallbackData);
impl_vec_clone!(
CoreCallbackData,
CoreCallbackDataVec,
CoreCallbackDataVecDestructor
);
impl_vec_mut!(CoreCallbackData, CoreCallbackDataVec);
impl_vec_debug!(CoreCallbackData, CoreCallbackDataVec);
impl_vec_partialord!(CoreCallbackData, CoreCallbackDataVec);
impl_vec_ord!(CoreCallbackData, CoreCallbackDataVec);
impl_vec_partialeq!(CoreCallbackData, CoreCallbackDataVec);
impl_vec_eq!(CoreCallbackData, CoreCallbackDataVec);
impl_vec_hash!(CoreCallbackData, CoreCallbackDataVec);
impl CoreCallbackDataVec {
#[inline]
pub fn as_container<'a>(&'a self) -> NodeDataContainerRef<'a, CoreCallbackData> {
NodeDataContainerRef {
internal: self.as_ref(),
}
}
#[inline]
pub fn as_container_mut<'a>(&'a mut self) -> NodeDataContainerRefMut<'a, CoreCallbackData> {
NodeDataContainerRefMut {
internal: self.as_mut(),
}
}
}
pub type CoreRenderImageCallbackType = usize;
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(C)]
pub struct CoreRenderImageCallback {
pub cb: CoreRenderImageCallbackType,
pub ctx: OptionRefAny,
}
impl From<CoreRenderImageCallbackType> for CoreRenderImageCallback {
fn from(cb: CoreRenderImageCallbackType) -> Self {
CoreRenderImageCallback {
cb,
ctx: OptionRefAny::None,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(C)]
pub struct CoreImageCallback {
pub refany: RefAny,
pub callback: CoreRenderImageCallback,
}
impl_option!(
CoreImageCallback,
OptionCoreImageCallback,
copy = false,
[Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
);