1#[cfg(not(feature = "std"))]
2use alloc::string::ToString;
3use alloc::{boxed::Box, collections::btree_map::BTreeMap, string::String, vec::Vec};
4use core::{
5 fmt,
6 hash::{Hash, Hasher},
7 sync::atomic::{AtomicU32, AtomicUsize, Ordering as AtomicOrdering},
8};
9
10use azul_css::{
11 format_rust_code::GetHash,
12 props::basic::{
13 pixel::DEFAULT_FONT_SIZE, ColorU, FloatValue, FontRef, LayoutRect, LayoutSize,
14 StyleFontFamily, StyleFontFamilyVec, StyleFontSize,
15 },
16 system::SystemStyle,
17 AzString, F32Vec, LayoutDebugMessage, OptionI32, StringVec, U16Vec, U32Vec, U8Vec,
18};
19use rust_fontconfig::FcFontCache;
20
21pub use crate::callbacks::{
23 CoreImageCallback, CoreRenderImageCallback, CoreRenderImageCallbackType,
24};
25use crate::{
26 callbacks::IFrameCallback,
27 dom::{DomId, NodeData, NodeType},
28 geom::{LogicalPosition, LogicalRect, LogicalSize},
29 gl::{OptionGlContextPtr, Texture},
30 hit_test::DocumentId,
31 id::NodeId,
32 prop_cache::CssPropertyCache,
33 refany::RefAny,
34 styled_dom::{
35 NodeHierarchyItemId, StyleFontFamiliesHash, StyleFontFamilyHash, StyledDom, StyledNodeState,
36 },
37 ui_solver::GlyphInstance,
38 window::OptionChar,
39 FastBTreeSet, FastHashMap,
40};
41
42#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
43#[repr(C)]
44pub struct DpiScaleFactor {
45 pub inner: FloatValue,
46}
47
48impl DpiScaleFactor {
49 pub fn new(f: f32) -> Self {
50 Self {
51 inner: FloatValue::new(f),
52 }
53 }
54}
55
56#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
58#[repr(C)]
59pub enum AppTerminationBehavior {
60 ReturnToMain,
64 RunForever,
67 EndProcess,
70}
71
72impl Default for AppTerminationBehavior {
73 fn default() -> Self {
74 AppTerminationBehavior::EndProcess
76 }
77}
78
79#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
82#[repr(C)]
83pub struct NamedFont {
84 pub name: AzString,
86 pub bytes: U8Vec,
88}
89
90impl_option!(
91 NamedFont,
92 OptionNamedFont,
93 copy = false,
94 [Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
95);
96
97impl NamedFont {
98 pub fn new(name: AzString, bytes: U8Vec) -> Self {
99 Self { name, bytes }
100 }
101}
102
103impl_vec!(NamedFont, NamedFontVec, NamedFontVecDestructor, NamedFontVecDestructorType, NamedFontVecSlice, OptionNamedFont);
104impl_vec_mut!(NamedFont, NamedFontVec);
105impl_vec_debug!(NamedFont, NamedFontVec);
106impl_vec_partialeq!(NamedFont, NamedFontVec);
107impl_vec_eq!(NamedFont, NamedFontVec);
108impl_vec_partialord!(NamedFont, NamedFontVec);
109impl_vec_ord!(NamedFont, NamedFontVec);
110impl_vec_hash!(NamedFont, NamedFontVec);
111impl_vec_clone!(NamedFont, NamedFontVec, NamedFontVecDestructor);
112
113#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
115#[repr(C, u8)]
116pub enum FontLoadingConfig {
117 LoadAllSystemFonts,
119 LoadOnlyFamilies(StringVec),
122 BundledFontsOnly,
124}
125
126impl Default for FontLoadingConfig {
127 fn default() -> Self {
128 FontLoadingConfig::LoadAllSystemFonts
129 }
130}
131
132#[derive(Debug, Clone, Default)]
157#[repr(C)]
158pub struct CssMockEnvironment {
159 pub os: azul_css::dynamic_selector::OptionOsCondition,
161 pub os_version: azul_css::dynamic_selector::OptionOsVersion,
163 pub desktop_env: azul_css::dynamic_selector::OptionLinuxDesktopEnv,
165 pub theme: azul_css::dynamic_selector::OptionThemeCondition,
167 pub language: azul_css::OptionString,
169 pub prefers_reduced_motion: azul_css::OptionBool,
171 pub prefers_high_contrast: azul_css::OptionBool,
173 pub viewport_width: azul_css::OptionF32,
176 pub viewport_height: azul_css::OptionF32,
177}
178
179impl CssMockEnvironment {
180 pub fn linux() -> Self {
182 Self {
183 os: azul_css::dynamic_selector::OptionOsCondition::Some(azul_css::dynamic_selector::OsCondition::Linux),
184 ..Default::default()
185 }
186 }
187
188 pub fn windows() -> Self {
190 Self {
191 os: azul_css::dynamic_selector::OptionOsCondition::Some(azul_css::dynamic_selector::OsCondition::Windows),
192 ..Default::default()
193 }
194 }
195
196 pub fn macos() -> Self {
198 Self {
199 os: azul_css::dynamic_selector::OptionOsCondition::Some(azul_css::dynamic_selector::OsCondition::MacOS),
200 ..Default::default()
201 }
202 }
203
204 pub fn dark_theme() -> Self {
206 Self {
207 theme: azul_css::dynamic_selector::OptionThemeCondition::Some(azul_css::dynamic_selector::ThemeCondition::Dark),
208 ..Default::default()
209 }
210 }
211
212 pub fn light_theme() -> Self {
214 Self {
215 theme: azul_css::dynamic_selector::OptionThemeCondition::Some(azul_css::dynamic_selector::ThemeCondition::Light),
216 ..Default::default()
217 }
218 }
219
220 pub fn apply_to(&self, ctx: &mut azul_css::dynamic_selector::DynamicSelectorContext) {
222 if let azul_css::dynamic_selector::OptionOsCondition::Some(os) = self.os {
223 ctx.os = os;
224 }
225 if let azul_css::dynamic_selector::OptionOsVersion::Some(os_version) = self.os_version {
226 ctx.os_version = os_version;
227 }
228 if let azul_css::dynamic_selector::OptionLinuxDesktopEnv::Some(de) = self.desktop_env {
229 ctx.desktop_env = azul_css::dynamic_selector::OptionLinuxDesktopEnv::Some(de);
230 }
231 if let azul_css::dynamic_selector::OptionThemeCondition::Some(ref theme) = self.theme {
232 ctx.theme = theme.clone();
233 }
234 if let azul_css::OptionString::Some(ref lang) = self.language {
235 ctx.language = lang.clone();
236 }
237 if let azul_css::OptionBool::Some(reduced) = self.prefers_reduced_motion {
238 ctx.prefers_reduced_motion = if reduced {
239 azul_css::dynamic_selector::BoolCondition::True
240 } else {
241 azul_css::dynamic_selector::BoolCondition::False
242 };
243 }
244 if let azul_css::OptionBool::Some(high_contrast) = self.prefers_high_contrast {
245 ctx.prefers_high_contrast = if high_contrast {
246 azul_css::dynamic_selector::BoolCondition::True
247 } else {
248 azul_css::dynamic_selector::BoolCondition::False
249 };
250 }
251 if let azul_css::OptionF32::Some(w) = self.viewport_width {
252 ctx.viewport_width = w;
253 }
254 if let azul_css::OptionF32::Some(h) = self.viewport_height {
255 ctx.viewport_height = h;
256 }
257 }
258}
259
260impl_option!(
261 CssMockEnvironment,
262 OptionCssMockEnvironment,
263 copy = false,
264 [Debug, Clone]
265);
266
267#[derive(Debug, Clone)]
269#[repr(C)]
270pub struct AppConfig {
271 pub log_level: AppLogLevel,
275 pub enable_visual_panic_hook: bool,
278 pub enable_logging_on_panic: bool,
281 pub enable_tab_navigation: bool,
284 pub termination_behavior: AppTerminationBehavior,
287 pub icon_provider: crate::icon::IconProviderHandle,
291 pub bundled_fonts: NamedFontVec,
294 pub font_loading: FontLoadingConfig,
297 pub mock_css_environment: OptionCssMockEnvironment,
307 pub system_style: SystemStyle,
313}
314
315impl AppConfig {
316 pub fn create() -> Self {
317 let log_level = AppLogLevel::Error;
318 let icon_provider = crate::icon::IconProviderHandle::new();
319 let bundled_fonts = NamedFontVec::from_const_slice(&[]);
320 let font_loading = FontLoadingConfig::default();
321 let system_style = SystemStyle::detect();
322 Self {
323 log_level,
324 enable_visual_panic_hook: false,
325 enable_logging_on_panic: true,
326 enable_tab_navigation: true,
327 termination_behavior: AppTerminationBehavior::default(),
328 icon_provider,
329 bundled_fonts,
330 font_loading,
331 mock_css_environment: OptionCssMockEnvironment::None,
332 system_style,
333 }
334 }
335
336 pub fn with_mock_environment(mut self, env: CssMockEnvironment) -> Self {
351 self.mock_css_environment = OptionCssMockEnvironment::Some(env);
352 self
353 }
354}
355
356impl Default for AppConfig {
357 fn default() -> Self {
358 Self::create()
359 }
360}
361
362#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
363#[repr(C)]
364pub enum AppLogLevel {
365 Off,
366 Error,
367 Warn,
368 Info,
369 Debug,
370 Trace,
371}
372
373#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
374pub struct PrimitiveFlags {
375 pub is_backface_visible: bool,
377 pub is_scrollbar_container: bool,
379 pub is_scrollbar_thumb: bool,
381 pub prefer_compositor_surface: bool,
385 pub supports_external_compositor_surface: bool,
389}
390
391#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
393#[repr(C)]
394pub struct ImageDescriptor {
395 pub format: RawImageFormat,
397 pub width: usize,
399 pub height: usize,
400 pub stride: OptionI32,
405 pub offset: i32,
411 pub flags: ImageDescriptorFlags,
413}
414
415#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
417#[repr(C)]
418pub struct ImageDescriptorFlags {
419 pub is_opaque: bool,
422 pub allow_mipmaps: bool,
428}
429
430#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
431pub struct IdNamespace(pub u32);
432
433impl ::core::fmt::Display for IdNamespace {
434 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
435 write!(f, "IdNamespace({})", self.0)
436 }
437}
438
439impl ::core::fmt::Debug for IdNamespace {
440 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
441 write!(f, "{}", self)
442 }
443}
444
445#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
446#[repr(C)]
447pub enum RawImageFormat {
448 R8,
449 RG8,
450 RGB8,
451 RGBA8,
452 R16,
453 RG16,
454 RGB16,
455 RGBA16,
456 BGR8,
457 BGRA8,
458 RGBF32,
459 RGBAF32,
460}
461
462static IMAGE_KEY: AtomicU32 = AtomicU32::new(1);
464static FONT_KEY: AtomicU32 = AtomicU32::new(0);
465static FONT_INSTANCE_KEY: AtomicU32 = AtomicU32::new(0);
466
467#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
468pub struct ImageKey {
469 pub namespace: IdNamespace,
470 pub key: u32,
471}
472
473impl ImageKey {
474 pub const DUMMY: Self = Self {
475 namespace: IdNamespace(0),
476 key: 0,
477 };
478
479 pub fn unique(render_api_namespace: IdNamespace) -> Self {
480 Self {
481 namespace: render_api_namespace,
482 key: IMAGE_KEY.fetch_add(1, AtomicOrdering::SeqCst),
483 }
484 }
485}
486
487#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
488pub struct FontKey {
489 pub namespace: IdNamespace,
490 pub key: u32,
491}
492
493impl FontKey {
494 pub fn unique(render_api_namespace: IdNamespace) -> Self {
495 Self {
496 namespace: render_api_namespace,
497 key: FONT_KEY.fetch_add(1, AtomicOrdering::SeqCst),
498 }
499 }
500}
501
502#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
503pub struct FontInstanceKey {
504 pub namespace: IdNamespace,
505 pub key: u32,
506}
507
508impl FontInstanceKey {
509 pub fn unique(render_api_namespace: IdNamespace) -> Self {
510 Self {
511 namespace: render_api_namespace,
512 key: FONT_INSTANCE_KEY.fetch_add(1, AtomicOrdering::SeqCst),
513 }
514 }
515}
516
517#[derive(Debug)]
520pub enum DecodedImage {
521 NullImage {
524 width: usize,
525 height: usize,
526 format: RawImageFormat,
527 tag: Vec<u8>,
529 },
530 Gl(Texture),
532 Raw((ImageDescriptor, ImageData)),
534 Callback(CoreImageCallback),
536 }
541
542#[derive(Debug)]
543#[repr(C)]
544pub struct ImageRef {
545 pub data: *const DecodedImage,
547 pub copies: *const AtomicUsize,
549 pub run_destructor: bool,
550}
551
552impl ImageRef {
553 pub fn get_hash(&self) -> ImageRefHash {
554 image_ref_get_hash(self)
555 }
556}
557
558#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Hash, Ord, Eq)]
559#[repr(C)]
560pub struct ImageRefHash {
561 pub inner: usize,
562}
563
564impl_option!(
565 ImageRef,
566 OptionImageRef,
567 copy = false,
568 [Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
569);
570
571impl ImageRef {
572 pub fn into_inner(self) -> Option<DecodedImage> {
574 unsafe {
575 if self.copies.as_ref().map(|m| m.load(AtomicOrdering::SeqCst)) == Some(1) {
576 let data = Box::from_raw(self.data as *mut DecodedImage);
577 let _ = Box::from_raw(self.copies as *mut AtomicUsize);
578 core::mem::forget(self); Some(*data)
580 } else {
581 None
582 }
583 }
584 }
585
586 pub fn get_data<'a>(&'a self) -> &'a DecodedImage {
587 unsafe { &*self.data }
588 }
589
590 pub fn get_image_callback<'a>(&'a self) -> Option<&'a CoreImageCallback> {
591 if unsafe { self.copies.as_ref().map(|m| m.load(AtomicOrdering::SeqCst)) != Some(1) } {
592 return None; }
594
595 match unsafe { &*self.data } {
596 DecodedImage::Callback(gl_texture_callback) => Some(gl_texture_callback),
597 _ => None,
598 }
599 }
600
601 pub fn get_image_callback_mut<'a>(&'a mut self) -> Option<&'a mut CoreImageCallback> {
602 if unsafe { self.copies.as_ref().map(|m| m.load(AtomicOrdering::SeqCst)) != Some(1) } {
603 return None; }
605
606 match unsafe { &mut *(self.data as *mut DecodedImage) } {
607 DecodedImage::Callback(gl_texture_callback) => Some(gl_texture_callback),
608 _ => None,
609 }
610 }
611
612 pub fn deep_copy(&self) -> Self {
614 let new_data = match self.get_data() {
615 DecodedImage::NullImage {
616 width,
617 height,
618 format,
619 tag,
620 } => DecodedImage::NullImage {
621 width: *width,
622 height: *height,
623 format: *format,
624 tag: tag.clone(),
625 },
626 DecodedImage::Gl(tex) => DecodedImage::NullImage {
630 width: tex.size.width as usize,
631 height: tex.size.height as usize,
632 format: tex.format,
633 tag: Vec::new(),
634 },
635 DecodedImage::Raw((descriptor, data)) => {
638 DecodedImage::Raw((descriptor.clone(), data.clone()))
639 }
640 DecodedImage::Callback(cb) => DecodedImage::Callback(cb.clone()),
641 };
642
643 Self::new(new_data)
644 }
645
646 pub fn is_null_image(&self) -> bool {
647 match self.get_data() {
648 DecodedImage::NullImage { .. } => true,
649 _ => false,
650 }
651 }
652
653 pub fn is_gl_texture(&self) -> bool {
654 match self.get_data() {
655 DecodedImage::Gl(_) => true,
656 _ => false,
657 }
658 }
659
660 pub fn is_raw_image(&self) -> bool {
661 match self.get_data() {
662 DecodedImage::Raw((_, _)) => true,
663 _ => false,
664 }
665 }
666
667 pub fn is_callback(&self) -> bool {
668 match self.get_data() {
669 DecodedImage::Callback(_) => true,
670 _ => false,
671 }
672 }
673
674 pub fn get_rawimage(&self) -> Option<RawImage> {
676 match self.get_data() {
677 DecodedImage::Raw((image_descriptor, image_data)) => Some(RawImage {
678 pixels: match image_data {
679 ImageData::Raw(shared_data) => {
680 let data_clone = shared_data.clone();
683 if let Some(u8vec) = data_clone.into_inner() {
684 RawImageData::U8(u8vec)
685 } else {
686 RawImageData::U8(shared_data.as_ref().to_vec().into())
688 }
689 }
690 ImageData::External(_) => return None,
691 },
692 width: image_descriptor.width,
693 height: image_descriptor.height,
694 premultiplied_alpha: true,
695 data_format: image_descriptor.format,
696 tag: Vec::new().into(),
697 }),
698 _ => None,
699 }
700 }
701
702 pub fn get_bytes(&self) -> Option<&[u8]> {
705 match self.get_data() {
706 DecodedImage::Raw((_, image_data)) => match image_data {
707 ImageData::Raw(shared_data) => Some(shared_data.as_ref()),
708 ImageData::External(_) => None,
709 },
710 _ => None,
711 }
712 }
713
714 pub fn get_bytes_ptr(&self) -> *const u8 {
717 match self.get_data() {
718 DecodedImage::Raw((_, image_data)) => match image_data {
719 ImageData::Raw(shared_data) => shared_data.as_ptr(),
720 ImageData::External(_) => core::ptr::null(),
721 },
722 _ => core::ptr::null(),
723 }
724 }
725
726 pub fn get_size(&self) -> LogicalSize {
728 match self.get_data() {
729 DecodedImage::NullImage { width, height, .. } => {
730 LogicalSize::new(*width as f32, *height as f32)
731 }
732 DecodedImage::Gl(tex) => {
733 LogicalSize::new(tex.size.width as f32, tex.size.height as f32)
734 }
735 DecodedImage::Raw((image_descriptor, _)) => LogicalSize::new(
736 image_descriptor.width as f32,
737 image_descriptor.height as f32,
738 ),
739 DecodedImage::Callback(_) => LogicalSize::new(0.0, 0.0),
740 }
741 }
742
743 pub fn null_image(width: usize, height: usize, format: RawImageFormat, tag: Vec<u8>) -> Self {
744 Self::new(DecodedImage::NullImage {
745 width,
746 height,
747 format,
748 tag,
749 })
750 }
751
752 pub fn callback<C: Into<CoreRenderImageCallback>>(callback: C, data: RefAny) -> Self {
753 Self::new(DecodedImage::Callback(CoreImageCallback {
754 callback: callback.into(),
755 refany: data,
756 }))
757 }
758
759 pub fn new_rawimage(image_data: RawImage) -> Option<Self> {
760 let (image_data, image_descriptor) = image_data.into_loaded_image_source()?;
761 Some(Self::new(DecodedImage::Raw((image_descriptor, image_data))))
762 }
763
764 pub fn new_gltexture(texture: Texture) -> Self {
765 Self::new(DecodedImage::Gl(texture))
766 }
767
768 fn new(data: DecodedImage) -> Self {
769 Self {
770 data: Box::into_raw(Box::new(data)),
771 copies: Box::into_raw(Box::new(AtomicUsize::new(1))),
772 run_destructor: true,
773 }
774 }
775
776 }
778
779unsafe impl Send for ImageRef {}
780unsafe impl Sync for ImageRef {}
781
782impl PartialEq for ImageRef {
783 fn eq(&self, rhs: &Self) -> bool {
784 self.data as usize == rhs.data as usize
785 }
786}
787
788impl PartialOrd for ImageRef {
789 fn partial_cmp(&self, other: &Self) -> Option<::core::cmp::Ordering> {
790 Some((self.data as usize).cmp(&(other.data as usize)))
791 }
792}
793
794impl Ord for ImageRef {
795 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
796 let self_data = self.data as usize;
797 let other_data = other.data as usize;
798 self_data.cmp(&other_data)
799 }
800}
801
802impl Eq for ImageRef {}
803
804impl Hash for ImageRef {
805 fn hash<H>(&self, state: &mut H)
806 where
807 H: Hasher,
808 {
809 let self_data = self.data as usize;
810 self_data.hash(state)
811 }
812}
813
814impl Clone for ImageRef {
815 fn clone(&self) -> Self {
816 unsafe {
817 self.copies
818 .as_ref()
819 .map(|m| m.fetch_add(1, AtomicOrdering::SeqCst));
820 }
821 Self {
822 data: self.data, copies: self.copies, run_destructor: true,
825 }
826 }
827}
828
829impl Drop for ImageRef {
830 fn drop(&mut self) {
831 self.run_destructor = false;
832 unsafe {
833 let copies = unsafe { (*self.copies).fetch_sub(1, AtomicOrdering::SeqCst) };
834 if copies == 1 {
835 let _ = Box::from_raw(self.data as *mut DecodedImage);
836 let _ = Box::from_raw(self.copies as *mut AtomicUsize);
837 }
838 }
839 }
840}
841
842pub fn image_ref_get_hash(ir: &ImageRef) -> ImageRefHash {
843 ImageRefHash {
844 inner: ir.data as usize,
845 }
846}
847
848pub fn image_ref_hash_to_image_key(hash: ImageRefHash, namespace: IdNamespace) -> ImageKey {
852 ImageKey {
853 namespace,
854 key: hash.inner as u32,
855 }
856}
857
858pub fn font_ref_get_hash(fr: &FontRef) -> u64 {
859 fr.get_hash()
860}
861
862#[derive(Debug)]
868pub struct ImageCache {
869 pub image_id_map: FastHashMap<AzString, ImageRef>,
875}
876
877impl Default for ImageCache {
878 fn default() -> Self {
879 Self {
880 image_id_map: FastHashMap::default(),
881 }
882 }
883}
884
885impl ImageCache {
886 pub fn new() -> Self {
887 Self::default()
888 }
889
890 pub fn add_css_image_id(&mut self, css_id: AzString, image: ImageRef) {
893 self.image_id_map.insert(css_id, image);
894 }
895
896 pub fn get_css_image_id(&self, css_id: &AzString) -> Option<&ImageRef> {
897 self.image_id_map.get(css_id)
898 }
899
900 pub fn delete_css_image_id(&mut self, css_id: &AzString) {
901 self.image_id_map.remove(css_id);
902 }
903}
904
905#[derive(Debug, Copy, Clone, PartialEq)]
907pub enum ImageType {
908 Background,
910 Content,
912 ClipMask,
914}
915
916#[derive(Debug, Copy, Clone, PartialEq)]
917pub struct ResolvedImage {
918 pub key: ImageKey,
919 pub descriptor: ImageDescriptor,
920}
921
922#[derive(Debug, Clone, PartialEq, PartialOrd)]
924pub struct TextExclusionArea {
925 pub rect: LogicalRect,
926 pub side: ExclusionSide,
927}
928
929#[derive(Debug, Clone, PartialEq, PartialOrd)]
931pub enum ExclusionSide {
932 Left,
933 Right,
934 Both,
935 None,
936}
937
938pub trait RendererResourcesTrait: core::fmt::Debug {
940 fn get_font_family(
942 &self,
943 style_font_families_hash: &StyleFontFamiliesHash,
944 ) -> Option<&StyleFontFamilyHash>;
945
946 fn get_font_key(&self, style_font_family_hash: &StyleFontFamilyHash) -> Option<&FontKey>;
948
949 fn get_registered_font(
951 &self,
952 font_key: &FontKey,
953 ) -> Option<&(FontRef, FastHashMap<(Au, DpiScaleFactor), FontInstanceKey>)>;
954
955 fn get_image(&self, hash: &ImageRefHash) -> Option<&ResolvedImage>;
957
958 fn update_image(
960 &mut self,
961 image_ref_hash: &ImageRefHash,
962 descriptor: crate::resources::ImageDescriptor,
963 );
964}
965
966impl RendererResourcesTrait for RendererResources {
968 fn get_font_family(
969 &self,
970 style_font_families_hash: &StyleFontFamiliesHash,
971 ) -> Option<&StyleFontFamilyHash> {
972 self.font_families_map.get(style_font_families_hash)
973 }
974
975 fn get_font_key(&self, style_font_family_hash: &StyleFontFamilyHash) -> Option<&FontKey> {
976 self.font_id_map.get(style_font_family_hash)
977 }
978
979 fn get_registered_font(
980 &self,
981 font_key: &FontKey,
982 ) -> Option<&(FontRef, FastHashMap<(Au, DpiScaleFactor), FontInstanceKey>)> {
983 self.currently_registered_fonts.get(font_key)
984 }
985
986 fn get_image(&self, hash: &ImageRefHash) -> Option<&ResolvedImage> {
987 self.currently_registered_images.get(hash)
988 }
989
990 fn update_image(
991 &mut self,
992 image_ref_hash: &ImageRefHash,
993 descriptor: crate::resources::ImageDescriptor,
994 ) {
995 if let Some(s) = self.currently_registered_images.get_mut(image_ref_hash) {
996 s.descriptor = descriptor;
997 }
998 }
999}
1000
1001pub struct RendererResources {
1008 pub currently_registered_images: FastHashMap<ImageRefHash, ResolvedImage>,
1010 pub image_key_map: FastHashMap<ImageKey, ImageRefHash>,
1012 pub currently_registered_fonts:
1014 FastHashMap<FontKey, (FontRef, FastHashMap<(Au, DpiScaleFactor), FontInstanceKey>)>,
1015 pub last_frame_registered_fonts:
1022 FastHashMap<FontKey, FastHashMap<(Au, DpiScaleFactor), FontInstanceKey>>,
1023 pub font_families_map: FastHashMap<StyleFontFamiliesHash, StyleFontFamilyHash>,
1028 pub font_id_map: FastHashMap<StyleFontFamilyHash, FontKey>,
1030 pub font_hash_map: FastHashMap<u64, FontKey>,
1033}
1034
1035impl fmt::Debug for RendererResources {
1036 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1037 write!(
1038 f,
1039 "RendererResources {{
1040 currently_registered_images: {:#?},
1041 currently_registered_fonts: {:#?},
1042 font_families_map: {:#?},
1043 font_id_map: {:#?},
1044 }}",
1045 self.currently_registered_images.keys().collect::<Vec<_>>(),
1046 self.currently_registered_fonts.keys().collect::<Vec<_>>(),
1047 self.font_families_map.keys().collect::<Vec<_>>(),
1048 self.font_id_map.keys().collect::<Vec<_>>(),
1049 )
1050 }
1051}
1052
1053impl Default for RendererResources {
1054 fn default() -> Self {
1055 Self {
1056 currently_registered_images: FastHashMap::default(),
1057 image_key_map: FastHashMap::default(),
1058 currently_registered_fonts: FastHashMap::default(),
1059 last_frame_registered_fonts: FastHashMap::default(),
1060 font_families_map: FastHashMap::default(),
1061 font_id_map: FastHashMap::default(),
1062 font_hash_map: FastHashMap::default(),
1063 }
1064 }
1065}
1066
1067impl RendererResources {
1068 pub fn get_renderable_font_data(
1069 &self,
1070 font_instance_key: &FontInstanceKey,
1071 ) -> Option<(&FontRef, Au, DpiScaleFactor)> {
1072 self.currently_registered_fonts
1073 .iter()
1074 .find_map(|(font_key, (font_ref, instances))| {
1075 instances.iter().find_map(|((au, dpi), instance_key)| {
1076 if *instance_key == *font_instance_key {
1077 Some((font_ref, *au, *dpi))
1078 } else {
1079 None
1080 }
1081 })
1082 })
1083 }
1084
1085 pub fn get_image(&self, hash: &ImageRefHash) -> Option<&ResolvedImage> {
1086 self.currently_registered_images.get(hash)
1087 }
1088
1089 pub fn get_font_family(
1090 &self,
1091 style_font_families_hash: &StyleFontFamiliesHash,
1092 ) -> Option<&StyleFontFamilyHash> {
1093 self.font_families_map.get(style_font_families_hash)
1094 }
1095
1096 pub fn get_font_key(&self, style_font_family_hash: &StyleFontFamilyHash) -> Option<&FontKey> {
1097 self.font_id_map.get(style_font_family_hash)
1098 }
1099
1100 pub fn get_registered_font(
1101 &self,
1102 font_key: &FontKey,
1103 ) -> Option<&(FontRef, FastHashMap<(Au, DpiScaleFactor), FontInstanceKey>)> {
1104 self.currently_registered_fonts.get(font_key)
1105 }
1106
1107 pub fn update_image(&mut self, image_ref_hash: &ImageRefHash, descriptor: ImageDescriptor) {
1108 if let Some(s) = self.currently_registered_images.get_mut(image_ref_hash) {
1109 s.descriptor = descriptor; }
1111 }
1112
1113 pub fn get_font_instance_key_for_text(
1114 &self,
1115 font_size_px: f32,
1116 css_property_cache: &CssPropertyCache,
1117 node_data: &NodeData,
1118 node_id: &NodeId,
1119 styled_node_state: &StyledNodeState,
1120 dpi_scale: f32,
1121 ) -> Option<FontInstanceKey> {
1122 let font_size = StyleFontSize {
1124 inner: azul_css::props::basic::PixelValue::const_px(font_size_px as isize),
1125 };
1126
1127 let font_size_au = font_size_to_au(font_size);
1129
1130 let dpi_scale_factor = DpiScaleFactor {
1132 inner: FloatValue::new(dpi_scale),
1133 };
1134
1135 let font_family =
1137 css_property_cache.get_font_id_or_default(node_data, node_id, styled_node_state);
1138
1139 let font_families_hash = StyleFontFamiliesHash::new(font_family.as_ref());
1141
1142 self.get_font_instance_key(&font_families_hash, font_size_au, dpi_scale_factor)
1143 }
1144
1145 pub fn get_font_instance_key(
1146 &self,
1147 font_families_hash: &StyleFontFamiliesHash,
1148 font_size_au: Au,
1149 dpi_scale: DpiScaleFactor,
1150 ) -> Option<FontInstanceKey> {
1151 let font_family_hash = self.get_font_family(font_families_hash)?;
1152 let font_key = self.get_font_key(font_family_hash)?;
1153 let (_, instances) = self.get_registered_font(font_key)?;
1154 instances.get(&(font_size_au, dpi_scale)).copied()
1155 }
1156
1157 fn remove_font_families_with_zero_references(&mut self) {
1159 let font_family_to_delete = self
1160 .font_id_map
1161 .iter()
1162 .filter_map(|(font_family, font_key)| {
1163 if !self.currently_registered_fonts.contains_key(font_key) {
1164 Some(font_family.clone())
1165 } else {
1166 None
1167 }
1168 })
1169 .collect::<Vec<_>>();
1170
1171 for f in font_family_to_delete {
1172 self.font_id_map.remove(&f); }
1174
1175 let font_families_to_delete = self
1176 .font_families_map
1177 .iter()
1178 .filter_map(|(font_families, font_family)| {
1179 if !self.font_id_map.contains_key(font_family) {
1180 Some(font_families.clone())
1181 } else {
1182 None
1183 }
1184 })
1185 .collect::<Vec<_>>();
1186
1187 for f in font_families_to_delete {
1188 self.font_families_map.remove(&f); }
1190 }
1191}
1192
1193#[derive(Debug, Clone)]
1204pub struct UpdateImageResult {
1205 pub key_to_update: ImageKey,
1206 pub new_descriptor: ImageDescriptor,
1207 pub new_image_data: ImageData,
1208}
1209
1210#[derive(Debug, Default)]
1211pub struct GlTextureCache {
1212 pub solved_textures:
1213 BTreeMap<DomId, BTreeMap<NodeId, (ImageKey, ImageDescriptor, ExternalImageId)>>,
1214 pub hashes: BTreeMap<(DomId, NodeId, ImageRefHash), ImageRefHash>,
1215}
1216
1217unsafe impl Send for GlTextureCache {}
1219
1220impl GlTextureCache {
1221 pub fn empty() -> Self {
1223 Self {
1224 solved_textures: BTreeMap::new(),
1225 hashes: BTreeMap::new(),
1226 }
1227 }
1228
1229 pub fn update_texture(
1248 &mut self,
1249 dom_id: DomId,
1250 node_id: NodeId,
1251 document_id: DocumentId,
1252 epoch: Epoch,
1253 new_texture: Texture,
1254 insert_into_active_gl_textures_fn: &GlStoreImageFn,
1255 ) -> Option<ExternalImageId> {
1256 let new_descriptor = new_texture.get_descriptor();
1257 let di_map = self.solved_textures.get_mut(&dom_id)?;
1258 let entry = di_map.get_mut(&node_id)?;
1259
1260 entry.1 = new_descriptor;
1262
1263 let external_image_id =
1265 (insert_into_active_gl_textures_fn)(document_id, epoch, new_texture);
1266
1267 entry.2 = external_image_id;
1269
1270 Some(external_image_id)
1271 }
1272}
1273
1274macro_rules! unique_id {
1275 ($struct_name:ident, $counter_name:ident) => {
1276 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)]
1277 #[repr(C)]
1278 pub struct $struct_name {
1279 pub id: usize,
1280 }
1281
1282 impl $struct_name {
1283 pub fn unique() -> Self {
1284 Self {
1285 id: $counter_name.fetch_add(1, AtomicOrdering::SeqCst),
1286 }
1287 }
1288 }
1289 };
1290}
1291
1292static PROPERTY_KEY_COUNTER: AtomicUsize = AtomicUsize::new(0);
1294unique_id!(TransformKey, PROPERTY_KEY_COUNTER);
1295unique_id!(ColorKey, PROPERTY_KEY_COUNTER);
1296unique_id!(OpacityKey, PROPERTY_KEY_COUNTER);
1297
1298static IMAGE_ID_COUNTER: AtomicUsize = AtomicUsize::new(0);
1299unique_id!(ImageId, IMAGE_ID_COUNTER);
1300static FONT_ID_COUNTER: AtomicUsize = AtomicUsize::new(0);
1301unique_id!(FontId, FONT_ID_COUNTER);
1302
1303#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1304#[repr(C)]
1305pub struct ImageMask {
1306 pub image: ImageRef,
1307 pub rect: LogicalRect,
1308 pub repeat: bool,
1309}
1310
1311impl_option!(
1312 ImageMask,
1313 OptionImageMask,
1314 copy = false,
1315 [Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash]
1316);
1317
1318#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1319pub enum ImmediateFontId {
1320 Resolved((StyleFontFamilyHash, FontKey)),
1321 Unresolved(StyleFontFamilyVec),
1322}
1323
1324#[derive(Debug, Clone, PartialEq, PartialOrd)]
1325#[repr(C, u8)]
1326pub enum RawImageData {
1327 U8(U8Vec),
1329 U16(U16Vec),
1331 F32(F32Vec),
1333}
1334
1335impl RawImageData {
1336 pub fn get_u8_vec_ref(&self) -> Option<&U8Vec> {
1337 match self {
1338 RawImageData::U8(v) => Some(v),
1339 _ => None,
1340 }
1341 }
1342
1343 pub fn get_u16_vec_ref(&self) -> Option<&U16Vec> {
1344 match self {
1345 RawImageData::U16(v) => Some(v),
1346 _ => None,
1347 }
1348 }
1349
1350 pub fn get_f32_vec_ref(&self) -> Option<&F32Vec> {
1351 match self {
1352 RawImageData::F32(v) => Some(v),
1353 _ => None,
1354 }
1355 }
1356
1357 fn get_u8_vec(self) -> Option<U8Vec> {
1358 match self {
1359 RawImageData::U8(v) => Some(v),
1360 _ => None,
1361 }
1362 }
1363
1364 fn get_u16_vec(self) -> Option<U16Vec> {
1365 match self {
1366 RawImageData::U16(v) => Some(v),
1367 _ => None,
1368 }
1369 }
1370}
1371
1372#[derive(Debug, Clone, PartialEq, PartialOrd)]
1373#[repr(C)]
1374pub struct RawImage {
1375 pub pixels: RawImageData,
1376 pub width: usize,
1377 pub height: usize,
1378 pub premultiplied_alpha: bool,
1379 pub data_format: RawImageFormat,
1380 pub tag: U8Vec,
1381}
1382
1383impl RawImage {
1384 pub fn null_image() -> Self {
1386 Self {
1387 pixels: RawImageData::U8(Vec::new().into()),
1388 width: 0,
1389 height: 0,
1390 premultiplied_alpha: true,
1391 data_format: RawImageFormat::BGRA8,
1392 tag: Vec::new().into(),
1393 }
1394 }
1395
1396 pub fn allocate_mask(size: LayoutSize) -> Self {
1398 Self {
1399 pixels: RawImageData::U8(
1400 vec![0; size.width.max(0) as usize * size.height.max(0) as usize].into(),
1401 ),
1402 width: size.width as usize,
1403 height: size.height as usize,
1404 premultiplied_alpha: true,
1405 data_format: RawImageFormat::R8,
1406 tag: Vec::new().into(),
1407 }
1408 }
1409
1410 pub fn into_loaded_image_source(self) -> Option<(ImageData, ImageDescriptor)> {
1416 #[inline(always)]
1419 fn premultiply_alpha(array: &mut [u8]) {
1420 if array.len() != 4 {
1421 return;
1422 }
1423 let a = u32::from(array[3]);
1424 array[0] = (((array[0] as u32 * a) + 128) / 255) as u8;
1425 array[1] = (((array[1] as u32 * a) + 128) / 255) as u8;
1426 array[2] = (((array[2] as u32 * a) + 128) / 255) as u8;
1427 }
1428
1429 #[inline(always)]
1430 fn normalize_u16(i: u16) -> u8 {
1431 ((core::u16::MAX as f32 / i as f32) * core::u8::MAX as f32) as u8
1432 }
1433
1434 let RawImage {
1435 width,
1436 height,
1437 pixels,
1438 mut data_format,
1439 premultiplied_alpha,
1440 tag,
1441 } = self;
1442
1443 const FOUR_BPP: usize = 4;
1444 const TWO_CHANNELS: usize = 2;
1445 const THREE_CHANNELS: usize = 3;
1446 const FOUR_CHANNELS: usize = 4;
1447
1448 let mut is_opaque = true;
1449
1450 let expected_len = width * height;
1451
1452 let bytes: U8Vec = match data_format {
1453 RawImageFormat::R8 => {
1454 let pixels = pixels.get_u8_vec()?;
1456
1457 if pixels.len() != expected_len {
1458 return None;
1459 }
1460
1461 let pixels_ref = pixels.as_ref();
1462 let mut px = vec![0; pixels_ref.len() * 4];
1463 for (i, r) in pixels_ref.iter().enumerate() {
1464 px[i * 4 + 0] = *r;
1465 px[i * 4 + 1] = *r;
1466 px[i * 4 + 2] = *r;
1467 px[i * 4 + 3] = 0xff;
1468 }
1469
1470 data_format = RawImageFormat::BGRA8;
1471 px.into()
1472 }
1473 RawImageFormat::RG8 => {
1474 let pixels = pixels.get_u8_vec()?;
1475
1476 if pixels.len() != expected_len * TWO_CHANNELS {
1477 return None;
1478 }
1479
1480 let mut px = vec![0; expected_len * FOUR_BPP];
1481
1482 for (pixel_index, greyalpha) in
1485 pixels.as_ref().chunks_exact(TWO_CHANNELS).enumerate()
1486 {
1487 let grey = greyalpha[0];
1488 let alpha = greyalpha[1];
1489
1490 if alpha != 255 {
1491 is_opaque = false;
1492 }
1493
1494 px[pixel_index * FOUR_BPP] = grey;
1495 px[(pixel_index * FOUR_BPP) + 1] = grey;
1496 px[(pixel_index * FOUR_BPP) + 2] = grey;
1497 px[(pixel_index * FOUR_BPP) + 3] = alpha;
1498 }
1499
1500 data_format = RawImageFormat::BGRA8;
1501 px.into()
1502 }
1503 RawImageFormat::RGB8 => {
1504 let pixels = pixels.get_u8_vec()?;
1505
1506 if pixels.len() != expected_len * THREE_CHANNELS {
1507 return None;
1508 }
1509
1510 let mut px = vec![0; expected_len * FOUR_BPP];
1511
1512 for (pixel_index, rgb) in pixels.as_ref().chunks_exact(THREE_CHANNELS).enumerate() {
1514 let red = rgb[0];
1515 let green = rgb[1];
1516 let blue = rgb[2];
1517
1518 px[pixel_index * FOUR_BPP] = blue;
1519 px[(pixel_index * FOUR_BPP) + 1] = green;
1520 px[(pixel_index * FOUR_BPP) + 2] = red;
1521 px[(pixel_index * FOUR_BPP) + 3] = 0xff;
1522 }
1523
1524 data_format = RawImageFormat::BGRA8;
1525 px.into()
1526 }
1527 RawImageFormat::RGBA8 => {
1528 let mut pixels: Vec<u8> = pixels.get_u8_vec()?.into_library_owned_vec();
1529
1530 if pixels.len() != expected_len * FOUR_CHANNELS {
1531 return None;
1532 }
1533
1534 if premultiplied_alpha {
1537 for rgba in pixels.chunks_exact_mut(4) {
1538 let (r, gba) = rgba.split_first_mut()?;
1539 core::mem::swap(r, gba.get_mut(1)?);
1540 let a = rgba.get_mut(3)?;
1541 if *a != 255 {
1542 is_opaque = false;
1543 }
1544 }
1545 } else {
1546 for rgba in pixels.chunks_exact_mut(4) {
1547 let (r, gba) = rgba.split_first_mut()?;
1549 core::mem::swap(r, gba.get_mut(1)?);
1550 let a = rgba.get_mut(3)?;
1551 if *a != 255 {
1552 is_opaque = false;
1553 }
1554 premultiply_alpha(rgba); }
1556 }
1557
1558 data_format = RawImageFormat::BGRA8;
1559 pixels.into()
1560 }
1561 RawImageFormat::R16 => {
1562 let pixels = pixels.get_u16_vec()?;
1563
1564 if pixels.len() != expected_len {
1565 return None;
1566 }
1567
1568 let mut px = vec![0; expected_len * FOUR_BPP];
1569
1570 for (pixel_index, grey_u16) in pixels.as_ref().iter().enumerate() {
1572 let grey_u8 = normalize_u16(*grey_u16);
1573 px[pixel_index * FOUR_BPP] = grey_u8;
1574 px[(pixel_index * FOUR_BPP) + 1] = grey_u8;
1575 px[(pixel_index * FOUR_BPP) + 2] = grey_u8;
1576 px[(pixel_index * FOUR_BPP) + 3] = 0xff;
1577 }
1578
1579 data_format = RawImageFormat::BGRA8;
1580 px.into()
1581 }
1582 RawImageFormat::RG16 => {
1583 let pixels = pixels.get_u16_vec()?;
1584
1585 if pixels.len() != expected_len * TWO_CHANNELS {
1586 return None;
1587 }
1588
1589 let mut px = vec![0; expected_len * FOUR_BPP];
1590
1591 for (pixel_index, greyalpha) in
1593 pixels.as_ref().chunks_exact(TWO_CHANNELS).enumerate()
1594 {
1595 let grey_u8 = normalize_u16(greyalpha[0]);
1596 let alpha_u8 = normalize_u16(greyalpha[1]);
1597
1598 if alpha_u8 != 255 {
1599 is_opaque = false;
1600 }
1601
1602 px[pixel_index * FOUR_BPP] = grey_u8;
1603 px[(pixel_index * FOUR_BPP) + 1] = grey_u8;
1604 px[(pixel_index * FOUR_BPP) + 2] = grey_u8;
1605 px[(pixel_index * FOUR_BPP) + 3] = alpha_u8;
1606 }
1607
1608 data_format = RawImageFormat::BGRA8;
1609 px.into()
1610 }
1611 RawImageFormat::RGB16 => {
1612 let pixels = pixels.get_u16_vec()?;
1613
1614 if pixels.len() != expected_len * THREE_CHANNELS {
1615 return None;
1616 }
1617
1618 let mut px = vec![0; expected_len * FOUR_BPP];
1619
1620 for (pixel_index, rgb) in pixels.as_ref().chunks_exact(THREE_CHANNELS).enumerate() {
1622 let red_u8 = normalize_u16(rgb[0]);
1623 let green_u8 = normalize_u16(rgb[1]);
1624 let blue_u8 = normalize_u16(rgb[2]);
1625
1626 px[pixel_index * FOUR_BPP] = blue_u8;
1627 px[(pixel_index * FOUR_BPP) + 1] = green_u8;
1628 px[(pixel_index * FOUR_BPP) + 2] = red_u8;
1629 px[(pixel_index * FOUR_BPP) + 3] = 0xff;
1630 }
1631
1632 data_format = RawImageFormat::BGRA8;
1633 px.into()
1634 }
1635 RawImageFormat::RGBA16 => {
1636 let pixels = pixels.get_u16_vec()?;
1637
1638 if pixels.len() != expected_len * FOUR_CHANNELS {
1639 return None;
1640 }
1641
1642 let mut px = vec![0; expected_len * FOUR_BPP];
1643
1644 if premultiplied_alpha {
1646 for (pixel_index, rgba) in
1647 pixels.as_ref().chunks_exact(FOUR_CHANNELS).enumerate()
1648 {
1649 let red_u8 = normalize_u16(rgba[0]);
1650 let green_u8 = normalize_u16(rgba[1]);
1651 let blue_u8 = normalize_u16(rgba[2]);
1652 let alpha_u8 = normalize_u16(rgba[3]);
1653
1654 if alpha_u8 != 255 {
1655 is_opaque = false;
1656 }
1657
1658 px[pixel_index * FOUR_BPP] = blue_u8;
1659 px[(pixel_index * FOUR_BPP) + 1] = green_u8;
1660 px[(pixel_index * FOUR_BPP) + 2] = red_u8;
1661 px[(pixel_index * FOUR_BPP) + 3] = alpha_u8;
1662 }
1663 } else {
1664 for (pixel_index, rgba) in
1665 pixels.as_ref().chunks_exact(FOUR_CHANNELS).enumerate()
1666 {
1667 let red_u8 = normalize_u16(rgba[0]);
1668 let green_u8 = normalize_u16(rgba[1]);
1669 let blue_u8 = normalize_u16(rgba[2]);
1670 let alpha_u8 = normalize_u16(rgba[3]);
1671
1672 if alpha_u8 != 255 {
1673 is_opaque = false;
1674 }
1675
1676 px[pixel_index * FOUR_BPP] = blue_u8;
1677 px[(pixel_index * FOUR_BPP) + 1] = green_u8;
1678 px[(pixel_index * FOUR_BPP) + 2] = red_u8;
1679 px[(pixel_index * FOUR_BPP) + 3] = alpha_u8;
1680 premultiply_alpha(
1681 &mut px
1682 [(pixel_index * FOUR_BPP)..((pixel_index * FOUR_BPP) + FOUR_BPP)],
1683 );
1684 }
1685 }
1686
1687 data_format = RawImageFormat::BGRA8;
1688 px.into()
1689 }
1690 RawImageFormat::BGR8 => {
1691 let pixels = pixels.get_u8_vec()?;
1692
1693 if pixels.len() != expected_len * THREE_CHANNELS {
1694 return None;
1695 }
1696
1697 let mut px = vec![0; expected_len * FOUR_BPP];
1698
1699 for (pixel_index, bgr) in pixels.as_ref().chunks_exact(THREE_CHANNELS).enumerate() {
1701 let blue = bgr[0];
1702 let green = bgr[1];
1703 let red = bgr[2];
1704
1705 px[pixel_index * FOUR_BPP] = blue;
1706 px[(pixel_index * FOUR_BPP) + 1] = green;
1707 px[(pixel_index * FOUR_BPP) + 2] = red;
1708 px[(pixel_index * FOUR_BPP) + 3] = 0xff;
1709 }
1710
1711 data_format = RawImageFormat::BGRA8;
1712 px.into()
1713 }
1714 RawImageFormat::BGRA8 => {
1715 if premultiplied_alpha {
1716 let pixels = pixels.get_u8_vec()?;
1718
1719 is_opaque = pixels
1720 .as_ref()
1721 .chunks_exact(FOUR_CHANNELS)
1722 .all(|bgra| bgra[3] == 255);
1723
1724 pixels
1725 } else {
1726 let mut pixels: Vec<u8> = pixels.get_u8_vec()?.into_library_owned_vec();
1727
1728 if pixels.len() != expected_len * FOUR_BPP {
1729 return None;
1730 }
1731
1732 for bgra in pixels.chunks_exact_mut(FOUR_CHANNELS) {
1733 if bgra[3] != 255 {
1734 is_opaque = false;
1735 }
1736 premultiply_alpha(bgra);
1737 }
1738 data_format = RawImageFormat::BGRA8;
1739 pixels.into()
1740 }
1741 }
1742 RawImageFormat::RGBF32 => {
1743 let pixels = pixels.get_f32_vec_ref()?;
1744
1745 if pixels.len() != expected_len * THREE_CHANNELS {
1746 return None;
1747 }
1748
1749 let mut px = vec![0; expected_len * FOUR_BPP];
1750
1751 for (pixel_index, rgb) in pixels.as_ref().chunks_exact(THREE_CHANNELS).enumerate() {
1753 let red_u8 = (rgb[0] * 255.0) as u8;
1754 let green_u8 = (rgb[1] * 255.0) as u8;
1755 let blue_u8 = (rgb[2] * 255.0) as u8;
1756
1757 px[pixel_index * FOUR_BPP] = blue_u8;
1758 px[(pixel_index * FOUR_BPP) + 1] = green_u8;
1759 px[(pixel_index * FOUR_BPP) + 2] = red_u8;
1760 px[(pixel_index * FOUR_BPP) + 3] = 0xff;
1761 }
1762
1763 data_format = RawImageFormat::BGRA8;
1764 px.into()
1765 }
1766 RawImageFormat::RGBAF32 => {
1767 let pixels = pixels.get_f32_vec_ref()?;
1768
1769 if pixels.len() != expected_len * FOUR_CHANNELS {
1770 return None;
1771 }
1772
1773 let mut px = vec![0; expected_len * FOUR_BPP];
1774
1775 if premultiplied_alpha {
1777 for (pixel_index, rgba) in
1778 pixels.as_ref().chunks_exact(FOUR_CHANNELS).enumerate()
1779 {
1780 let red_u8 = (rgba[0] * 255.0) as u8;
1781 let green_u8 = (rgba[1] * 255.0) as u8;
1782 let blue_u8 = (rgba[2] * 255.0) as u8;
1783 let alpha_u8 = (rgba[3] * 255.0) as u8;
1784
1785 if alpha_u8 != 255 {
1786 is_opaque = false;
1787 }
1788
1789 px[pixel_index * FOUR_BPP] = blue_u8;
1790 px[(pixel_index * FOUR_BPP) + 1] = green_u8;
1791 px[(pixel_index * FOUR_BPP) + 2] = red_u8;
1792 px[(pixel_index * FOUR_BPP) + 3] = alpha_u8;
1793 }
1794 } else {
1795 for (pixel_index, rgba) in
1796 pixels.as_ref().chunks_exact(FOUR_CHANNELS).enumerate()
1797 {
1798 let red_u8 = (rgba[0] * 255.0) as u8;
1799 let green_u8 = (rgba[1] * 255.0) as u8;
1800 let blue_u8 = (rgba[2] * 255.0) as u8;
1801 let alpha_u8 = (rgba[3] * 255.0) as u8;
1802
1803 if alpha_u8 != 255 {
1804 is_opaque = false;
1805 }
1806
1807 px[pixel_index * FOUR_BPP] = blue_u8;
1808 px[(pixel_index * FOUR_BPP) + 1] = green_u8;
1809 px[(pixel_index * FOUR_BPP) + 2] = red_u8;
1810 px[(pixel_index * FOUR_BPP) + 3] = alpha_u8;
1811 premultiply_alpha(
1812 &mut px
1813 [(pixel_index * FOUR_BPP)..((pixel_index * FOUR_BPP) + FOUR_BPP)],
1814 );
1815 }
1816 }
1817
1818 data_format = RawImageFormat::BGRA8;
1819 px.into()
1820 }
1821 };
1822
1823 let image_data = ImageData::Raw(SharedRawImageData::new(bytes));
1824 let image_descriptor = ImageDescriptor {
1825 format: data_format,
1826 width,
1827 height,
1828 offset: 0,
1829 stride: None.into(),
1830 flags: ImageDescriptorFlags {
1831 is_opaque,
1832 allow_mipmaps: true,
1833 },
1834 };
1835
1836 Some((image_data, image_descriptor))
1837 }
1838}
1839
1840impl_option!(
1841 RawImage,
1842 OptionRawImage,
1843 copy = false,
1844 [Debug, Clone, PartialEq, PartialOrd]
1845);
1846
1847pub fn font_size_to_au(font_size: StyleFontSize) -> Au {
1848 Au::from_px(font_size.inner.to_pixels_internal(0.0, DEFAULT_FONT_SIZE))
1849}
1850
1851pub type FontInstanceFlags = u32;
1852
1853pub const FONT_INSTANCE_FLAG_SYNTHETIC_BOLD: u32 = 1 << 1;
1855pub const FONT_INSTANCE_FLAG_EMBEDDED_BITMAPS: u32 = 1 << 2;
1856pub const FONT_INSTANCE_FLAG_SUBPIXEL_BGR: u32 = 1 << 3;
1857pub const FONT_INSTANCE_FLAG_TRANSPOSE: u32 = 1 << 4;
1858pub const FONT_INSTANCE_FLAG_FLIP_X: u32 = 1 << 5;
1859pub const FONT_INSTANCE_FLAG_FLIP_Y: u32 = 1 << 6;
1860pub const FONT_INSTANCE_FLAG_SUBPIXEL_POSITION: u32 = 1 << 7;
1861
1862pub const FONT_INSTANCE_FLAG_FORCE_GDI: u32 = 1 << 16;
1864
1865pub const FONT_INSTANCE_FLAG_FONT_SMOOTHING: u32 = 1 << 16;
1867
1868pub const FONT_INSTANCE_FLAG_FORCE_AUTOHINT: u32 = 1 << 16;
1870pub const FONT_INSTANCE_FLAG_NO_AUTOHINT: u32 = 1 << 17;
1871pub const FONT_INSTANCE_FLAG_VERTICAL_LAYOUT: u32 = 1 << 18;
1872pub const FONT_INSTANCE_FLAG_LCD_VERTICAL: u32 = 1 << 19;
1873
1874#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
1875pub struct GlyphOptions {
1876 pub render_mode: FontRenderMode,
1877 pub flags: FontInstanceFlags,
1878}
1879
1880#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
1881pub enum FontRenderMode {
1882 Mono,
1883 Alpha,
1884 Subpixel,
1885}
1886
1887#[cfg(target_arch = "wasm32")]
1888#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
1889pub struct FontInstancePlatformOptions {
1890 }
1892
1893#[cfg(target_os = "windows")]
1894#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
1895pub struct FontInstancePlatformOptions {
1896 pub gamma: u16,
1897 pub contrast: u8,
1898 pub cleartype_level: u8,
1899}
1900
1901#[cfg(target_os = "macos")]
1902#[derive(Default, Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
1903pub struct FontInstancePlatformOptions {
1904 pub unused: u32,
1905}
1906
1907#[cfg(target_os = "linux")]
1908#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
1909pub struct FontInstancePlatformOptions {
1910 pub lcd_filter: FontLCDFilter,
1911 pub hinting: FontHinting,
1912}
1913
1914#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
1915pub enum FontHinting {
1916 None,
1917 Mono,
1918 Light,
1919 Normal,
1920 LCD,
1921}
1922
1923#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
1924pub enum FontLCDFilter {
1925 None,
1926 Default,
1927 Light,
1928 Legacy,
1929}
1930
1931impl Default for FontLCDFilter {
1932 fn default() -> Self {
1933 FontLCDFilter::Default
1934 }
1935}
1936
1937#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
1938pub struct FontInstanceOptions {
1939 pub render_mode: FontRenderMode,
1940 pub flags: FontInstanceFlags,
1941 pub bg_color: ColorU,
1942 pub synthetic_italics: SyntheticItalics,
1946}
1947
1948impl Default for FontInstanceOptions {
1949 fn default() -> FontInstanceOptions {
1950 FontInstanceOptions {
1951 render_mode: FontRenderMode::Subpixel,
1952 flags: 0,
1953 bg_color: ColorU::TRANSPARENT,
1954 synthetic_italics: SyntheticItalics::default(),
1955 }
1956 }
1957}
1958
1959#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
1960pub struct SyntheticItalics {
1961 pub angle: i16,
1962}
1963
1964impl Default for SyntheticItalics {
1965 fn default() -> Self {
1966 Self { angle: 0 }
1967 }
1968}
1969
1970#[derive(Debug)]
1976#[repr(C)]
1977pub struct SharedRawImageData {
1978 pub data: *const U8Vec,
1980 pub copies: *const AtomicUsize,
1982 pub run_destructor: bool,
1984}
1985
1986impl SharedRawImageData {
1987 pub fn new(data: U8Vec) -> Self {
1989 Self {
1990 data: Box::into_raw(Box::new(data)),
1991 copies: Box::into_raw(Box::new(AtomicUsize::new(1))),
1992 run_destructor: true,
1993 }
1994 }
1995
1996 pub fn as_ref(&self) -> &[u8] {
1998 unsafe { (*self.data).as_ref() }
1999 }
2000
2001 pub fn get_bytes(&self) -> &[u8] {
2003 self.as_ref()
2004 }
2005
2006 pub fn as_ptr(&self) -> *const u8 {
2008 unsafe { (*self.data).as_ref().as_ptr() }
2009 }
2010
2011 pub fn len(&self) -> usize {
2013 unsafe { (*self.data).len() }
2014 }
2015
2016 pub fn is_empty(&self) -> bool {
2018 self.len() == 0
2019 }
2020
2021 pub fn into_inner(self) -> Option<U8Vec> {
2024 unsafe {
2025 if self.copies.as_ref().map(|m| m.load(AtomicOrdering::SeqCst)) == Some(1) {
2026 let data = Box::from_raw(self.data as *mut U8Vec);
2027 let _ = Box::from_raw(self.copies as *mut AtomicUsize);
2028 core::mem::forget(self); Some(*data)
2030 } else {
2031 None
2032 }
2033 }
2034 }
2035}
2036
2037unsafe impl Send for SharedRawImageData {}
2038unsafe impl Sync for SharedRawImageData {}
2039
2040impl Clone for SharedRawImageData {
2041 fn clone(&self) -> Self {
2042 unsafe {
2043 self.copies
2044 .as_ref()
2045 .map(|m| m.fetch_add(1, AtomicOrdering::SeqCst));
2046 }
2047 Self {
2048 data: self.data,
2049 copies: self.copies,
2050 run_destructor: true,
2051 }
2052 }
2053}
2054
2055impl Drop for SharedRawImageData {
2056 fn drop(&mut self) {
2057 self.run_destructor = false;
2058 unsafe {
2059 let copies = (*self.copies).fetch_sub(1, AtomicOrdering::SeqCst);
2060 if copies == 1 {
2061 let _ = Box::from_raw(self.data as *mut U8Vec);
2062 let _ = Box::from_raw(self.copies as *mut AtomicUsize);
2063 }
2064 }
2065 }
2066}
2067
2068impl PartialEq for SharedRawImageData {
2069 fn eq(&self, rhs: &Self) -> bool {
2070 self.data as usize == rhs.data as usize
2071 }
2072}
2073
2074impl Eq for SharedRawImageData {}
2075
2076impl PartialOrd for SharedRawImageData {
2077 fn partial_cmp(&self, other: &Self) -> Option<::core::cmp::Ordering> {
2078 Some(self.cmp(other))
2079 }
2080}
2081
2082impl Ord for SharedRawImageData {
2083 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
2084 (self.data as usize).cmp(&(other.data as usize))
2085 }
2086}
2087
2088impl Hash for SharedRawImageData {
2089 fn hash<H>(&self, state: &mut H)
2090 where
2091 H: Hasher,
2092 {
2093 (self.data as usize).hash(state)
2094 }
2095}
2096
2097#[derive(Debug, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
2100#[repr(C, u8)]
2101pub enum ImageData {
2102 Raw(SharedRawImageData),
2105 External(ExternalImageData),
2108}
2109
2110#[derive(Debug, Copy, Clone, Eq, Hash, PartialEq, PartialOrd, Ord)]
2112#[repr(C, u8)]
2113pub enum ExternalImageType {
2114 TextureHandle(ImageBufferKind),
2116 Buffer,
2118}
2119
2120#[repr(C)]
2124#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, PartialOrd, Ord)]
2125pub struct ExternalImageId {
2126 pub inner: u64,
2127}
2128
2129static LAST_EXTERNAL_IMAGE_ID: AtomicUsize = AtomicUsize::new(0);
2130
2131impl ExternalImageId {
2132 pub fn new() -> Self {
2134 Self {
2135 inner: LAST_EXTERNAL_IMAGE_ID.fetch_add(1, AtomicOrdering::SeqCst) as u64,
2136 }
2137 }
2138}
2139
2140#[derive(Debug, Clone, PartialEq, PartialOrd)]
2141#[repr(C, u8)]
2142pub enum GlyphOutlineOperation {
2143 MoveTo(OutlineMoveTo),
2144 LineTo(OutlineLineTo),
2145 QuadraticCurveTo(OutlineQuadTo),
2146 CubicCurveTo(OutlineCubicTo),
2147 ClosePath,
2148}
2149
2150impl_option!(
2151 GlyphOutlineOperation,
2152 OptionGlyphOutlineOperation,
2153 copy = false,
2154 [Debug, Clone, PartialEq, PartialOrd]
2155);
2156
2157#[derive(Debug, Clone, PartialEq, PartialOrd)]
2159#[repr(C)]
2160pub struct OutlineMoveTo {
2161 pub x: i16,
2162 pub y: i16,
2163}
2164
2165#[derive(Debug, Clone, PartialEq, PartialOrd)]
2167#[repr(C)]
2168pub struct OutlineLineTo {
2169 pub x: i16,
2170 pub y: i16,
2171}
2172
2173#[derive(Debug, Clone, PartialEq, PartialOrd)]
2175#[repr(C)]
2176pub struct OutlineQuadTo {
2177 pub ctrl_1_x: i16,
2178 pub ctrl_1_y: i16,
2179 pub end_x: i16,
2180 pub end_y: i16,
2181}
2182
2183#[derive(Debug, Clone, PartialEq, PartialOrd)]
2185#[repr(C)]
2186pub struct OutlineCubicTo {
2187 pub ctrl_1_x: i16,
2188 pub ctrl_1_y: i16,
2189 pub ctrl_2_x: i16,
2190 pub ctrl_2_y: i16,
2191 pub end_x: i16,
2192 pub end_y: i16,
2193}
2194
2195#[derive(Debug, Clone, PartialEq, PartialOrd)]
2196#[repr(C)]
2197pub struct GlyphOutline {
2198 pub operations: GlyphOutlineOperationVec,
2199}
2200
2201azul_css::impl_vec!(GlyphOutlineOperation, GlyphOutlineOperationVec, GlyphOutlineOperationVecDestructor, GlyphOutlineOperationVecDestructorType, GlyphOutlineOperationVecSlice, OptionGlyphOutlineOperation);
2202azul_css::impl_vec_clone!(
2203 GlyphOutlineOperation,
2204 GlyphOutlineOperationVec,
2205 GlyphOutlineOperationVecDestructor
2206);
2207azul_css::impl_vec_debug!(GlyphOutlineOperation, GlyphOutlineOperationVec);
2208azul_css::impl_vec_partialord!(GlyphOutlineOperation, GlyphOutlineOperationVec);
2209azul_css::impl_vec_partialeq!(GlyphOutlineOperation, GlyphOutlineOperationVec);
2210
2211#[derive(Debug, Clone)]
2212#[repr(C)]
2213pub struct OwnedGlyphBoundingBox {
2214 pub max_x: i16,
2215 pub max_y: i16,
2216 pub min_x: i16,
2217 pub min_y: i16,
2218}
2219
2220#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
2222#[repr(C)]
2223pub enum ImageBufferKind {
2224 Texture2D = 0,
2226 TextureRect = 1,
2233 TextureExternal = 2,
2238}
2239
2240#[repr(C)]
2242#[derive(Debug, Clone, Eq, Hash, PartialEq, PartialOrd, Ord)]
2243pub struct ExternalImageData {
2244 pub id: ExternalImageId,
2246 pub channel_index: u8,
2249 pub image_type: ExternalImageType,
2251}
2252
2253pub type TileSize = u16;
2254
2255#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
2256pub enum ImageDirtyRect {
2257 All,
2258 Partial(LayoutRect),
2259}
2260
2261#[derive(Debug, Clone, PartialEq, PartialOrd)]
2262pub enum ResourceUpdate {
2263 AddFont(AddFont),
2264 DeleteFont(FontKey),
2265 AddFontInstance(AddFontInstance),
2266 DeleteFontInstance(FontInstanceKey),
2267 AddImage(AddImage),
2268 UpdateImage(UpdateImage),
2269 DeleteImage(ImageKey),
2270}
2271
2272#[derive(Debug, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
2273pub struct AddImage {
2274 pub key: ImageKey,
2275 pub descriptor: ImageDescriptor,
2276 pub data: ImageData,
2277 pub tiling: Option<TileSize>,
2278}
2279
2280#[derive(Debug, Clone, PartialEq, PartialOrd)]
2281pub struct UpdateImage {
2282 pub key: ImageKey,
2283 pub descriptor: ImageDescriptor,
2284 pub data: ImageData,
2285 pub dirty_rect: ImageDirtyRect,
2286}
2287
2288#[derive(Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
2291pub struct AddFont {
2292 pub key: FontKey,
2293 pub font: azul_css::props::basic::FontRef,
2294}
2295
2296impl fmt::Debug for AddFont {
2297 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2298 write!(
2299 f,
2300 "AddFont {{ key: {:?}, font: {:?} }}",
2301 self.key, self.font
2302 )
2303 }
2304}
2305
2306#[derive(Debug, Clone, PartialEq, PartialOrd)]
2307pub struct AddFontInstance {
2308 pub key: FontInstanceKey,
2309 pub font_key: FontKey,
2310 pub glyph_size: (Au, DpiScaleFactor),
2311 pub options: Option<FontInstanceOptions>,
2312 pub platform_options: Option<FontInstancePlatformOptions>,
2313 pub variations: Vec<FontVariation>,
2314}
2315
2316#[repr(C)]
2317#[derive(Clone, Copy, Debug, PartialOrd, PartialEq)]
2318pub struct FontVariation {
2319 pub tag: u32,
2320 pub value: f32,
2321}
2322
2323#[repr(C)]
2324#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
2325pub struct Epoch {
2326 inner: u32,
2327}
2328
2329impl fmt::Display for Epoch {
2330 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2331 write!(f, "{}", self.inner)
2332 }
2333}
2334
2335impl Epoch {
2336 pub const fn new() -> Self {
2340 Self { inner: 0 }
2341 }
2342 pub const fn from(i: u32) -> Self {
2343 Self { inner: i }
2344 }
2345 pub const fn into_u32(&self) -> u32 {
2346 self.inner
2347 }
2348
2349 pub fn increment(&mut self) {
2352 use core::u32;
2353 const MAX_ID: u32 = u32::MAX - 1;
2354 *self = match self.inner {
2355 MAX_ID => Epoch { inner: 0 },
2356 other => Epoch {
2357 inner: other.saturating_add(1),
2358 },
2359 };
2360 }
2361}
2362
2363#[derive(Debug, Clone, Copy, Hash, PartialEq, PartialOrd, Eq, Ord)]
2365pub struct Au(pub i32);
2366
2367pub const AU_PER_PX: i32 = 60;
2368pub const MAX_AU: i32 = (1 << 30) - 1;
2369pub const MIN_AU: i32 = -(1 << 30) - 1;
2370
2371impl Au {
2372 pub fn from_px(px: f32) -> Self {
2373 let target_app_units = (px * AU_PER_PX as f32) as i32;
2374 Au(target_app_units.min(MAX_AU).max(MIN_AU))
2375 }
2376 pub fn into_px(&self) -> f32 {
2377 self.0 as f32 / AU_PER_PX as f32
2378 }
2379}
2380
2381#[derive(Debug)]
2383pub enum AddFontMsg {
2384 Font(FontKey, StyleFontFamilyHash, FontRef),
2386 Instance(AddFontInstance, (Au, DpiScaleFactor)),
2387}
2388
2389impl AddFontMsg {
2390 pub fn into_resource_update(&self) -> ResourceUpdate {
2391 use self::AddFontMsg::*;
2392 match self {
2393 Font(font_key, _, font_ref) => ResourceUpdate::AddFont(AddFont {
2394 key: *font_key,
2395 font: font_ref.clone(),
2396 }),
2397 Instance(fi, _) => ResourceUpdate::AddFontInstance(fi.clone()),
2398 }
2399 }
2400}
2401
2402#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
2403pub enum DeleteFontMsg {
2404 Font(FontKey),
2405 Instance(FontInstanceKey, (Au, DpiScaleFactor)),
2406}
2407
2408impl DeleteFontMsg {
2409 pub fn into_resource_update(&self) -> ResourceUpdate {
2410 use self::DeleteFontMsg::*;
2411 match self {
2412 Font(f) => ResourceUpdate::DeleteFont(*f),
2413 Instance(fi, _) => ResourceUpdate::DeleteFontInstance(*fi),
2414 }
2415 }
2416}
2417
2418#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
2419pub struct AddImageMsg(pub AddImage);
2420
2421impl AddImageMsg {
2422 pub fn into_resource_update(&self) -> ResourceUpdate {
2423 ResourceUpdate::AddImage(self.0.clone())
2424 }
2425}
2426
2427#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
2428pub struct DeleteImageMsg(ImageKey);
2429
2430impl DeleteImageMsg {
2431 pub fn into_resource_update(&self) -> ResourceUpdate {
2432 ResourceUpdate::DeleteImage(self.0.clone())
2433 }
2434}
2435
2436#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2437#[repr(C)]
2438pub struct LoadedFontSource {
2439 pub data: U8Vec,
2440 pub index: u32,
2441 pub load_outlines: bool,
2442}
2443
2444pub type LoadFontFn = fn(&StyleFontFamily, &FcFontCache) -> Option<LoadedFontSource>;
2446
2447pub type ParseFontFn = fn(LoadedFontSource) -> Option<FontRef>; pub type GlStoreImageFn = fn(DocumentId, Epoch, Texture) -> ExternalImageId;
2451
2452pub fn build_add_font_resource_updates(
2461 renderer_resources: &mut RendererResources,
2462 dpi: DpiScaleFactor,
2463 fc_cache: &FcFontCache,
2464 id_namespace: IdNamespace,
2465 fonts_in_dom: &FastHashMap<ImmediateFontId, FastBTreeSet<Au>>,
2466 font_source_load_fn: LoadFontFn,
2467 parse_font_fn: ParseFontFn,
2468) -> Vec<(StyleFontFamilyHash, AddFontMsg)> {
2469 let mut resource_updates = alloc::vec::Vec::new();
2470 let mut font_instances_added_this_frame = FastBTreeSet::new();
2471
2472 'outer: for (im_font_id, font_sizes) in fonts_in_dom {
2473 macro_rules! insert_font_instances {
2474 ($font_family_hash:expr, $font_key:expr, $font_size:expr) => {{
2475 let font_instance_key_exists = renderer_resources
2476 .currently_registered_fonts
2477 .get(&$font_key)
2478 .and_then(|(_, font_instances)| font_instances.get(&($font_size, dpi)))
2479 .is_some()
2480 || font_instances_added_this_frame.contains(&($font_key, ($font_size, dpi)));
2481
2482 if !font_instance_key_exists {
2483 let font_instance_key = FontInstanceKey::unique(id_namespace);
2484
2485 #[cfg(target_os = "windows")]
2487 let platform_options = FontInstancePlatformOptions {
2488 gamma: 300,
2489 contrast: 100,
2490 cleartype_level: 100,
2491 };
2492
2493 #[cfg(target_os = "linux")]
2494 let platform_options = FontInstancePlatformOptions {
2495 lcd_filter: FontLCDFilter::Default,
2496 hinting: FontHinting::Normal,
2497 };
2498
2499 #[cfg(target_os = "macos")]
2500 let platform_options = FontInstancePlatformOptions::default();
2501
2502 #[cfg(target_arch = "wasm32")]
2503 let platform_options = FontInstancePlatformOptions::default();
2504
2505 let options = FontInstanceOptions {
2506 render_mode: FontRenderMode::Subpixel,
2507 flags: 0 | FONT_INSTANCE_FLAG_NO_AUTOHINT,
2508 ..Default::default()
2509 };
2510
2511 font_instances_added_this_frame.insert(($font_key, ($font_size, dpi)));
2512 resource_updates.push((
2513 $font_family_hash,
2514 AddFontMsg::Instance(
2515 AddFontInstance {
2516 key: font_instance_key,
2517 font_key: $font_key,
2518 glyph_size: ($font_size, dpi),
2519 options: Some(options),
2520 platform_options: Some(platform_options),
2521 variations: alloc::vec::Vec::new(),
2522 },
2523 ($font_size, dpi),
2524 ),
2525 ));
2526 }
2527 }};
2528 }
2529
2530 match im_font_id {
2531 ImmediateFontId::Resolved((font_family_hash, font_id)) => {
2532 for font_size in font_sizes.iter() {
2535 insert_font_instances!(*font_family_hash, *font_id, *font_size);
2536 }
2537 }
2538 ImmediateFontId::Unresolved(style_font_families) => {
2539 let mut font_family_hash = None;
2549 let font_families_hash = StyleFontFamiliesHash::new(style_font_families.as_ref());
2550
2551 'inner: for family in style_font_families.as_ref().iter() {
2553 let current_family_hash = StyleFontFamilyHash::new(&family);
2554
2555 if let Some(font_id) = renderer_resources.font_id_map.get(¤t_family_hash)
2556 {
2557 for font_size in font_sizes {
2559 insert_font_instances!(current_family_hash, *font_id, *font_size);
2560 }
2561 continue 'outer;
2562 }
2563
2564 let font_ref = match family {
2565 StyleFontFamily::Ref(r) => r.clone(), other => {
2567 let font_data = match (font_source_load_fn)(&other, fc_cache) {
2569 Some(s) => s,
2570 None => continue 'inner,
2571 };
2572
2573 let font_ref = match (parse_font_fn)(font_data) {
2574 Some(s) => s,
2575 None => continue 'inner,
2576 };
2577
2578 font_ref
2579 }
2580 };
2581
2582 font_family_hash = Some((current_family_hash, font_ref));
2584 break 'inner;
2585 }
2586
2587 let (font_family_hash, font_ref) = match font_family_hash {
2588 None => continue 'outer, Some(s) => s,
2590 };
2591
2592 let font_key = FontKey::unique(id_namespace);
2594 let add_font_msg = AddFontMsg::Font(font_key, font_family_hash, font_ref);
2595
2596 renderer_resources
2597 .font_id_map
2598 .insert(font_family_hash, font_key);
2599 renderer_resources
2600 .font_families_map
2601 .insert(font_families_hash, font_family_hash);
2602 resource_updates.push((font_family_hash, add_font_msg));
2603
2604 for font_size in font_sizes {
2606 insert_font_instances!(font_family_hash, font_key, *font_size);
2607 }
2608 }
2609 }
2610 }
2611
2612 resource_updates
2613}
2614
2615#[allow(unused_variables)]
2631pub fn build_add_image_resource_updates(
2632 renderer_resources: &RendererResources,
2633 id_namespace: IdNamespace,
2634 epoch: Epoch,
2635 document_id: &DocumentId,
2636 images_in_dom: &FastBTreeSet<ImageRef>,
2637 insert_into_active_gl_textures: GlStoreImageFn,
2638) -> Vec<(ImageRefHash, AddImageMsg)> {
2639 images_in_dom
2640 .iter()
2641 .filter_map(|image_ref| {
2642 let image_ref_hash = image_ref_get_hash(&image_ref);
2643
2644 if renderer_resources
2645 .currently_registered_images
2646 .contains_key(&image_ref_hash)
2647 {
2648 return None;
2649 }
2650
2651 match image_ref.get_data() {
2654 DecodedImage::Gl(texture) => {
2655 let descriptor = texture.get_descriptor();
2656 let key = image_ref_hash_to_image_key(image_ref_hash, id_namespace);
2657 let external_image_id =
2659 (insert_into_active_gl_textures)(*document_id, epoch, texture.clone());
2660 Some((
2661 image_ref_hash,
2662 AddImageMsg(AddImage {
2663 key,
2664 data: ImageData::External(ExternalImageData {
2665 id: external_image_id,
2666 channel_index: 0,
2667 image_type: ExternalImageType::TextureHandle(
2668 ImageBufferKind::Texture2D,
2669 ),
2670 }),
2671 descriptor,
2672 tiling: None,
2673 }),
2674 ))
2675 }
2676 DecodedImage::Raw((descriptor, data)) => {
2677 let key = image_ref_hash_to_image_key(image_ref_hash, id_namespace);
2678 Some((
2679 image_ref_hash,
2680 AddImageMsg(AddImage {
2681 key,
2682 data: data.clone(), descriptor: descriptor.clone(), tiling: None,
2686 }),
2687 ))
2688 }
2689 DecodedImage::NullImage {
2690 width: _,
2691 height: _,
2692 format: _,
2693 tag: _,
2694 } => None,
2695 DecodedImage::Callback(_) => None, }
2698 })
2699 .collect()
2700}
2701
2702fn add_gl_resources(
2703 renderer_resources: &mut RendererResources,
2704 all_resource_updates: &mut Vec<ResourceUpdate>,
2705 add_image_resources: Vec<(ImageRefHash, ImageRefHash, AddImageMsg)>,
2706) {
2707 let add_image_resources = add_image_resources
2708 .into_iter()
2709 .map(|(_, k, v)| (k, v))
2711 .collect::<Vec<_>>();
2712
2713 add_resources(
2714 renderer_resources,
2715 all_resource_updates,
2716 Vec::new(),
2717 add_image_resources,
2718 );
2719}
2720
2721pub fn add_resources(
2726 renderer_resources: &mut RendererResources,
2727 all_resource_updates: &mut Vec<ResourceUpdate>,
2728 add_font_resources: Vec<(StyleFontFamilyHash, AddFontMsg)>,
2729 add_image_resources: Vec<(ImageRefHash, AddImageMsg)>,
2730) {
2731 all_resource_updates.extend(
2732 add_font_resources
2733 .iter()
2734 .map(|(_, f)| f.into_resource_update()),
2735 );
2736 all_resource_updates.extend(
2737 add_image_resources
2738 .iter()
2739 .map(|(_, i)| i.into_resource_update()),
2740 );
2741
2742 for (image_ref_hash, add_image_msg) in add_image_resources.iter() {
2743 renderer_resources.currently_registered_images.insert(
2744 *image_ref_hash,
2745 ResolvedImage {
2746 key: add_image_msg.0.key,
2747 descriptor: add_image_msg.0.descriptor,
2748 },
2749 );
2750 }
2751
2752 for (_, add_font_msg) in add_font_resources {
2753 use self::AddFontMsg::*;
2754 match add_font_msg {
2755 Font(fk, font_family_hash, font_ref) => {
2756 renderer_resources
2757 .currently_registered_fonts
2758 .entry(fk)
2759 .or_insert_with(|| (font_ref.clone(), FastHashMap::default()));
2760
2761 renderer_resources
2763 .font_hash_map
2764 .insert(font_ref.get_hash(), fk);
2765 }
2766 Instance(fi, size) => {
2767 if let Some((_, instances)) = renderer_resources
2768 .currently_registered_fonts
2769 .get_mut(&fi.font_key)
2770 {
2771 instances.insert(size, fi.key);
2772 }
2773 }
2774 }
2775 }
2776}