1#![allow(dead_code)]
2
3#[cfg(not(feature = "std"))]
4use alloc::string::ToString;
5use alloc::{alloc::Layout, boxed::Box, collections::BTreeMap, vec::Vec};
6use core::{
7 ffi::c_void,
8 fmt,
9 sync::atomic::{AtomicUsize, Ordering as AtomicOrdering},
10};
11#[cfg(feature = "std")]
12use std::hash::Hash;
13
14use azul_css::{
15 AnimationInterpolationFunction, AzString, CssPath, CssProperty, CssPropertyType, FontRef,
16 InterpolateResolver, LayoutRect, LayoutSize,
17};
18use rust_fontconfig::{FcFontCache, FontSource};
19
20use crate::{
21 app_resources::{
22 FontInstanceKey, IdNamespace, ImageCache, ImageMask, ImageRef, LayoutedGlyphs,
23 RendererResources, ShapedWords, WordPositions, Words,
24 },
25 gl::OptionGlContextPtr,
26 id_tree::{NodeDataContainer, NodeId},
27 styled_dom::{
28 CssPropertyCache, DomId, NodeHierarchyItemId, NodeHierarchyItemVec, StyledDom, StyledNode,
29 StyledNodeVec,
30 },
31 task::{
32 CreateThreadCallback, Duration as AzDuration, ExternalSystemCallbacks,
33 GetSystemTimeCallback, Instant as AzInstant, Instant, TerminateTimer, Thread, ThreadId,
34 ThreadReceiver, ThreadSendMsg, ThreadSender, Timer, TimerId,
35 },
36 ui_solver::{
37 LayoutResult, OverflowingScrollNode, PositionInfo, PositionedRectangle,
38 ResolvedTextLayoutOptions, TextLayoutOptions,
39 },
40 window::{
41 AzStringPair, FullWindowState, KeyboardState, LogicalPosition, LogicalRect, LogicalSize,
42 MouseState, OptionChar, OptionLogicalPosition, PhysicalSize, RawWindowHandle,
43 UpdateFocusWarning, WindowCreateOptions, WindowFlags, WindowSize, WindowState, WindowTheme,
44 },
45 FastBTreeSet, FastHashMap,
46};
47
48#[repr(C)]
52pub struct Dummy {
53 pub _dummy: u8,
54}
55
56#[repr(C)]
58#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
59pub enum Update {
60 DoNothing,
62 RefreshDom,
65 RefreshDomAllWindows,
67}
68
69impl Update {
70 pub fn max_self(&mut self, other: Self) {
71 if *self == Update::DoNothing && other != Update::DoNothing {
72 *self = other;
73 } else if *self == Update::RefreshDom && other == Update::RefreshDomAllWindows {
74 *self = other;
75 }
76 }
77}
78
79#[derive(Debug)]
80#[repr(C)]
81pub struct RefCountInner {
82 pub num_copies: AtomicUsize,
83 pub num_refs: AtomicUsize,
84 pub num_mutable_refs: AtomicUsize,
85 pub _internal_len: usize,
86 pub _internal_layout_size: usize,
87 pub _internal_layout_align: usize,
88 pub type_id: u64,
89 pub type_name: AzString,
90 pub custom_destructor: extern "C" fn(*mut c_void),
91}
92
93#[derive(Hash, PartialEq, PartialOrd, Ord, Eq)]
94#[repr(C)]
95pub struct RefCount {
96 pub ptr: *const RefCountInner,
97 pub run_destructor: bool,
98}
99
100impl fmt::Debug for RefCount {
101 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
102 self.downcast().fmt(f)
103 }
104}
105
106impl Clone for RefCount {
107 fn clone(&self) -> Self {
108 Self {
109 ptr: self.ptr,
110 run_destructor: true,
111 }
112 }
113}
114
115impl Drop for RefCount {
116 fn drop(&mut self) {
117 self.run_destructor = false;
118 }
120}
121
122#[derive(Debug, Clone)]
123pub struct RefCountInnerDebug {
124 pub num_copies: usize,
125 pub num_refs: usize,
126 pub num_mutable_refs: usize,
127 pub _internal_len: usize,
128 pub _internal_layout_size: usize,
129 pub _internal_layout_align: usize,
130 pub type_id: u64,
131 pub type_name: AzString,
132 pub custom_destructor: usize,
133}
134
135impl RefCount {
136 fn new(ref_count: RefCountInner) -> Self {
137 RefCount {
138 ptr: Box::into_raw(Box::new(ref_count)),
139 run_destructor: true,
140 }
141 }
142 fn downcast(&self) -> &RefCountInner {
143 unsafe { &*self.ptr }
144 }
145
146 pub fn debug_get_refcount_copied(&self) -> RefCountInnerDebug {
147 let dc = self.downcast();
148 RefCountInnerDebug {
149 num_copies: dc.num_copies.load(AtomicOrdering::SeqCst),
150 num_refs: dc.num_refs.load(AtomicOrdering::SeqCst),
151 num_mutable_refs: dc.num_mutable_refs.load(AtomicOrdering::SeqCst),
152 _internal_len: dc._internal_len,
153 _internal_layout_size: dc._internal_layout_size,
154 _internal_layout_align: dc._internal_layout_align,
155 type_id: dc.type_id,
156 type_name: dc.type_name.clone(),
157 custom_destructor: dc.custom_destructor as usize,
158 }
159 }
160
161 pub fn can_be_shared(&self) -> bool {
163 self.downcast()
164 .num_mutable_refs
165 .load(AtomicOrdering::SeqCst)
166 == 0
167 }
168
169 pub fn can_be_shared_mut(&self) -> bool {
171 let info = self.downcast();
172 info.num_mutable_refs.load(AtomicOrdering::SeqCst) == 0
173 && info.num_refs.load(AtomicOrdering::SeqCst) == 0
174 }
175
176 pub fn increase_ref(&self) {
177 self.downcast()
178 .num_refs
179 .fetch_add(1, AtomicOrdering::SeqCst);
180 }
181
182 pub fn decrease_ref(&self) {
183 self.downcast()
184 .num_refs
185 .fetch_sub(1, AtomicOrdering::SeqCst);
186 }
187
188 pub fn increase_refmut(&self) {
189 self.downcast()
190 .num_mutable_refs
191 .fetch_add(1, AtomicOrdering::SeqCst);
192 }
193
194 pub fn decrease_refmut(&self) {
195 self.downcast()
196 .num_mutable_refs
197 .fetch_sub(1, AtomicOrdering::SeqCst);
198 }
199}
200
201#[derive(Debug)]
202#[repr(C)]
203pub struct Ref<'a, T> {
204 ptr: &'a T,
205 sharing_info: RefCount,
206}
207
208impl<'a, T> Drop for Ref<'a, T> {
209 fn drop(&mut self) {
210 self.sharing_info.decrease_ref();
211 }
212}
213
214impl<'a, T> core::ops::Deref for Ref<'a, T> {
215 type Target = T;
216
217 fn deref(&self) -> &Self::Target {
218 self.ptr
219 }
220}
221
222#[derive(Debug)]
223#[repr(C)]
224pub struct RefMut<'a, T> {
225 ptr: &'a mut T,
226 sharing_info: RefCount,
227}
228
229impl<'a, T> Drop for RefMut<'a, T> {
230 fn drop(&mut self) {
231 self.sharing_info.decrease_refmut();
232 }
233}
234
235impl<'a, T> core::ops::Deref for RefMut<'a, T> {
236 type Target = T;
237
238 fn deref(&self) -> &Self::Target {
239 &*self.ptr
240 }
241}
242
243impl<'a, T> core::ops::DerefMut for RefMut<'a, T> {
244 fn deref_mut(&mut self) -> &mut Self::Target {
245 self.ptr
246 }
247}
248
249#[derive(Debug, Hash, PartialEq, PartialOrd, Ord, Eq)]
250#[repr(C)]
251pub struct RefAny {
252 pub _internal_ptr: *const c_void,
255 pub sharing_info: RefCount,
258 pub instance_id: u64,
262 pub run_destructor: bool,
263}
264
265impl_option!(
266 RefAny,
267 OptionRefAny,
268 copy = false,
269 [Debug, Hash, Clone, PartialEq, PartialOrd, Ord, Eq]
270);
271
272unsafe impl Send for RefAny {}
274unsafe impl Sync for RefAny {} impl RefAny {
278 pub fn new<T: 'static>(value: T) -> Self {
281 extern "C" fn default_custom_destructor<U: 'static>(ptr: &mut c_void) {
282 use core::{mem, ptr};
283
284 unsafe {
287 let mut stack_mem = mem::MaybeUninit::<U>::uninit();
290 ptr::copy_nonoverlapping(
291 (ptr as *mut c_void) as *const U,
292 stack_mem.as_mut_ptr(),
293 mem::size_of::<U>(),
294 );
295 let stack_mem = stack_mem.assume_init();
296 mem::drop(stack_mem);
297 }
298 }
299
300 let type_name = ::core::any::type_name::<T>();
301 let st = AzString::from_const_str(type_name);
302 let s = Self::new_c(
303 (&value as *const T) as *const c_void,
304 ::core::mem::size_of::<T>(),
305 Self::get_type_id_static::<T>(),
306 st,
307 default_custom_destructor::<T>,
308 );
309 ::core::mem::forget(value); s
311 }
312
313 pub fn new_c(
315 ptr: *const c_void,
317 len: usize,
319 type_id: u64,
321 type_name: AzString,
323 custom_destructor: extern "C" fn(&mut c_void),
324 ) -> Self {
325 use core::ptr;
326
327 let (_internal_ptr, layout) = if len == 0 {
332 let _dummy: [u8; 0] = [];
333 (ptr::null_mut(), Layout::for_value(&_dummy))
334 } else {
335 let struct_as_bytes = unsafe { core::slice::from_raw_parts(ptr as *const u8, len) };
337 let layout = Layout::for_value(&*struct_as_bytes);
338
339 let heap_struct_as_bytes = unsafe { alloc::alloc::alloc(layout) };
341 unsafe {
342 ptr::copy_nonoverlapping(
343 struct_as_bytes.as_ptr(),
344 heap_struct_as_bytes,
345 struct_as_bytes.len(),
346 )
347 };
348 (heap_struct_as_bytes, layout)
349 };
350
351 let ref_count_inner = RefCountInner {
352 num_copies: AtomicUsize::new(1),
353 num_refs: AtomicUsize::new(0),
354 num_mutable_refs: AtomicUsize::new(0),
355 _internal_len: len,
356 _internal_layout_size: layout.size(),
357 _internal_layout_align: layout.align(),
358 type_id,
359 type_name,
360 custom_destructor: unsafe { core::mem::transmute(custom_destructor) },
362 };
363
364 Self {
365 _internal_ptr: _internal_ptr as *const c_void,
366 sharing_info: RefCount::new(ref_count_inner),
367 instance_id: 0,
368 run_destructor: true,
369 }
370 }
371
372 pub fn has_no_copies(&self) -> bool {
374 self.sharing_info
375 .downcast()
376 .num_copies
377 .load(AtomicOrdering::SeqCst)
378 == 1
379 && self
380 .sharing_info
381 .downcast()
382 .num_refs
383 .load(AtomicOrdering::SeqCst)
384 == 0
385 && self
386 .sharing_info
387 .downcast()
388 .num_mutable_refs
389 .load(AtomicOrdering::SeqCst)
390 == 0
391 }
392
393 #[inline]
395 pub fn downcast_ref<'a, U: 'static>(&'a mut self) -> Option<Ref<'a, U>> {
396 let is_same_type = self.get_type_id() == Self::get_type_id_static::<U>();
397 if !is_same_type {
398 return None;
399 }
400
401 let can_be_shared = self.sharing_info.can_be_shared();
402 if !can_be_shared {
403 return None;
404 }
405
406 if self._internal_ptr.is_null() {
407 return None;
408 }
409 self.sharing_info.increase_ref();
410 Some(Ref {
411 ptr: unsafe { &*(self._internal_ptr as *const U) },
412 sharing_info: self.sharing_info.clone(),
413 })
414 }
415
416 #[inline]
419 pub fn downcast_mut<'a, U: 'static>(&'a mut self) -> Option<RefMut<'a, U>> {
420 let is_same_type = self.get_type_id() == Self::get_type_id_static::<U>();
421 if !is_same_type {
422 return None;
423 }
424
425 let can_be_shared_mut = self.sharing_info.can_be_shared_mut();
426 if !can_be_shared_mut {
427 return None;
428 }
429
430 if self._internal_ptr.is_null() {
431 return None;
432 }
433 self.sharing_info.increase_refmut();
434
435 Some(RefMut {
436 ptr: unsafe { &mut *(self._internal_ptr as *mut U) },
437 sharing_info: self.sharing_info.clone(),
438 })
439 }
440
441 #[inline]
444 fn get_type_id_static<T: 'static>() -> u64 {
445 use core::{any::TypeId, mem};
446
447 let t_id = TypeId::of::<T>();
449 let struct_as_bytes = unsafe {
450 core::slice::from_raw_parts(
451 (&t_id as *const TypeId) as *const u8,
452 mem::size_of::<TypeId>(),
453 )
454 };
455
456 struct_as_bytes
457 .into_iter()
458 .enumerate()
459 .map(|(s_pos, s)| ((*s as u64) << s_pos))
460 .sum()
461 }
462
463 pub fn is_type(&self, type_id: u64) -> bool {
465 self.sharing_info.downcast().type_id == type_id
466 }
467
468 pub fn get_type_id(&self) -> u64 {
470 self.sharing_info.downcast().type_id
471 }
472
473 pub fn get_type_name(&self) -> AzString {
475 self.sharing_info.downcast().type_name.clone()
476 }
477}
478
479impl Clone for RefAny {
480 fn clone(&self) -> Self {
481 self.sharing_info
482 .downcast()
483 .num_copies
484 .fetch_add(1, AtomicOrdering::SeqCst);
485 Self {
486 _internal_ptr: self._internal_ptr,
487 sharing_info: RefCount {
488 ptr: self.sharing_info.ptr,
489 run_destructor: true,
490 },
491 instance_id: self
492 .sharing_info
493 .downcast()
494 .num_copies
495 .load(AtomicOrdering::SeqCst) as u64,
496 run_destructor: true,
497 }
498 }
499}
500
501impl Drop for RefAny {
502 fn drop(&mut self) {
503 use core::ptr;
504
505 self.run_destructor = false;
506
507 let current_copies = self
508 .sharing_info
509 .downcast()
510 .num_copies
511 .fetch_sub(1, AtomicOrdering::SeqCst);
512
513 if current_copies != 1 {
514 return;
515 }
516
517 let sharing_info = unsafe { Box::from_raw(self.sharing_info.ptr as *mut RefCountInner) };
518 let sharing_info = *sharing_info; if sharing_info._internal_len == 0
521 || sharing_info._internal_layout_size == 0
522 || self._internal_ptr.is_null()
523 {
524 let mut _dummy: [u8; 0] = [];
525 (sharing_info.custom_destructor)(_dummy.as_ptr() as *mut c_void);
526 } else {
527 let layout = unsafe {
528 Layout::from_size_align_unchecked(
529 sharing_info._internal_layout_size,
530 sharing_info._internal_layout_align,
531 )
532 };
533
534 (sharing_info.custom_destructor)(self._internal_ptr as *mut c_void);
535 unsafe {
536 alloc::alloc::dealloc(self._internal_ptr as *mut u8, layout);
537 }
538 }
539 }
540}
541
542pub type PipelineSourceId = u32;
547
548#[derive(Debug, Clone, PartialEq, PartialOrd)]
550pub struct ScrollPosition {
551 pub parent_rect: LogicalRect,
554 pub children_rect: LogicalRect,
556}
557
558#[derive(Copy, Clone, Eq, Hash, PartialEq, PartialOrd, Ord)]
559pub struct DocumentId {
560 pub namespace_id: IdNamespace,
561 pub id: u32,
562}
563
564impl ::core::fmt::Display for DocumentId {
565 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
566 write!(
567 f,
568 "DocumentId {{ ns: {}, id: {} }}",
569 self.namespace_id, self.id
570 )
571 }
572}
573
574impl ::core::fmt::Debug for DocumentId {
575 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
576 write!(f, "{}", self)
577 }
578}
579
580#[derive(Copy, Clone, Eq, Hash, PartialEq, PartialOrd, Ord)]
581pub struct PipelineId(pub PipelineSourceId, pub u32);
582
583impl ::core::fmt::Display for PipelineId {
584 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
585 write!(f, "PipelineId({}, {})", self.0, self.1)
586 }
587}
588
589impl ::core::fmt::Debug for PipelineId {
590 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
591 write!(f, "{}", self)
592 }
593}
594
595static LAST_PIPELINE_ID: AtomicUsize = AtomicUsize::new(0);
596
597impl PipelineId {
598 pub const DUMMY: PipelineId = PipelineId(0, 0);
599
600 pub fn new() -> Self {
601 PipelineId(
602 LAST_PIPELINE_ID.fetch_add(1, AtomicOrdering::SeqCst) as u32,
603 0,
604 )
605 }
606}
607
608#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
609pub struct HitTestItem {
610 pub point_in_viewport: LogicalPosition,
614 pub point_relative_to_item: LogicalPosition,
617 pub is_focusable: bool,
619 pub is_iframe_hit: Option<(DomId, LogicalPosition)>,
621}
622
623#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
624pub struct ScrollHitTestItem {
625 pub point_in_viewport: LogicalPosition,
629 pub point_relative_to_item: LogicalPosition,
632 pub scroll_node: OverflowingScrollNode,
634}
635
636#[macro_export]
652macro_rules! impl_callback {
653 ($callback_value:ident) => {
654 impl ::core::fmt::Display for $callback_value {
655 fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
656 write!(f, "{:?}", self)
657 }
658 }
659
660 impl ::core::fmt::Debug for $callback_value {
661 fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
662 let callback = stringify!($callback_value);
663 write!(f, "{} @ 0x{:x}", callback, self.cb as usize)
664 }
665 }
666
667 impl Clone for $callback_value {
668 fn clone(&self) -> Self {
669 $callback_value {
670 cb: self.cb.clone(),
671 }
672 }
673 }
674
675 impl ::core::hash::Hash for $callback_value {
676 fn hash<H>(&self, state: &mut H)
677 where
678 H: ::core::hash::Hasher,
679 {
680 state.write_usize(self.cb as usize);
681 }
682 }
683
684 impl PartialEq for $callback_value {
685 fn eq(&self, rhs: &Self) -> bool {
686 self.cb as usize == rhs.cb as usize
687 }
688 }
689
690 impl PartialOrd for $callback_value {
691 fn partial_cmp(&self, other: &Self) -> Option<::core::cmp::Ordering> {
692 Some((self.cb as usize).cmp(&(other.cb as usize)))
693 }
694 }
695
696 impl Ord for $callback_value {
697 fn cmp(&self, other: &Self) -> ::core::cmp::Ordering {
698 (self.cb as usize).cmp(&(other.cb as usize))
699 }
700 }
701
702 impl Eq for $callback_value {}
703
704 impl Copy for $callback_value {}
705 };
706}
707
708#[allow(unused_macros)]
709macro_rules! impl_get_gl_context {
710 () => {
711 pub fn get_gl_context(&self) -> OptionGlContextPtr {
713 Some(self.gl_context.clone())
714 }
715 };
716}
717
718#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
719#[repr(C)]
720pub struct DomNodeId {
721 pub dom: DomId,
722 pub node: NodeHierarchyItemId,
723}
724
725impl_option!(
726 DomNodeId,
727 OptionDomNodeId,
728 [Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
729);
730
731impl DomNodeId {
732 pub const ROOT: DomNodeId = DomNodeId {
733 dom: DomId::ROOT_ID,
734 node: NodeHierarchyItemId::NONE,
735 };
736}
737pub type LayoutCallbackType = extern "C" fn(&mut RefAny, &mut LayoutCallbackInfo) -> StyledDom;
754
755#[repr(C)]
756pub struct LayoutCallbackInner {
757 pub cb: LayoutCallbackType,
758}
759impl_callback!(LayoutCallbackInner);
760
761extern "C" fn default_layout_callback(_: &mut RefAny, _: &mut LayoutCallbackInfo) -> StyledDom {
762 StyledDom::default()
763}
764
765pub type MarshaledLayoutCallbackType = extern "C" fn(
773 &mut RefAny,
774 &mut RefAny,
775 &mut LayoutCallbackInfo,
776) -> StyledDom;
777
778#[derive(Debug, Clone, PartialEq)]
779#[repr(C, u8)]
780pub enum LayoutCallback {
781 Raw(LayoutCallbackInner),
782 Marshaled(MarshaledLayoutCallback),
783}
784
785impl Default for LayoutCallback {
786 fn default() -> Self {
787 Self::Raw(LayoutCallbackInner {
788 cb: default_layout_callback,
789 })
790 }
791}
792
793#[derive(Debug, Clone, PartialEq)]
794#[repr(C)]
795pub struct MarshaledLayoutCallback {
796 pub marshal_data: RefAny,
797 pub cb: MarshaledLayoutCallbackInner,
798}
799
800#[repr(C)]
801pub struct MarshaledLayoutCallbackInner {
802 pub cb: MarshaledLayoutCallbackType,
803}
804
805impl_callback!(MarshaledLayoutCallbackInner);
806
807#[repr(C)]
816pub struct Callback {
817 pub cb: CallbackType,
818}
819impl_callback!(Callback);
820
821impl_option!(
822 Callback,
823 OptionCallback,
824 [Debug, Eq, Copy, Clone, PartialEq, PartialOrd, Ord, Hash]
825);
826
827#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
828#[repr(C)]
829pub struct InlineTextHit {
830 pub unicode_codepoint: OptionChar, pub hit_relative_to_inline_text: LogicalPosition,
835 pub hit_relative_to_line: LogicalPosition,
836 pub hit_relative_to_text_content: LogicalPosition,
837 pub hit_relative_to_glyph: LogicalPosition,
838
839 pub line_index_relative_to_text: usize,
841 pub word_index_relative_to_text: usize,
842 pub text_content_index_relative_to_text: usize,
843 pub glyph_index_relative_to_text: usize,
844 pub char_index_relative_to_text: usize,
845
846 pub word_index_relative_to_line: usize,
848 pub text_content_index_relative_to_line: usize,
849 pub glyph_index_relative_to_line: usize,
850 pub char_index_relative_to_line: usize,
851
852 pub glyph_index_relative_to_word: usize,
854 pub char_index_relative_to_word: usize,
855}
856
857impl_vec!(InlineTextHit, InlineTextHitVec, InlineTextHitVecDestructor);
858impl_vec_clone!(InlineTextHit, InlineTextHitVec, InlineTextHitVecDestructor);
859impl_vec_debug!(InlineTextHit, InlineTextHitVec);
860impl_vec_partialeq!(InlineTextHit, InlineTextHitVec);
861impl_vec_partialord!(InlineTextHit, InlineTextHitVec);
862
863#[derive(Debug, Clone, PartialEq, PartialOrd)]
865#[repr(C)]
866pub struct InlineText {
867 pub lines: InlineLineVec,
869 pub content_size: LogicalSize,
872 pub font_size_px: f32,
874 pub last_word_index: usize,
876 pub baseline_descender_px: f32,
878}
879
880impl_option!(
881 InlineText,
882 OptionInlineText,
883 copy = false,
884 [Debug, Clone, PartialEq, PartialOrd]
885);
886
887impl InlineText {
888 pub fn get_layouted_glyphs(&self) -> LayoutedGlyphs {
899 use crate::display_list::GlyphInstance;
900
901 let default: InlineGlyphVec = Vec::new().into();
902 let default_ref = &default;
903
904 let baseline_descender_px = LogicalPosition::new(0.0, self.baseline_descender_px);
906
907 LayoutedGlyphs {
908 glyphs: self
909 .lines
910 .iter()
911 .flat_map(move |line| {
912 let line_origin = line.bounds.origin;
914
915 line.words.iter().flat_map(move |word| {
916 let (glyphs, mut word_origin) = match word {
917 InlineWord::Tab | InlineWord::Return | InlineWord::Space => {
918 (default_ref, LogicalPosition::zero())
919 }
920 InlineWord::Word(text_contents) => {
921 (&text_contents.glyphs, text_contents.bounds.origin)
922 }
923 };
924
925 word_origin.y = 0.0;
926
927 glyphs.iter().map(move |glyph| GlyphInstance {
928 index: glyph.glyph_index,
929 point: {
930 line_origin
931 + baseline_descender_px
932 + word_origin
933 + glyph.bounds.origin
934 },
935 size: glyph.bounds.size,
936 })
937 })
938 })
939 .collect::<Vec<GlyphInstance>>(),
940 }
941 }
942
943 pub fn hit_test(&self, position: LogicalPosition) -> Vec<InlineTextHit> {
949 let bounds = LogicalRect::new(LogicalPosition::zero(), self.content_size);
950
951 let hit_relative_to_inline_text = match bounds.hit_test(&position) {
952 Some(s) => s,
953 None => return Vec::new(),
954 };
955
956 let mut global_char_hit = 0;
957 let mut global_word_hit = 0;
958 let mut global_glyph_hit = 0;
959 let mut global_text_content_hit = 0;
960
961 let font_size_px = self.font_size_px;
965 let descender_px = self.baseline_descender_px;
966
967 self.lines
968 .iter() .enumerate()
970 .flat_map(|(line_index, line)| {
971
972 let char_at_line_start = global_char_hit;
973 let word_at_line_start = global_word_hit;
974 let glyph_at_line_start = global_glyph_hit;
975 let text_content_at_line_start = global_text_content_hit;
976
977 let mut line_bounds = line.bounds.clone();
978 line_bounds.origin.y -= line.bounds.size.height;
979
980 line_bounds.hit_test(&hit_relative_to_inline_text)
981 .map(|mut hit_relative_to_line| {
982
983 line.words
984 .iter() .flat_map(|word| {
986
987 let char_at_text_content_start = global_char_hit;
988 let glyph_at_text_content_start = global_glyph_hit;
989
990 let word_result = word
991 .get_text_content()
992 .and_then(|text_content| {
993
994 let mut text_content_bounds = text_content.bounds.clone();
995 text_content_bounds.origin.y = 0.0;
996
997 text_content_bounds
998 .hit_test(&hit_relative_to_line)
999 .map(|mut hit_relative_to_text_content| {
1000
1001 text_content.glyphs
1002 .iter() .flat_map(|glyph| {
1004
1005 let mut glyph_bounds = glyph.bounds;
1006 glyph_bounds.origin.y = text_content.bounds.size.height + descender_px - glyph.bounds.size.height;
1007
1008 let result = glyph_bounds
1009 .hit_test(&hit_relative_to_text_content)
1010 .map(|hit_relative_to_glyph| {
1011 InlineTextHit {
1012 unicode_codepoint: glyph.unicode_codepoint,
1013
1014 hit_relative_to_inline_text,
1015 hit_relative_to_line,
1016 hit_relative_to_text_content,
1017 hit_relative_to_glyph,
1018
1019 line_index_relative_to_text: line_index,
1020 word_index_relative_to_text: global_word_hit,
1021 text_content_index_relative_to_text: global_text_content_hit,
1022 glyph_index_relative_to_text: global_glyph_hit,
1023 char_index_relative_to_text: global_char_hit,
1024
1025 word_index_relative_to_line: global_word_hit - word_at_line_start,
1026 text_content_index_relative_to_line: global_text_content_hit - text_content_at_line_start,
1027 glyph_index_relative_to_line: global_glyph_hit - glyph_at_line_start,
1028 char_index_relative_to_line: global_char_hit - char_at_line_start,
1029
1030 glyph_index_relative_to_word: global_glyph_hit - glyph_at_text_content_start,
1031 char_index_relative_to_word: global_char_hit - char_at_text_content_start,
1032 }
1033 });
1034
1035 if glyph.has_codepoint() {
1036 global_char_hit += 1;
1037 }
1038
1039 global_glyph_hit += 1;
1040
1041 result
1042 })
1043 .collect::<Vec<_>>()
1044 })
1045 }).unwrap_or_default();
1046
1047 if word.has_text_content() {
1048 global_text_content_hit += 1;
1049 }
1050
1051 global_word_hit += 1;
1052
1053 word_result.into_iter()
1054 })
1055 .collect::<Vec<_>>()
1056 })
1057 .unwrap_or_default()
1058 .into_iter()
1059
1060 })
1061 .collect::<Vec<_>>()
1062 }
1063}
1064
1065#[derive(Debug, Clone, PartialEq, PartialOrd)]
1066#[repr(C)]
1067pub struct InlineLine {
1068 pub words: InlineWordVec,
1069 pub bounds: LogicalRect,
1070}
1071
1072impl_vec!(InlineLine, InlineLineVec, InlineLineVecDestructor);
1073impl_vec_clone!(InlineLine, InlineLineVec, InlineLineVecDestructor);
1074impl_vec_debug!(InlineLine, InlineLineVec);
1075impl_vec_partialeq!(InlineLine, InlineLineVec);
1076impl_vec_partialord!(InlineLine, InlineLineVec);
1077
1078#[derive(Debug, Clone, PartialEq, PartialOrd)]
1079#[repr(C, u8)]
1080pub enum InlineWord {
1081 Tab,
1082 Return,
1083 Space,
1084 Word(InlineTextContents),
1085}
1086
1087impl InlineWord {
1088 pub fn has_text_content(&self) -> bool {
1089 self.get_text_content().is_some()
1090 }
1091 pub fn get_text_content(&self) -> Option<&InlineTextContents> {
1092 match self {
1093 InlineWord::Tab | InlineWord::Return | InlineWord::Space => None,
1094 InlineWord::Word(tc) => Some(tc),
1095 }
1096 }
1097}
1098
1099impl_vec!(InlineWord, InlineWordVec, InlineWordVecDestructor);
1100impl_vec_clone!(InlineWord, InlineWordVec, InlineWordVecDestructor);
1101impl_vec_debug!(InlineWord, InlineWordVec);
1102impl_vec_partialeq!(InlineWord, InlineWordVec);
1103impl_vec_partialord!(InlineWord, InlineWordVec);
1104
1105#[derive(Debug, Clone, PartialEq, PartialOrd)]
1106#[repr(C)]
1107pub struct InlineTextContents {
1108 pub glyphs: InlineGlyphVec,
1109 pub bounds: LogicalRect,
1110}
1111
1112#[derive(Debug, Clone, PartialEq, PartialOrd)]
1113#[repr(C)]
1114pub struct InlineGlyph {
1115 pub bounds: LogicalRect,
1116 pub unicode_codepoint: OptionChar,
1117 pub glyph_index: u32,
1118}
1119
1120impl InlineGlyph {
1121 pub fn has_codepoint(&self) -> bool {
1122 self.unicode_codepoint.is_some()
1123 }
1124}
1125
1126impl_vec!(InlineGlyph, InlineGlyphVec, InlineGlyphVecDestructor);
1127impl_vec_clone!(InlineGlyph, InlineGlyphVec, InlineGlyphVecDestructor);
1128impl_vec_debug!(InlineGlyph, InlineGlyphVec);
1129impl_vec_partialeq!(InlineGlyph, InlineGlyphVec);
1130impl_vec_partialord!(InlineGlyph, InlineGlyphVec);
1131
1132#[derive(Debug)]
1134#[repr(C)]
1135pub struct CallbackInfo {
1136 layout_results: *const LayoutResult,
1138 layout_results_count: usize,
1140 renderer_resources: *const RendererResources,
1142 previous_window_state: *const Option<FullWindowState>,
1144 current_window_state: *const FullWindowState,
1146 modifiable_window_state: *mut WindowState,
1148 gl_context: *const OptionGlContextPtr,
1150 image_cache: *mut ImageCache,
1152 system_fonts: *mut FcFontCache,
1154 timers: *mut FastHashMap<TimerId, Timer>,
1156 threads: *mut FastHashMap<ThreadId, Thread>,
1158 timers_removed: *mut FastBTreeSet<TimerId>,
1160 threads_removed: *mut FastBTreeSet<ThreadId>,
1162 current_window_handle: *const RawWindowHandle,
1164 new_windows: *mut Vec<WindowCreateOptions>,
1167 system_callbacks: *const ExternalSystemCallbacks,
1169 stop_propagation: *mut bool,
1171 focus_target: *mut Option<FocusTarget>,
1175 words_changed_in_callbacks: *mut BTreeMap<DomId, BTreeMap<NodeId, AzString>>,
1177 images_changed_in_callbacks:
1179 *mut BTreeMap<DomId, BTreeMap<NodeId, (ImageRef, UpdateImageType)>>,
1180 image_masks_changed_in_callbacks: *mut BTreeMap<DomId, BTreeMap<NodeId, ImageMask>>,
1182 css_properties_changed_in_callbacks: *mut BTreeMap<DomId, BTreeMap<NodeId, Vec<CssProperty>>>,
1185 current_scroll_states: *const BTreeMap<DomId, BTreeMap<NodeHierarchyItemId, ScrollPosition>>,
1187 nodes_scrolled_in_callback:
1190 *mut BTreeMap<DomId, BTreeMap<NodeHierarchyItemId, LogicalPosition>>,
1191 hit_dom_node: DomNodeId,
1195 cursor_relative_to_item: OptionLogicalPosition,
1198 cursor_in_viewport: OptionLogicalPosition,
1200 _abi_ref: *const c_void,
1202 _abi_mut: *mut c_void,
1204}
1205
1206impl CallbackInfo {
1207 #[inline]
1211 pub fn new<'a, 'b>(
1212 layout_results: &'a [LayoutResult],
1213 renderer_resources: &'a RendererResources,
1214 previous_window_state: &'a Option<FullWindowState>,
1215 current_window_state: &'a FullWindowState,
1216 modifiable_window_state: &'a mut WindowState,
1217 gl_context: &'a OptionGlContextPtr,
1218 image_cache: &'a mut ImageCache,
1219 system_fonts: &'a mut FcFontCache,
1220 timers: &'a mut FastHashMap<TimerId, Timer>,
1221 threads: &'a mut FastHashMap<ThreadId, Thread>,
1222 timers_removed: &'a mut FastBTreeSet<TimerId>,
1223 threads_removed: &'a mut FastBTreeSet<ThreadId>,
1224 current_window_handle: &'a RawWindowHandle,
1225 new_windows: &'a mut Vec<WindowCreateOptions>,
1226 system_callbacks: &'a ExternalSystemCallbacks,
1227 stop_propagation: &'a mut bool,
1228 focus_target: &'a mut Option<FocusTarget>,
1229 words_changed_in_callbacks: &'a mut BTreeMap<DomId, BTreeMap<NodeId, AzString>>,
1230 images_changed_in_callbacks: &'a mut BTreeMap<
1231 DomId,
1232 BTreeMap<NodeId, (ImageRef, UpdateImageType)>,
1233 >,
1234 image_masks_changed_in_callbacks: &'a mut BTreeMap<DomId, BTreeMap<NodeId, ImageMask>>,
1235 css_properties_changed_in_callbacks: &'a mut BTreeMap<
1236 DomId,
1237 BTreeMap<NodeId, Vec<CssProperty>>,
1238 >,
1239 current_scroll_states: &'a BTreeMap<DomId, BTreeMap<NodeHierarchyItemId, ScrollPosition>>,
1240 nodes_scrolled_in_callback: &'a mut BTreeMap<
1241 DomId,
1242 BTreeMap<NodeHierarchyItemId, LogicalPosition>,
1243 >,
1244 hit_dom_node: DomNodeId,
1245 cursor_relative_to_item: OptionLogicalPosition,
1246 cursor_in_viewport: OptionLogicalPosition,
1247 ) -> Self {
1248 Self {
1249 layout_results: layout_results.as_ptr(),
1250 layout_results_count: layout_results.len(),
1251 renderer_resources: renderer_resources as *const RendererResources,
1252 previous_window_state: previous_window_state as *const Option<FullWindowState>,
1253 current_window_state: current_window_state as *const FullWindowState,
1254 modifiable_window_state: modifiable_window_state as *mut WindowState,
1255 gl_context: gl_context as *const OptionGlContextPtr,
1256 image_cache: image_cache as *mut ImageCache,
1257 system_fonts: system_fonts as *mut FcFontCache,
1258 timers: timers as *mut FastHashMap<TimerId, Timer>,
1259 threads: threads as *mut FastHashMap<ThreadId, Thread>,
1260 timers_removed: timers_removed as *mut FastBTreeSet<TimerId>,
1261 threads_removed: threads_removed as *mut FastBTreeSet<ThreadId>,
1262 new_windows: new_windows as *mut Vec<WindowCreateOptions>,
1263 current_window_handle: current_window_handle as *const RawWindowHandle,
1264 system_callbacks: system_callbacks as *const ExternalSystemCallbacks,
1265 stop_propagation: stop_propagation as *mut bool,
1266 focus_target: focus_target as *mut Option<FocusTarget>,
1267 words_changed_in_callbacks: words_changed_in_callbacks
1268 as *mut BTreeMap<DomId, BTreeMap<NodeId, AzString>>,
1269 images_changed_in_callbacks: images_changed_in_callbacks
1270 as *mut BTreeMap<DomId, BTreeMap<NodeId, (ImageRef, UpdateImageType)>>,
1271 image_masks_changed_in_callbacks: image_masks_changed_in_callbacks
1272 as *mut BTreeMap<DomId, BTreeMap<NodeId, ImageMask>>,
1273 css_properties_changed_in_callbacks: css_properties_changed_in_callbacks
1274 as *mut BTreeMap<DomId, BTreeMap<NodeId, Vec<CssProperty>>>,
1275 current_scroll_states: current_scroll_states
1276 as *const BTreeMap<DomId, BTreeMap<NodeHierarchyItemId, ScrollPosition>>,
1277 nodes_scrolled_in_callback: nodes_scrolled_in_callback
1278 as *mut BTreeMap<DomId, BTreeMap<NodeHierarchyItemId, LogicalPosition>>,
1279 hit_dom_node,
1280 cursor_relative_to_item,
1281 cursor_in_viewport,
1282 _abi_ref: core::ptr::null(),
1283 _abi_mut: core::ptr::null_mut(),
1284 }
1285 }
1286
1287 fn internal_get_layout_results<'a>(&'a self) -> &'a [LayoutResult] {
1288 unsafe { core::slice::from_raw_parts(self.layout_results, self.layout_results_count) }
1289 }
1290 fn internal_get_renderer_resources<'a>(&'a self) -> &'a RendererResources {
1291 unsafe { &*self.renderer_resources }
1292 }
1293 fn internal_get_previous_window_state<'a>(&'a self) -> &'a Option<FullWindowState> {
1294 unsafe { &*self.previous_window_state }
1295 }
1296 fn internal_get_current_window_state<'a>(&'a self) -> &'a FullWindowState {
1297 unsafe { &*self.current_window_state }
1298 }
1299 fn internal_get_modifiable_window_state<'a>(&'a mut self) -> &'a mut WindowState {
1300 unsafe { &mut *self.modifiable_window_state }
1301 }
1302 fn internal_get_gl_context<'a>(&'a self) -> &'a OptionGlContextPtr {
1303 unsafe { &*self.gl_context }
1304 }
1305 fn internal_get_image_cache<'a>(&'a mut self) -> &'a mut ImageCache {
1306 unsafe { &mut *self.image_cache }
1307 }
1308 fn internal_get_image_cache_ref<'a>(&'a self) -> &'a ImageCache {
1309 unsafe { &*self.image_cache }
1310 }
1311 fn internal_get_system_fonts<'a>(&'a mut self) -> &'a mut FcFontCache {
1312 unsafe { &mut *self.system_fonts }
1313 }
1314 fn internal_get_timers<'a>(&'a mut self) -> &'a mut FastHashMap<TimerId, Timer> {
1315 unsafe { &mut *self.timers }
1316 }
1317 fn internal_get_threads<'a>(&'a mut self) -> &'a mut FastHashMap<ThreadId, Thread> {
1318 unsafe { &mut *self.threads }
1319 }
1320 fn internal_get_timers_removed<'a>(&'a mut self) -> &'a mut FastBTreeSet<TimerId> {
1321 unsafe { &mut *self.timers_removed }
1322 }
1323 fn internal_get_threads_removed<'a>(&'a mut self) -> &'a mut FastBTreeSet<ThreadId> {
1324 unsafe { &mut *self.threads_removed }
1325 }
1326 fn internal_get_new_windows<'a>(&'a mut self) -> &'a mut Vec<WindowCreateOptions> {
1327 unsafe { &mut *self.new_windows }
1328 }
1329 fn internal_get_current_window_handle<'a>(&'a self) -> &'a RawWindowHandle {
1330 unsafe { &*self.current_window_handle }
1331 }
1332 fn internal_get_extern_system_callbacks<'a>(&'a self) -> &'a ExternalSystemCallbacks {
1333 unsafe { &*self.system_callbacks }
1334 }
1335 fn internal_get_stop_propagation<'a>(&'a mut self) -> &'a mut bool {
1336 unsafe { &mut *self.stop_propagation }
1337 }
1338 fn internal_get_focus_target<'a>(&'a mut self) -> &'a mut Option<FocusTarget> {
1339 unsafe { &mut *self.focus_target }
1340 }
1341 fn internal_get_current_scroll_states<'a>(
1342 &'a self,
1343 ) -> &'a BTreeMap<DomId, BTreeMap<NodeHierarchyItemId, ScrollPosition>> {
1344 unsafe { &*self.current_scroll_states }
1345 }
1346 fn internal_get_css_properties_changed_in_callbacks<'a>(
1347 &'a mut self,
1348 ) -> &'a mut BTreeMap<DomId, BTreeMap<NodeId, Vec<CssProperty>>> {
1349 unsafe { &mut *self.css_properties_changed_in_callbacks }
1350 }
1351 fn internal_get_nodes_scrolled_in_callback<'a>(
1352 &'a mut self,
1353 ) -> &'a mut BTreeMap<DomId, BTreeMap<NodeHierarchyItemId, LogicalPosition>> {
1354 unsafe { &mut *self.nodes_scrolled_in_callback }
1355 }
1356 fn internal_get_hit_dom_node<'a>(&'a self) -> DomNodeId {
1357 self.hit_dom_node
1358 }
1359 fn internal_get_cursor_relative_to_item<'a>(&'a self) -> OptionLogicalPosition {
1360 self.cursor_relative_to_item
1361 }
1362 fn internal_get_cursor_in_viewport<'a>(&'a self) -> OptionLogicalPosition {
1363 self.cursor_in_viewport
1364 }
1365 fn internal_get_words_changed_in_callbacks<'a>(
1366 &'a mut self,
1367 ) -> &'a mut BTreeMap<DomId, BTreeMap<NodeId, AzString>> {
1368 unsafe { &mut *self.words_changed_in_callbacks }
1369 }
1370 fn internal_get_images_changed_in_callbacks<'a>(
1371 &'a mut self,
1372 ) -> &'a mut BTreeMap<DomId, BTreeMap<NodeId, (ImageRef, UpdateImageType)>> {
1373 unsafe { &mut *self.images_changed_in_callbacks }
1374 }
1375 fn internal_get_image_masks_changed_in_callbacks<'a>(
1376 &'a mut self,
1377 ) -> &'a mut BTreeMap<DomId, BTreeMap<NodeId, ImageMask>> {
1378 unsafe { &mut *self.image_masks_changed_in_callbacks }
1379 }
1380
1381 pub fn get_hit_node(&self) -> DomNodeId {
1383 self.internal_get_hit_dom_node()
1384 }
1385 pub fn get_system_time_fn(&self) -> GetSystemTimeCallback {
1386 self.internal_get_extern_system_callbacks()
1387 .get_system_time_fn
1388 }
1389 pub fn get_thread_create_fn(&self) -> CreateThreadCallback {
1390 self.internal_get_extern_system_callbacks().create_thread_fn
1391 }
1392 pub fn get_cursor_relative_to_node(&self) -> OptionLogicalPosition {
1393 self.internal_get_cursor_relative_to_item()
1394 }
1395 pub fn get_cursor_relative_to_viewport(&self) -> OptionLogicalPosition {
1396 self.internal_get_cursor_in_viewport()
1397 }
1398 pub fn get_current_window_state(&self) -> WindowState {
1399 self.internal_get_current_window_state().clone().into()
1400 }
1401 pub fn get_current_window_flags(&self) -> WindowFlags {
1402 self.internal_get_current_window_state().flags.clone()
1403 }
1404 pub fn get_current_keyboard_state(&self) -> KeyboardState {
1405 self.internal_get_current_window_state()
1406 .keyboard_state
1407 .clone()
1408 }
1409 pub fn get_current_mouse_state(&self) -> MouseState {
1410 self.internal_get_current_window_state().mouse_state.clone()
1411 }
1412 pub fn get_previous_window_state(&self) -> Option<WindowState> {
1413 Some(
1414 self.internal_get_previous_window_state()
1415 .as_ref()?
1416 .clone()
1417 .into(),
1418 )
1419 }
1420 pub fn get_previous_keyboard_state(&self) -> Option<KeyboardState> {
1421 Some(
1422 self.internal_get_previous_window_state()
1423 .as_ref()?
1424 .keyboard_state
1425 .clone(),
1426 )
1427 }
1428 pub fn get_previous_mouse_state(&self) -> Option<MouseState> {
1429 Some(
1430 self.internal_get_previous_window_state()
1431 .as_ref()?
1432 .mouse_state
1433 .clone(),
1434 )
1435 }
1436 pub fn get_current_window_handle(&self) -> RawWindowHandle {
1437 self.internal_get_current_window_handle().clone()
1438 }
1439 pub fn get_current_time(&self) -> Instant {
1440 (self
1441 .internal_get_extern_system_callbacks()
1442 .get_system_time_fn
1443 .cb)()
1444 }
1445 pub fn get_gl_context(&self) -> OptionGlContextPtr {
1446 self.internal_get_gl_context().clone()
1447 }
1448
1449 pub fn get_scroll_position(&self, node_id: DomNodeId) -> Option<LogicalPosition> {
1450 self.internal_get_current_scroll_states()
1451 .get(&node_id.dom)?
1452 .get(&node_id.node)
1453 .map(|sp| {
1454 LogicalPosition::new(
1455 sp.children_rect.origin.x - sp.parent_rect.origin.x,
1456 sp.children_rect.origin.y - sp.parent_rect.origin.y,
1457 )
1458 })
1459 }
1460
1461 pub fn set_scroll_position(&mut self, node_id: DomNodeId, scroll_position: LogicalPosition) {
1462 self.internal_get_nodes_scrolled_in_callback()
1463 .entry(node_id.dom)
1464 .or_insert_with(|| BTreeMap::new())
1465 .insert(node_id.node, scroll_position);
1466 }
1467
1468 pub fn get_parent(&self, node_id: DomNodeId) -> Option<DomNodeId> {
1469 let nid = node_id.node.into_crate_internal()?;
1470 self.internal_get_layout_results()
1471 .get(node_id.dom.inner)?
1472 .styled_dom
1473 .node_hierarchy
1474 .as_container()
1475 .get(node_id.node.into_crate_internal()?)?
1476 .parent_id()
1477 .map(|nid| DomNodeId {
1478 dom: node_id.dom,
1479 node: NodeHierarchyItemId::from_crate_internal(Some(nid)),
1480 })
1481 }
1482
1483 pub fn get_previous_sibling(&self, node_id: DomNodeId) -> Option<DomNodeId> {
1484 let nid = node_id.node.into_crate_internal()?;
1485 self.internal_get_layout_results()
1486 .get(node_id.dom.inner)?
1487 .styled_dom
1488 .node_hierarchy
1489 .as_container()
1490 .get(node_id.node.into_crate_internal()?)?
1491 .previous_sibling_id()
1492 .map(|nid| DomNodeId {
1493 dom: node_id.dom,
1494 node: NodeHierarchyItemId::from_crate_internal(Some(nid)),
1495 })
1496 }
1497
1498 pub fn get_next_sibling(&self, node_id: DomNodeId) -> Option<DomNodeId> {
1499 let nid = node_id.node.into_crate_internal()?;
1500 self.internal_get_layout_results()
1501 .get(node_id.dom.inner)?
1502 .styled_dom
1503 .node_hierarchy
1504 .as_container()
1505 .get(node_id.node.into_crate_internal()?)?
1506 .next_sibling_id()
1507 .map(|nid| DomNodeId {
1508 dom: node_id.dom,
1509 node: NodeHierarchyItemId::from_crate_internal(Some(nid)),
1510 })
1511 }
1512
1513 pub fn get_first_child(&self, node_id: DomNodeId) -> Option<DomNodeId> {
1514 let nid = node_id.node.into_crate_internal()?;
1515 self.internal_get_layout_results()
1516 .get(node_id.dom.inner)?
1517 .styled_dom
1518 .node_hierarchy
1519 .as_container()
1520 .get(nid)?
1521 .first_child_id(nid)
1522 .map(|nid| DomNodeId {
1523 dom: node_id.dom,
1524 node: NodeHierarchyItemId::from_crate_internal(Some(nid)),
1525 })
1526 }
1527
1528 pub fn get_last_child(&self, node_id: DomNodeId) -> Option<DomNodeId> {
1529 let nid = node_id.node.into_crate_internal()?;
1530 self.internal_get_layout_results()
1531 .get(node_id.dom.inner)?
1532 .styled_dom
1533 .node_hierarchy
1534 .as_container()
1535 .get(node_id.node.into_crate_internal()?)?
1536 .last_child_id()
1537 .map(|nid| DomNodeId {
1538 dom: node_id.dom,
1539 node: NodeHierarchyItemId::from_crate_internal(Some(nid)),
1540 })
1541 }
1542
1543 pub fn get_dataset(&mut self, node_id: DomNodeId) -> Option<RefAny> {
1544 self.internal_get_layout_results()
1545 .get(node_id.dom.inner)?
1546 .styled_dom
1547 .node_data
1548 .as_container()
1549 .get(node_id.node.into_crate_internal()?)?
1550 .dataset
1551 .as_ref()
1552 .map(|s| s.clone())
1553 }
1554
1555 pub fn get_node_id_of_root_dataset(&mut self, search_key: RefAny) -> Option<DomNodeId> {
1556 let mut found: Option<(u64, DomNodeId)> = None;
1557
1558 for (dom_node_id, layout_result) in self.internal_get_layout_results().iter().enumerate() {
1559 for (node_id, node_data) in layout_result
1560 .styled_dom
1561 .node_data
1562 .as_container()
1563 .iter()
1564 .enumerate()
1565 {
1566 if let Some(dataset) = node_data.dataset.as_ref() {
1567 if dataset._internal_ptr as usize != search_key._internal_ptr as usize {
1569 continue;
1570 }
1571
1572 let node_id = DomNodeId {
1573 dom: DomId { inner: dom_node_id },
1574 node: NodeHierarchyItemId::from_crate_internal(Some(NodeId::new(node_id))),
1575 };
1576
1577 if (dataset.instance_id as u64)
1578 < found.as_ref().map(|s| s.0).unwrap_or(u64::MAX)
1579 {
1580 found = Some((dataset.instance_id, node_id))
1581 }
1582 }
1583 }
1584 }
1585
1586 found.map(|s| s.1)
1587 }
1588
1589 pub fn set_window_state(&mut self, new_state: WindowState) {
1590 *self.internal_get_modifiable_window_state() = new_state;
1591 }
1592
1593 pub fn set_window_flags(&mut self, new_flags: WindowFlags) {
1594 self.internal_get_modifiable_window_state().flags = new_flags;
1595 }
1596
1597 pub fn set_css_property(&mut self, node_id: DomNodeId, prop: CssProperty) {
1598 if let Some(nid) = node_id.node.into_crate_internal() {
1599 self.internal_get_css_properties_changed_in_callbacks()
1600 .entry(node_id.dom)
1601 .or_insert_with(|| BTreeMap::new())
1602 .entry(nid)
1603 .or_insert_with(|| Vec::new())
1604 .push(prop);
1605 }
1606 }
1607
1608 pub fn set_focus(&mut self, target: FocusTarget) {
1609 *self.internal_get_focus_target() = Some(target);
1610 }
1611
1612 pub fn get_string_contents(&self, node_id: DomNodeId) -> Option<AzString> {
1613 self.internal_get_layout_results()
1614 .get(node_id.dom.inner)?
1615 .words_cache
1616 .get(&node_id.node.into_crate_internal()?)
1617 .map(|words| words.internal_str.clone())
1618 }
1619
1620 pub fn set_string_contents(&mut self, node_id: DomNodeId, new_string_contents: AzString) {
1621 if let Some(nid) = node_id.node.into_crate_internal() {
1622 self.internal_get_words_changed_in_callbacks()
1623 .entry(node_id.dom)
1624 .or_insert_with(|| BTreeMap::new())
1625 .insert(nid, new_string_contents);
1626 }
1627 }
1628
1629 pub fn get_inline_text(&self, node_id: DomNodeId) -> Option<InlineText> {
1630 let nid = node_id.node.into_crate_internal()?;
1631 let layout_result = self.internal_get_layout_results().get(node_id.dom.inner)?;
1632 let words = layout_result.words_cache.get(&nid)?;
1633 let shaped_words = layout_result.shaped_words_cache.get(&nid)?;
1634 let word_positions = layout_result.positioned_words_cache.get(&nid)?;
1635 let positioned_rectangles = layout_result.rects.as_ref();
1636 let positioned_rectangle = positioned_rectangles.get(nid)?;
1637 let (_, inline_text_layout) = positioned_rectangle.resolved_text_layout_options.as_ref()?;
1638 Some(crate::app_resources::get_inline_text(
1639 &words,
1640 &shaped_words,
1641 &word_positions.0,
1642 &inline_text_layout,
1643 ))
1644 }
1645
1646 pub fn get_font_ref(&self, node_id: DomNodeId) -> Option<FontRef> {
1648 use crate::styled_dom::StyleFontFamiliesHash;
1649
1650 let layout_result = self.internal_get_layout_results().get(node_id.dom.inner)?;
1651 let renderer_resources = self.internal_get_renderer_resources();
1652
1653 let node_data = layout_result.styled_dom.node_data.as_container();
1654 let node_data = node_data.get(node_id.node.into_crate_internal()?)?;
1655
1656 if !node_data.is_text_node() {
1657 return None;
1658 }
1659
1660 let nid = node_id.node.into_crate_internal()?;
1661 let styled_nodes = layout_result.styled_dom.styled_nodes.as_container();
1662 styled_nodes
1663 .get(nid)
1664 .map(|s| {
1665 layout_result
1666 .styled_dom
1667 .css_property_cache
1668 .ptr
1669 .get_font_id_or_default(node_data, &nid, &s.state)
1670 })
1671 .map(|css_font_families| StyleFontFamiliesHash::new(css_font_families.as_ref()))
1672 .and_then(|css_font_families_hash| {
1673 renderer_resources.get_font_family(&css_font_families_hash)
1674 })
1675 .and_then(|css_font_family| renderer_resources.get_font_key(&css_font_family))
1676 .and_then(|font_key| renderer_resources.get_registered_font(&font_key))
1677 .map(|f| f.0.clone())
1678 }
1679
1680 pub fn get_text_layout_options(&self, node_id: DomNodeId) -> Option<ResolvedTextLayoutOptions> {
1681 let layout_result = self.internal_get_layout_results().get(node_id.dom.inner)?;
1682 let nid = node_id.node.into_crate_internal()?;
1683 let positioned_rectangles = layout_result.rects.as_ref();
1684 let positioned_rectangle = positioned_rectangles.get(nid)?;
1685 let (text_layout_options, _) =
1686 positioned_rectangle.resolved_text_layout_options.as_ref()?;
1687 Some(text_layout_options.clone())
1688 }
1689
1690 pub fn get_computed_css_property(
1691 &self,
1692 node_id: DomNodeId,
1693 property_type: CssPropertyType,
1694 ) -> Option<CssProperty> {
1695 let layout_result = self.internal_get_layout_results().get(node_id.dom.inner)?;
1696
1697 None
1712 }
1713
1714 pub fn stop_propagation(&mut self) {
1715 *self.internal_get_stop_propagation() = true;
1716 }
1717
1718 pub fn create_window(&mut self, window: WindowCreateOptions) {
1719 self.internal_get_new_windows().push(window);
1720 }
1721
1722 pub fn start_thread(
1724 &mut self,
1725 thread_initialize_data: RefAny,
1726 writeback_data: RefAny,
1727 callback: ThreadCallbackType,
1728 ) -> Option<ThreadId> {
1729 if thread_initialize_data.has_no_copies() {
1730 let callback = ThreadCallback { cb: callback };
1731 let thread_id = ThreadId::unique();
1732 let thread = (self
1733 .internal_get_extern_system_callbacks()
1734 .create_thread_fn
1735 .cb)(thread_initialize_data, writeback_data, callback);
1736 self.internal_get_threads().insert(thread_id, thread);
1737 Some(thread_id)
1738 } else {
1739 None
1740 }
1741 }
1742
1743 #[cfg(feature = "std")]
1744 pub fn send_thread_msg(&mut self, thread_id: ThreadId, msg: ThreadSendMsg) -> bool {
1745 if let Some(thread) = self.internal_get_threads().get_mut(&thread_id) {
1746 if let Some(s) = thread.ptr.lock().ok() {
1747 s.sender.send(msg).is_ok()
1748 } else {
1749 false
1750 }
1751 } else {
1752 false
1753 }
1754 }
1755
1756 pub fn stop_thread(&mut self, thread_id: ThreadId) -> bool {
1758 self.internal_get_threads_removed().insert(thread_id)
1759 }
1760
1761 pub fn start_timer(&mut self, timer: Timer) -> TimerId {
1762 let timer_id = TimerId::unique();
1763 self.internal_get_timers().insert(timer_id, timer);
1765 timer_id
1766 }
1767
1768 pub fn start_animation(
1769 &mut self,
1770 dom_node_id: DomNodeId,
1771 animation: Animation,
1772 ) -> Option<TimerId> {
1773 use crate::task::SystemTimeDiff;
1774
1775 let layout_result = self
1776 .internal_get_layout_results()
1777 .get(dom_node_id.dom.inner)?;
1778 let nid = dom_node_id.node.into_crate_internal()?;
1779
1780 let timer_duration = if animation.repeat == AnimationRepeat::NoRepeat {
1782 Some(animation.duration.clone())
1783 } else {
1784 None };
1786
1787 let parent_id = layout_result
1788 .styled_dom
1789 .node_hierarchy
1790 .as_container()
1791 .get(nid)?
1792 .parent_id()
1793 .unwrap_or(NodeId::ZERO);
1794 let current_size = layout_result.rects.as_ref().get(nid)?.size;
1795 let parent_size = layout_result.rects.as_ref().get(nid)?.size;
1796
1797 if animation.from.get_type() != animation.to.get_type() {
1798 return None;
1799 }
1800
1801 let timer_id = TimerId::unique();
1802
1803 let now = self.get_current_time();
1804
1805 let animation_data = AnimationData {
1806 from: animation.from,
1807 to: animation.to,
1808 start: now.clone(),
1809 repeat: animation.repeat,
1810 interpolate: animation.easing,
1811 duration: animation.duration,
1812 relayout_on_finish: animation.relayout_on_finish,
1813 parent_rect_width: parent_size.width,
1814 parent_rect_height: parent_size.height,
1815 current_rect_width: current_size.width,
1816 current_rect_height: current_size.height,
1817 get_system_time_fn: self
1818 .internal_get_extern_system_callbacks()
1819 .get_system_time_fn
1820 .clone(),
1821 };
1822
1823 let timer = Timer {
1824 data: RefAny::new(animation_data),
1825 node_id: Some(dom_node_id).into(),
1826 created: now,
1827 run_count: 0,
1828 last_run: None.into(),
1829 delay: None.into(),
1830 interval: Some(AzDuration::System(SystemTimeDiff::from_millis(10))).into(),
1831 timeout: timer_duration.into(),
1832 callback: TimerCallback {
1833 cb: drive_animation_func,
1834 },
1835 };
1836
1837 self.internal_get_timers().insert(timer_id, timer);
1838
1839 Some(timer_id)
1840 }
1841
1842 pub fn stop_timer(&mut self, timer_id: TimerId) -> bool {
1843 self.internal_get_timers_removed().insert(timer_id)
1844 }
1845
1846 pub fn get_node_position(&self, node_id: DomNodeId) -> Option<PositionInfo> {
1847 let layout_result = self.internal_get_layout_results().get(node_id.dom.inner)?;
1848 let nid = node_id.node.into_crate_internal()?;
1849 let positioned_rectangles = layout_result.rects.as_ref();
1850 let positioned_rectangle = positioned_rectangles.get(nid)?;
1851 Some(positioned_rectangle.position)
1852 }
1853
1854 pub fn get_node_size(&self, node_id: DomNodeId) -> Option<LogicalSize> {
1855 let layout_result = self.internal_get_layout_results().get(node_id.dom.inner)?;
1856 let nid = node_id.node.into_crate_internal()?;
1857 let positioned_rectangles = layout_result.rects.as_ref();
1858 let positioned_rectangle = positioned_rectangles.get(nid)?;
1859 Some(positioned_rectangle.size)
1860 }
1861
1862 pub fn add_image(&mut self, css_id: AzString, image: ImageRef) {
1864 self.internal_get_image_cache()
1865 .add_css_image_id(css_id, image);
1866 }
1867
1868 pub fn has_image(&self, css_id: &AzString) -> bool {
1869 self.internal_get_image_cache_ref()
1870 .get_css_image_id(css_id)
1871 .is_some()
1872 }
1873
1874 pub fn get_image(&self, css_id: &AzString) -> Option<ImageRef> {
1875 self.internal_get_image_cache_ref()
1876 .get_css_image_id(css_id)
1877 .cloned()
1878 }
1879
1880 pub fn delete_image(&mut self, css_id: &AzString) {
1882 self.internal_get_image_cache().delete_css_image_id(css_id);
1883 }
1884
1885 pub fn update_image(
1886 &mut self,
1887 node_id: DomNodeId,
1888 new_image: ImageRef,
1889 image_type: UpdateImageType,
1890 ) {
1891 if let Some(nid) = node_id.node.into_crate_internal() {
1892 self.internal_get_images_changed_in_callbacks()
1893 .entry(node_id.dom)
1894 .or_insert_with(|| BTreeMap::new())
1895 .insert(nid, (new_image, image_type));
1896 }
1897 }
1898
1899 pub fn update_image_mask(&mut self, node_id: DomNodeId, new_image_mask: ImageMask) {
1900 if let Some(nid) = node_id.node.into_crate_internal() {
1901 self.internal_get_image_masks_changed_in_callbacks()
1902 .entry(node_id.dom)
1903 .or_insert_with(|| BTreeMap::new())
1904 .insert(nid, new_image_mask);
1905 }
1906 }
1907}
1908
1909impl Clone for CallbackInfo {
1910 fn clone(&self) -> Self {
1911 Self {
1912 layout_results: self.layout_results,
1913 layout_results_count: self.layout_results_count,
1914 renderer_resources: self.renderer_resources,
1915 previous_window_state: self.previous_window_state,
1916 current_window_state: self.current_window_state,
1917 modifiable_window_state: self.modifiable_window_state,
1918 gl_context: self.gl_context,
1919 image_cache: self.image_cache,
1920 system_fonts: self.system_fonts,
1921 timers: self.timers,
1922 threads: self.threads,
1923 timers_removed: self.timers_removed,
1924 threads_removed: self.threads_removed,
1925 current_window_handle: self.current_window_handle,
1926 new_windows: self.new_windows,
1927 system_callbacks: self.system_callbacks,
1928 stop_propagation: self.stop_propagation,
1929 focus_target: self.focus_target,
1930 words_changed_in_callbacks: self.words_changed_in_callbacks,
1931 images_changed_in_callbacks: self.images_changed_in_callbacks,
1932 image_masks_changed_in_callbacks: self.image_masks_changed_in_callbacks,
1933 css_properties_changed_in_callbacks: self.css_properties_changed_in_callbacks,
1934 current_scroll_states: self.current_scroll_states,
1935 nodes_scrolled_in_callback: self.nodes_scrolled_in_callback,
1936 hit_dom_node: self.hit_dom_node,
1937 cursor_relative_to_item: self.cursor_relative_to_item,
1938 cursor_in_viewport: self.cursor_in_viewport,
1939 _abi_ref: self._abi_ref,
1940 _abi_mut: self._abi_mut,
1941 }
1942 }
1943}
1944
1945#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1946#[repr(C)]
1947pub enum UpdateImageType {
1948 Background,
1949 Content,
1950}
1951
1952#[derive(Debug, Clone, PartialEq)]
1953pub struct AnimationData {
1954 pub from: CssProperty,
1955 pub to: CssProperty,
1956 pub start: AzInstant,
1957 pub duration: AzDuration,
1958 pub repeat: AnimationRepeat,
1959 pub interpolate: AnimationInterpolationFunction,
1960 pub relayout_on_finish: bool,
1961 pub parent_rect_width: f32,
1962 pub parent_rect_height: f32,
1963 pub current_rect_width: f32,
1964 pub current_rect_height: f32,
1965 pub get_system_time_fn: GetSystemTimeCallback,
1966}
1967
1968#[derive(Debug, Clone, PartialEq)]
1969#[repr(C)]
1970pub struct Animation {
1971 pub from: CssProperty,
1972 pub to: CssProperty,
1973 pub duration: AzDuration,
1974 pub repeat: AnimationRepeat,
1975 pub repeat_times: AnimationRepeatCount,
1976 pub easing: AnimationInterpolationFunction,
1977 pub relayout_on_finish: bool,
1978}
1979
1980#[derive(Debug, Copy, Clone, PartialEq)]
1981#[repr(C)]
1982pub enum AnimationRepeat {
1983 NoRepeat,
1984 Loop,
1985 PingPong,
1986}
1987
1988#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Hash)]
1989#[repr(C, u8)]
1990pub enum AnimationRepeatCount {
1991 Times(usize),
1992 Infinite,
1993}
1994
1995extern "C" fn drive_animation_func(
1997 anim_data: &mut RefAny,
1998 info: &mut TimerCallbackInfo,
1999) -> TimerCallbackReturn {
2000 let mut anim_data = match anim_data.downcast_mut::<AnimationData>() {
2001 Some(s) => s,
2002 None => {
2003 return TimerCallbackReturn {
2004 should_update: Update::DoNothing,
2005 should_terminate: TerminateTimer::Terminate,
2006 };
2007 }
2008 };
2009
2010 let mut anim_data = &mut *anim_data;
2011
2012 let node_id = match info.node_id.into_option() {
2013 Some(s) => s,
2014 None => {
2015 return TimerCallbackReturn {
2016 should_update: Update::DoNothing,
2017 should_terminate: TerminateTimer::Terminate,
2018 };
2019 }
2020 };
2021
2022 let resolver = InterpolateResolver {
2024 parent_rect_width: anim_data.parent_rect_width,
2025 parent_rect_height: anim_data.parent_rect_height,
2026 current_rect_width: anim_data.current_rect_width,
2027 current_rect_height: anim_data.current_rect_height,
2028 interpolate_func: anim_data.interpolate,
2029 };
2030
2031 let anim_next_end = anim_data
2032 .start
2033 .add_optional_duration(Some(&anim_data.duration));
2034 let now = (anim_data.get_system_time_fn.cb)();
2035 let t = now.linear_interpolate(anim_data.start.clone(), anim_next_end.clone());
2036 let interpolated_css = anim_data.from.interpolate(&anim_data.to, t, &resolver);
2037
2038 info.callback_info
2040 .set_css_property(node_id, interpolated_css);
2041
2042 if now > anim_next_end {
2044 match anim_data.repeat {
2045 AnimationRepeat::Loop => {
2046 anim_data.start = now;
2048 }
2049 AnimationRepeat::PingPong => {
2050 use core::mem;
2051 mem::swap(&mut anim_data.from, &mut anim_data.to);
2053 anim_data.start = now;
2054 }
2055 AnimationRepeat::NoRepeat => {
2056 return TimerCallbackReturn {
2058 should_terminate: TerminateTimer::Terminate,
2059 should_update: if anim_data.relayout_on_finish {
2060 Update::RefreshDom
2061 } else {
2062 Update::DoNothing
2063 },
2064 };
2065 }
2066 }
2067 }
2068
2069 if info.is_about_to_finish {
2071 TimerCallbackReturn {
2072 should_terminate: TerminateTimer::Terminate,
2073 should_update: if anim_data.relayout_on_finish {
2074 Update::RefreshDom
2075 } else {
2076 Update::DoNothing
2077 },
2078 }
2079 } else {
2080 TimerCallbackReturn {
2081 should_terminate: TerminateTimer::Continue,
2082 should_update: Update::DoNothing,
2083 }
2084 }
2085}
2086
2087pub type CallbackType = extern "C" fn(&mut RefAny, &mut CallbackInfo) -> Update;
2088
2089#[repr(C)]
2093pub struct RenderImageCallback {
2094 pub cb: RenderImageCallbackType,
2095}
2096impl_callback!(RenderImageCallback);
2097
2098#[derive(Debug)]
2099#[repr(C)]
2100pub struct RenderImageCallbackInfo {
2101 callback_node_id: DomNodeId,
2103 bounds: HidpiAdjustedBounds,
2105 gl_context: *const OptionGlContextPtr,
2107 image_cache: *const ImageCache,
2108 system_fonts: *const FcFontCache,
2109 node_hierarchy: *const NodeHierarchyItemVec,
2110 words_cache: *const BTreeMap<NodeId, Words>,
2111 shaped_words_cache: *const BTreeMap<NodeId, ShapedWords>,
2112 positioned_words_cache: *const BTreeMap<NodeId, (WordPositions, FontInstanceKey)>,
2113 positioned_rects: *const NodeDataContainer<PositionedRectangle>,
2114 _abi_ref: *const c_void,
2116 _abi_mut: *mut c_void,
2118}
2119
2120impl Clone for RenderImageCallbackInfo {
2123 fn clone(&self) -> Self {
2124 Self {
2125 callback_node_id: self.callback_node_id,
2126 bounds: self.bounds,
2127 gl_context: self.gl_context,
2128 image_cache: self.image_cache,
2129 system_fonts: self.system_fonts,
2130 node_hierarchy: self.node_hierarchy,
2131 words_cache: self.words_cache,
2132 shaped_words_cache: self.shaped_words_cache,
2133 positioned_words_cache: self.positioned_words_cache,
2134 positioned_rects: self.positioned_rects,
2135 _abi_ref: self._abi_ref,
2136 _abi_mut: self._abi_mut,
2137 }
2138 }
2139}
2140
2141impl RenderImageCallbackInfo {
2142 pub fn new<'a>(
2143 gl_context: &'a OptionGlContextPtr,
2144 image_cache: &'a ImageCache,
2145 system_fonts: &'a FcFontCache,
2146 node_hierarchy: &'a NodeHierarchyItemVec,
2147 words_cache: &'a BTreeMap<NodeId, Words>,
2148 shaped_words_cache: &'a BTreeMap<NodeId, ShapedWords>,
2149 positioned_words_cache: &'a BTreeMap<NodeId, (WordPositions, FontInstanceKey)>,
2150 positioned_rects: &'a NodeDataContainer<PositionedRectangle>,
2151 bounds: HidpiAdjustedBounds,
2152 callback_node_id: DomNodeId,
2153 ) -> Self {
2154 Self {
2155 callback_node_id,
2156 gl_context: gl_context as *const OptionGlContextPtr,
2157 image_cache: image_cache as *const ImageCache,
2158 system_fonts: system_fonts as *const FcFontCache,
2159 node_hierarchy: node_hierarchy as *const NodeHierarchyItemVec,
2160 words_cache: words_cache as *const BTreeMap<NodeId, Words>,
2161 shaped_words_cache: shaped_words_cache as *const BTreeMap<NodeId, ShapedWords>,
2162 positioned_words_cache: positioned_words_cache
2163 as *const BTreeMap<NodeId, (WordPositions, FontInstanceKey)>,
2164 positioned_rects: positioned_rects as *const NodeDataContainer<PositionedRectangle>,
2165 bounds,
2166 _abi_ref: core::ptr::null(),
2167 _abi_mut: core::ptr::null_mut(),
2168 }
2169 }
2170
2171 fn internal_get_gl_context<'a>(&'a self) -> &'a OptionGlContextPtr {
2172 unsafe { &*self.gl_context }
2173 }
2174 fn internal_get_image_cache<'a>(&'a self) -> &'a ImageCache {
2175 unsafe { &*self.image_cache }
2176 }
2177 fn internal_get_system_fonts<'a>(&'a self) -> &'a FcFontCache {
2178 unsafe { &*self.system_fonts }
2179 }
2180 fn internal_get_bounds<'a>(&'a self) -> HidpiAdjustedBounds {
2181 self.bounds
2182 }
2183 fn internal_get_node_hierarchy<'a>(&'a self) -> &'a NodeHierarchyItemVec {
2184 unsafe { &*self.node_hierarchy }
2185 }
2186 fn internal_get_words_cache<'a>(&'a self) -> &'a BTreeMap<NodeId, Words> {
2187 unsafe { &*self.words_cache }
2188 }
2189 fn internal_get_shaped_words_cache<'a>(&'a self) -> &'a BTreeMap<NodeId, ShapedWords> {
2190 unsafe { &*self.shaped_words_cache }
2191 }
2192 fn internal_get_positioned_words_cache<'a>(
2193 &'a self,
2194 ) -> &'a BTreeMap<NodeId, (WordPositions, FontInstanceKey)> {
2195 unsafe { &*self.positioned_words_cache }
2196 }
2197 fn internal_get_positioned_rectangles<'a>(
2198 &'a self,
2199 ) -> &'a NodeDataContainer<PositionedRectangle> {
2200 unsafe { &*self.positioned_rects }
2201 }
2202
2203 pub fn get_gl_context(&self) -> OptionGlContextPtr {
2204 self.internal_get_gl_context().clone()
2205 }
2206 pub fn get_bounds(&self) -> HidpiAdjustedBounds {
2207 self.internal_get_bounds()
2208 }
2209 pub fn get_callback_node_id(&self) -> DomNodeId {
2210 self.callback_node_id
2211 }
2212
2213 pub fn get_inline_text(&self, node_id: DomNodeId) -> Option<InlineText> {
2217 if node_id.dom != self.get_callback_node_id().dom {
2218 return None;
2219 }
2220
2221 let nid = node_id.node.into_crate_internal()?;
2222 let words = self.internal_get_words_cache();
2223 let words = words.get(&nid)?;
2224 let shaped_words = self.internal_get_shaped_words_cache();
2225 let shaped_words = shaped_words.get(&nid)?;
2226 let word_positions = self.internal_get_positioned_words_cache();
2227 let word_positions = word_positions.get(&nid)?;
2228 let positioned_rectangle = self.internal_get_positioned_rectangles();
2229 let positioned_rectangle = positioned_rectangle.as_ref();
2230 let positioned_rectangle = positioned_rectangle.get(nid)?;
2231 let (_, inline_text_layout) = positioned_rectangle.resolved_text_layout_options.as_ref()?;
2232
2233 Some(crate::app_resources::get_inline_text(
2234 &words,
2235 &shaped_words,
2236 &word_positions.0,
2237 &inline_text_layout,
2238 ))
2239 }
2240
2241 pub fn get_parent(&self, node_id: DomNodeId) -> Option<DomNodeId> {
2242 if node_id.dom != self.get_callback_node_id().dom {
2243 None
2244 } else {
2245 self.internal_get_node_hierarchy()
2246 .as_container()
2247 .get(node_id.node.into_crate_internal()?)?
2248 .parent_id()
2249 .map(|nid| DomNodeId {
2250 dom: node_id.dom,
2251 node: NodeHierarchyItemId::from_crate_internal(Some(nid)),
2252 })
2253 }
2254 }
2255
2256 pub fn get_previous_sibling(&self, node_id: DomNodeId) -> Option<DomNodeId> {
2257 if node_id.dom != self.get_callback_node_id().dom {
2258 None
2259 } else {
2260 self.internal_get_node_hierarchy()
2261 .as_container()
2262 .get(node_id.node.into_crate_internal()?)?
2263 .previous_sibling_id()
2264 .map(|nid| DomNodeId {
2265 dom: node_id.dom,
2266 node: NodeHierarchyItemId::from_crate_internal(Some(nid)),
2267 })
2268 }
2269 }
2270
2271 pub fn get_next_sibling(&self, node_id: DomNodeId) -> Option<DomNodeId> {
2272 if node_id.dom != self.get_callback_node_id().dom {
2273 None
2274 } else {
2275 self.internal_get_node_hierarchy()
2276 .as_container()
2277 .get(node_id.node.into_crate_internal()?)?
2278 .next_sibling_id()
2279 .map(|nid| DomNodeId {
2280 dom: node_id.dom,
2281 node: NodeHierarchyItemId::from_crate_internal(Some(nid)),
2282 })
2283 }
2284 }
2285
2286 pub fn get_first_child(&self, node_id: DomNodeId) -> Option<DomNodeId> {
2287 if node_id.dom != self.get_callback_node_id().dom {
2288 None
2289 } else {
2290 let nid = node_id.node.into_crate_internal()?;
2291 self.internal_get_node_hierarchy()
2292 .as_container()
2293 .get(nid)?
2294 .first_child_id(nid)
2295 .map(|nid| DomNodeId {
2296 dom: node_id.dom,
2297 node: NodeHierarchyItemId::from_crate_internal(Some(nid)),
2298 })
2299 }
2300 }
2301
2302 pub fn get_last_child(&self, node_id: DomNodeId) -> Option<DomNodeId> {
2303 if node_id.dom != self.get_callback_node_id().dom {
2304 None
2305 } else {
2306 self.internal_get_node_hierarchy()
2307 .as_container()
2308 .get(node_id.node.into_crate_internal()?)?
2309 .last_child_id()
2310 .map(|nid| DomNodeId {
2311 dom: node_id.dom,
2312 node: NodeHierarchyItemId::from_crate_internal(Some(nid)),
2313 })
2314 }
2315 }
2316}
2317
2318pub type RenderImageCallbackType =
2320 extern "C" fn(&mut RefAny, &mut RenderImageCallbackInfo) -> ImageRef;
2321
2322pub type IFrameCallbackType =
2325 extern "C" fn(&mut RefAny, &mut IFrameCallbackInfo) -> IFrameCallbackReturn;
2326
2327#[repr(C)]
2330pub struct IFrameCallback {
2331 pub cb: IFrameCallbackType,
2332}
2333impl_callback!(IFrameCallback);
2334
2335#[derive(Debug)]
2336#[repr(C)]
2337pub struct IFrameCallbackInfo {
2338 pub system_fonts: *const FcFontCache,
2339 pub image_cache: *const ImageCache,
2340 pub window_theme: WindowTheme,
2341 pub bounds: HidpiAdjustedBounds,
2342 pub scroll_size: LogicalSize,
2343 pub scroll_offset: LogicalPosition,
2344 pub virtual_scroll_size: LogicalSize,
2345 pub virtual_scroll_offset: LogicalPosition,
2346 _abi_ref: *const c_void,
2348 _abi_mut: *mut c_void,
2350}
2351
2352impl Clone for IFrameCallbackInfo {
2353 fn clone(&self) -> Self {
2354 Self {
2355 system_fonts: self.system_fonts,
2356 image_cache: self.image_cache,
2357 window_theme: self.window_theme,
2358 bounds: self.bounds,
2359 scroll_size: self.scroll_size,
2360 scroll_offset: self.scroll_offset,
2361 virtual_scroll_size: self.virtual_scroll_size,
2362 virtual_scroll_offset: self.virtual_scroll_offset,
2363 _abi_ref: self._abi_ref,
2364 _abi_mut: self._abi_mut,
2365 }
2366 }
2367}
2368
2369impl IFrameCallbackInfo {
2370 pub fn new<'a>(
2371 system_fonts: &'a FcFontCache,
2372 image_cache: &'a ImageCache,
2373 window_theme: WindowTheme,
2374 bounds: HidpiAdjustedBounds,
2375 scroll_size: LogicalSize,
2376 scroll_offset: LogicalPosition,
2377 virtual_scroll_size: LogicalSize,
2378 virtual_scroll_offset: LogicalPosition,
2379 ) -> Self {
2380 Self {
2381 system_fonts: system_fonts as *const FcFontCache,
2382 image_cache: image_cache as *const ImageCache,
2383 window_theme,
2384 bounds,
2385 scroll_size,
2386 scroll_offset,
2387 virtual_scroll_size,
2388 virtual_scroll_offset,
2389 _abi_ref: core::ptr::null(),
2390 _abi_mut: core::ptr::null_mut(),
2391 }
2392 }
2393
2394 pub fn get_bounds(&self) -> HidpiAdjustedBounds {
2395 self.bounds
2396 }
2397
2398 fn internal_get_system_fonts<'a>(&'a self) -> &'a FcFontCache {
2402 unsafe { &*self.system_fonts }
2403 }
2404 fn internal_get_image_cache<'a>(&'a self) -> &'a ImageCache {
2405 unsafe { &*self.image_cache }
2406 }
2407}
2408
2409#[derive(Debug, Clone, PartialEq)]
2410#[repr(C)]
2411pub struct IFrameCallbackReturn {
2412 pub dom: StyledDom,
2413 pub scroll_size: LogicalSize,
2414 pub scroll_offset: LogicalPosition,
2415 pub virtual_scroll_size: LogicalSize,
2416 pub virtual_scroll_offset: LogicalPosition,
2417}
2418
2419impl Default for IFrameCallbackReturn {
2420 fn default() -> IFrameCallbackReturn {
2421 IFrameCallbackReturn {
2422 dom: StyledDom::default(),
2423 scroll_size: LogicalSize::zero(),
2424 scroll_offset: LogicalPosition::zero(),
2425 virtual_scroll_size: LogicalSize::zero(),
2426 virtual_scroll_offset: LogicalPosition::zero(),
2427 }
2428 }
2429}
2430
2431pub type ThreadCallbackType = extern "C" fn(RefAny, ThreadSender, ThreadReceiver);
2433
2434#[repr(C)]
2435pub struct ThreadCallback {
2436 pub cb: ThreadCallbackType,
2437}
2438impl_callback!(ThreadCallback);
2439
2440#[repr(C)]
2444pub struct TimerCallback {
2445 pub cb: TimerCallbackType,
2446}
2447impl_callback!(TimerCallback);
2448
2449#[derive(Debug)]
2450#[repr(C)]
2451pub struct TimerCallbackInfo {
2452 pub callback_info: CallbackInfo,
2454 pub node_id: OptionDomNodeId,
2456 pub frame_start: Instant,
2458 pub call_count: usize,
2460 pub is_about_to_finish: bool,
2463 pub(crate) _abi_ref: *const c_void,
2465 pub(crate) _abi_mut: *mut c_void,
2467}
2468
2469impl Clone for TimerCallbackInfo {
2470 fn clone(&self) -> Self {
2471 Self {
2472 callback_info: self.callback_info.clone(),
2473 node_id: self.node_id,
2474 frame_start: self.frame_start.clone(),
2475 call_count: self.call_count,
2476 is_about_to_finish: self.is_about_to_finish,
2477 _abi_ref: self._abi_ref,
2478 _abi_mut: self._abi_mut,
2479 }
2480 }
2481}
2482
2483pub type WriteBackCallbackType = extern "C" fn(
2484 &mut RefAny,
2485 &mut RefAny,
2486 &mut CallbackInfo,
2487) -> Update;
2488
2489#[repr(C)]
2491pub struct WriteBackCallback {
2492 pub cb: WriteBackCallbackType,
2493}
2494impl_callback!(WriteBackCallback);
2495
2496#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
2497#[repr(C)]
2498pub struct TimerCallbackReturn {
2499 pub should_update: Update,
2500 pub should_terminate: TerminateTimer,
2501}
2502
2503pub type TimerCallbackType = extern "C" fn(
2504 &mut RefAny,
2505 &mut TimerCallbackInfo,
2506) -> TimerCallbackReturn;
2507
2508#[derive(Debug)]
2511#[repr(C)]
2512pub struct LayoutCallbackInfo {
2513 pub window_size: WindowSize,
2517 pub theme: WindowTheme,
2519 image_cache: *const ImageCache,
2521 pub gl_context: *const OptionGlContextPtr,
2523 system_fonts: *const FcFontCache,
2525 _abi_ref: *const c_void,
2527 _abi_mut: *mut c_void,
2529}
2530
2531impl Clone for LayoutCallbackInfo {
2532 fn clone(&self) -> Self {
2533 Self {
2534 window_size: self.window_size,
2535 theme: self.theme,
2536 image_cache: self.image_cache,
2537 gl_context: self.gl_context,
2538 system_fonts: self.system_fonts,
2539 _abi_ref: self._abi_ref,
2540 _abi_mut: self._abi_mut,
2541 }
2542 }
2543}
2544
2545impl LayoutCallbackInfo {
2546 pub fn new<'a>(
2547 window_size: WindowSize,
2548 theme: WindowTheme,
2549 image_cache: &'a ImageCache,
2550 gl_context: &'a OptionGlContextPtr,
2551 fc_cache: &'a FcFontCache,
2552 ) -> Self {
2553 Self {
2554 window_size,
2555 theme,
2556 image_cache: image_cache as *const ImageCache,
2557 gl_context: gl_context as *const OptionGlContextPtr,
2558 system_fonts: fc_cache as *const FcFontCache,
2559 _abi_ref: core::ptr::null(),
2560 _abi_mut: core::ptr::null_mut(),
2561 }
2562 }
2563
2564 fn internal_get_image_cache<'a>(&'a self) -> &'a ImageCache {
2565 unsafe { &*self.image_cache }
2566 }
2567 fn internal_get_system_fonts<'a>(&'a self) -> &'a FcFontCache {
2568 unsafe { &*self.system_fonts }
2569 }
2570 fn internal_get_gl_context<'a>(&'a self) -> &'a OptionGlContextPtr {
2571 unsafe { &*self.gl_context }
2572 }
2573
2574 pub fn get_gl_context(&self) -> OptionGlContextPtr {
2575 self.internal_get_gl_context().clone()
2576 }
2577
2578 pub fn get_system_fonts(&self) -> Vec<AzStringPair> {
2579 let fc_cache = self.internal_get_system_fonts();
2580
2581 fc_cache
2582 .list()
2583 .iter()
2584 .filter_map(|(pattern, font_id)| {
2585 let source = fc_cache.get_font_by_id(font_id)?;
2586 match source {
2587 FontSource::Memory(f) => None,
2588 FontSource::Disk(d) => Some((pattern.name.as_ref()?.clone(), d.path.clone())),
2589 }
2590 })
2591 .map(|(k, v)| AzStringPair {
2592 key: k.into(),
2593 value: v.into(),
2594 })
2595 .collect()
2596 }
2597
2598 pub fn get_image(&self, image_id: &AzString) -> Option<ImageRef> {
2599 self.internal_get_image_cache()
2600 .get_css_image_id(image_id)
2601 .cloned()
2602 }
2603}
2604
2605#[derive(Debug, Copy, Clone)]
2610#[repr(C)]
2611pub struct HidpiAdjustedBounds {
2612 pub logical_size: LogicalSize,
2613 pub hidpi_factor: f32,
2614}
2615
2616impl HidpiAdjustedBounds {
2617 #[inline(always)]
2618 pub fn from_bounds(bounds: LayoutSize, hidpi_factor: f32) -> Self {
2619 let logical_size = LogicalSize::new(bounds.width as f32, bounds.height as f32);
2620 Self {
2621 logical_size,
2622 hidpi_factor,
2623 }
2624 }
2625
2626 pub fn get_physical_size(&self) -> PhysicalSize<u32> {
2627 self.get_logical_size().to_physical(self.hidpi_factor)
2629 }
2630
2631 pub fn get_logical_size(&self) -> LogicalSize {
2632 self.logical_size
2633 }
2634
2635 pub fn get_hidpi_factor(&self) -> f32 {
2636 self.hidpi_factor
2637 }
2638}
2639
2640#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2642#[repr(C, u8)]
2643pub enum FocusTarget {
2644 Id(DomNodeId),
2645 Path(FocusTargetPath),
2646 Previous,
2647 Next,
2648 First,
2649 Last,
2650 NoFocus,
2651}
2652
2653#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2654#[repr(C)]
2655pub struct FocusTargetPath {
2656 pub dom: DomId,
2657 pub css_path: CssPath,
2658}
2659
2660impl FocusTarget {
2661 pub fn resolve(
2662 &self,
2663 layout_results: &[LayoutResult],
2664 current_focus: Option<DomNodeId>,
2665 ) -> Result<Option<DomNodeId>, UpdateFocusWarning> {
2666 use crate::{callbacks::FocusTarget::*, style::matches_html_element};
2667
2668 if layout_results.is_empty() {
2669 return Ok(None);
2670 }
2671
2672 macro_rules! search_for_focusable_node_id {
2673 (
2674 $layout_results:expr,
2675 $start_dom_id:expr,
2676 $start_node_id:expr,
2677 $get_next_node_fn:ident
2678 ) => {{
2679 let mut start_dom_id = $start_dom_id;
2680 let mut start_node_id = $start_node_id;
2681
2682 let min_dom_id = DomId::ROOT_ID;
2683 let max_dom_id = DomId {
2684 inner: layout_results.len() - 1,
2685 };
2686
2687 loop {
2689 let layout_result = $layout_results
2692 .get(start_dom_id.inner)
2693 .ok_or(UpdateFocusWarning::FocusInvalidDomId(start_dom_id.clone()))?;
2694
2695 let node_id_valid = layout_result
2696 .styled_dom
2697 .node_data
2698 .as_container()
2699 .get(start_node_id)
2700 .is_some();
2701
2702 if !node_id_valid {
2703 return Err(UpdateFocusWarning::FocusInvalidNodeId(
2704 NodeHierarchyItemId::from_crate_internal(Some(start_node_id.clone())),
2705 ));
2706 }
2707
2708 if layout_result.styled_dom.node_data.is_empty() {
2709 return Err(UpdateFocusWarning::FocusInvalidDomId(start_dom_id.clone()));
2710 }
2712
2713 let max_node_id = NodeId::new(layout_result.styled_dom.node_data.len() - 1);
2714 let min_node_id = NodeId::ZERO;
2715
2716 loop {
2718 let current_node_id =
2719 NodeId::new(start_node_id.index().$get_next_node_fn(1))
2720 .max(min_node_id)
2721 .min(max_node_id);
2722
2723 if layout_result.styled_dom.node_data.as_container()[current_node_id]
2724 .is_focusable()
2725 {
2726 return Ok(Some(DomNodeId {
2727 dom: start_dom_id,
2728 node: NodeHierarchyItemId::from_crate_internal(Some(
2729 current_node_id,
2730 )),
2731 }));
2732 }
2733
2734 if current_node_id == min_node_id && current_node_id < start_node_id {
2735 if start_dom_id == min_dom_id {
2737 return Ok(None);
2739 } else {
2740 start_dom_id.inner -= 1;
2741 start_node_id = NodeId::new(
2742 $layout_results[start_dom_id.inner]
2743 .styled_dom
2744 .node_data
2745 .len()
2746 - 1,
2747 );
2748 break; }
2750 } else if current_node_id == max_node_id && current_node_id > start_node_id
2751 {
2752 if start_dom_id == max_dom_id {
2754 return Ok(None);
2756 } else {
2757 start_dom_id.inner += 1;
2758 start_node_id = NodeId::ZERO;
2759 break; }
2761 } else {
2762 start_node_id = current_node_id;
2763 }
2764 }
2765 }
2766 }};
2767 }
2768
2769 match self {
2770 Path(FocusTargetPath { dom, css_path }) => {
2771 let layout_result = layout_results
2772 .get(dom.inner)
2773 .ok_or(UpdateFocusWarning::FocusInvalidDomId(dom.clone()))?;
2774 let html_node_tree = &layout_result.styled_dom.cascade_info;
2775 let node_hierarchy = &layout_result.styled_dom.node_hierarchy;
2776 let node_data = &layout_result.styled_dom.node_data;
2777 let resolved_node_id = html_node_tree
2778 .as_container()
2779 .linear_iter()
2780 .find(|node_id| {
2781 matches_html_element(
2782 css_path,
2783 *node_id,
2784 &node_hierarchy.as_container(),
2785 &node_data.as_container(),
2786 &html_node_tree.as_container(),
2787 None,
2788 )
2789 })
2790 .ok_or(UpdateFocusWarning::CouldNotFindFocusNode(css_path.clone()))?;
2791 Ok(Some(DomNodeId {
2792 dom: dom.clone(),
2793 node: NodeHierarchyItemId::from_crate_internal(Some(resolved_node_id)),
2794 }))
2795 }
2796 Id(dom_node_id) => {
2797 let layout_result = layout_results.get(dom_node_id.dom.inner).ok_or(
2798 UpdateFocusWarning::FocusInvalidDomId(dom_node_id.dom.clone()),
2799 )?;
2800 let node_is_valid = dom_node_id
2801 .node
2802 .into_crate_internal()
2803 .map(|o| {
2804 layout_result
2805 .styled_dom
2806 .node_data
2807 .as_container()
2808 .get(o)
2809 .is_some()
2810 })
2811 .unwrap_or(false);
2812
2813 if !node_is_valid {
2814 Err(UpdateFocusWarning::FocusInvalidNodeId(
2815 dom_node_id.node.clone(),
2816 ))
2817 } else {
2818 Ok(Some(dom_node_id.clone()))
2819 }
2820 }
2821 Previous => {
2822 let last_layout_dom_id = DomId {
2823 inner: layout_results.len() - 1,
2824 };
2825
2826 let (current_focus_dom, current_focus_node_id) = match current_focus {
2829 Some(s) => match s.node.into_crate_internal() {
2830 Some(n) => (s.dom, n),
2831 None => {
2832 if let Some(layout_result) = layout_results.get(s.dom.inner) {
2833 (
2834 s.dom,
2835 NodeId::new(layout_result.styled_dom.node_data.len() - 1),
2836 )
2837 } else {
2838 (
2839 last_layout_dom_id,
2840 NodeId::new(
2841 layout_results[last_layout_dom_id.inner]
2842 .styled_dom
2843 .node_data
2844 .len()
2845 - 1,
2846 ),
2847 )
2848 }
2849 }
2850 },
2851 None => (
2852 last_layout_dom_id,
2853 NodeId::new(
2854 layout_results[last_layout_dom_id.inner]
2855 .styled_dom
2856 .node_data
2857 .len()
2858 - 1,
2859 ),
2860 ),
2861 };
2862
2863 search_for_focusable_node_id!(
2864 layout_results,
2865 current_focus_dom,
2866 current_focus_node_id,
2867 saturating_sub
2868 );
2869 }
2870 Next => {
2871 let (current_focus_dom, current_focus_node_id) = match current_focus {
2875 Some(s) => match s.node.into_crate_internal() {
2876 Some(n) => (s.dom, n),
2877 None => {
2878 if layout_results.get(s.dom.inner).is_some() {
2879 (s.dom, NodeId::ZERO)
2880 } else {
2881 (DomId::ROOT_ID, NodeId::ZERO)
2882 }
2883 }
2884 },
2885 None => (DomId::ROOT_ID, NodeId::ZERO),
2886 };
2887
2888 search_for_focusable_node_id!(
2889 layout_results,
2890 current_focus_dom,
2891 current_focus_node_id,
2892 saturating_add
2893 );
2894 }
2895 First => {
2896 let (current_focus_dom, current_focus_node_id) = (DomId::ROOT_ID, NodeId::ZERO);
2897 search_for_focusable_node_id!(
2898 layout_results,
2899 current_focus_dom,
2900 current_focus_node_id,
2901 saturating_add
2902 );
2903 }
2904 Last => {
2905 let last_layout_dom_id = DomId {
2906 inner: layout_results.len() - 1,
2907 };
2908 let (current_focus_dom, current_focus_node_id) = (
2909 last_layout_dom_id,
2910 NodeId::new(
2911 layout_results[last_layout_dom_id.inner]
2912 .styled_dom
2913 .node_data
2914 .len()
2915 - 1,
2916 ),
2917 );
2918 search_for_focusable_node_id!(
2919 layout_results,
2920 current_focus_dom,
2921 current_focus_node_id,
2922 saturating_add
2923 );
2924 }
2925 NoFocus => Ok(None),
2926 }
2927 }
2928}