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 AzString, F32Vec, LayoutDebugMessage, OptionI32, U16Vec, U32Vec, U8Vec,
17};
18use rust_fontconfig::FcFontCache;
19
20pub use crate::callbacks::{
22 CoreImageCallback, CoreRenderImageCallback, CoreRenderImageCallbackType,
23};
24use crate::{
25 callbacks::IFrameCallback,
26 dom::{DomId, NodeData, NodeType},
27 geom::{LogicalPosition, LogicalRect, LogicalSize},
28 gl::{OptionGlContextPtr, Texture},
29 hit_test::DocumentId,
30 id::NodeId,
31 prop_cache::CssPropertyCache,
32 refany::RefAny,
33 styled_dom::{
34 NodeHierarchyItemId, StyleFontFamiliesHash, StyleFontFamilyHash, StyledDom, StyledNodeState,
35 },
36 ui_solver::GlyphInstance,
37 window::OptionChar,
38 FastBTreeSet, FastHashMap,
39};
40
41#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
42#[repr(C)]
43pub struct DpiScaleFactor {
44 pub inner: FloatValue,
45}
46
47impl DpiScaleFactor {
48 pub fn new(f: f32) -> Self {
49 Self {
50 inner: FloatValue::new(f),
51 }
52 }
53}
54
55#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
57#[repr(C)]
58pub enum AppTerminationBehavior {
59 ReturnToMain,
63 RunForever,
66 EndProcess,
69}
70
71impl Default for AppTerminationBehavior {
72 fn default() -> Self {
73 AppTerminationBehavior::EndProcess
75 }
76}
77
78#[derive(Debug, Clone)]
80#[repr(C)]
81pub struct AppConfig {
82 pub log_level: AppLogLevel,
86 pub enable_visual_panic_hook: bool,
89 pub enable_logging_on_panic: bool,
92 pub enable_tab_navigation: bool,
95 pub termination_behavior: AppTerminationBehavior,
98 pub icon_provider: crate::icon::IconProviderHandle,
102}
103
104impl AppConfig {
105 pub fn create() -> Self {
106 Self {
107 log_level: AppLogLevel::Error,
108 enable_visual_panic_hook: false,
109 enable_logging_on_panic: true,
110 enable_tab_navigation: true,
111 termination_behavior: AppTerminationBehavior::default(),
112 icon_provider: crate::icon::IconProviderHandle::new(),
113 }
114 }
115}
116
117impl Default for AppConfig {
118 fn default() -> Self {
119 Self::create()
120 }
121}
122
123#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
124#[repr(C)]
125pub enum AppLogLevel {
126 Off,
127 Error,
128 Warn,
129 Info,
130 Debug,
131 Trace,
132}
133
134#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
135pub struct PrimitiveFlags {
136 pub is_backface_visible: bool,
138 pub is_scrollbar_container: bool,
140 pub is_scrollbar_thumb: bool,
142 pub prefer_compositor_surface: bool,
146 pub supports_external_compositor_surface: bool,
150}
151
152#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
154#[repr(C)]
155pub struct ImageDescriptor {
156 pub format: RawImageFormat,
158 pub width: usize,
160 pub height: usize,
161 pub stride: OptionI32,
166 pub offset: i32,
172 pub flags: ImageDescriptorFlags,
174}
175
176#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
178#[repr(C)]
179pub struct ImageDescriptorFlags {
180 pub is_opaque: bool,
183 pub allow_mipmaps: bool,
189}
190
191#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
192pub struct IdNamespace(pub u32);
193
194impl ::core::fmt::Display for IdNamespace {
195 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
196 write!(f, "IdNamespace({})", self.0)
197 }
198}
199
200impl ::core::fmt::Debug for IdNamespace {
201 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
202 write!(f, "{}", self)
203 }
204}
205
206#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
207#[repr(C)]
208pub enum RawImageFormat {
209 R8,
210 RG8,
211 RGB8,
212 RGBA8,
213 R16,
214 RG16,
215 RGB16,
216 RGBA16,
217 BGR8,
218 BGRA8,
219 RGBF32,
220 RGBAF32,
221}
222
223static IMAGE_KEY: AtomicU32 = AtomicU32::new(1);
225static FONT_KEY: AtomicU32 = AtomicU32::new(0);
226static FONT_INSTANCE_KEY: AtomicU32 = AtomicU32::new(0);
227
228#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
229pub struct ImageKey {
230 pub namespace: IdNamespace,
231 pub key: u32,
232}
233
234impl ImageKey {
235 pub const DUMMY: Self = Self {
236 namespace: IdNamespace(0),
237 key: 0,
238 };
239
240 pub fn unique(render_api_namespace: IdNamespace) -> Self {
241 Self {
242 namespace: render_api_namespace,
243 key: IMAGE_KEY.fetch_add(1, AtomicOrdering::SeqCst),
244 }
245 }
246}
247
248#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
249pub struct FontKey {
250 pub namespace: IdNamespace,
251 pub key: u32,
252}
253
254impl FontKey {
255 pub fn unique(render_api_namespace: IdNamespace) -> Self {
256 Self {
257 namespace: render_api_namespace,
258 key: FONT_KEY.fetch_add(1, AtomicOrdering::SeqCst),
259 }
260 }
261}
262
263#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
264pub struct FontInstanceKey {
265 pub namespace: IdNamespace,
266 pub key: u32,
267}
268
269impl FontInstanceKey {
270 pub fn unique(render_api_namespace: IdNamespace) -> Self {
271 Self {
272 namespace: render_api_namespace,
273 key: FONT_INSTANCE_KEY.fetch_add(1, AtomicOrdering::SeqCst),
274 }
275 }
276}
277
278#[derive(Debug)]
281pub enum DecodedImage {
282 NullImage {
285 width: usize,
286 height: usize,
287 format: RawImageFormat,
288 tag: Vec<u8>,
290 },
291 Gl(Texture),
293 Raw((ImageDescriptor, ImageData)),
295 Callback(CoreImageCallback),
297 }
302
303#[derive(Debug)]
304#[repr(C)]
305pub struct ImageRef {
306 pub data: *const DecodedImage,
308 pub copies: *const AtomicUsize,
310 pub run_destructor: bool,
311}
312
313impl ImageRef {
314 pub fn get_hash(&self) -> ImageRefHash {
315 image_ref_get_hash(self)
316 }
317}
318
319#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Hash, Ord, Eq)]
320#[repr(C)]
321pub struct ImageRefHash {
322 pub inner: usize,
323}
324
325impl_option!(
326 ImageRef,
327 OptionImageRef,
328 copy = false,
329 [Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
330);
331
332impl ImageRef {
333 pub fn into_inner(self) -> Option<DecodedImage> {
335 unsafe {
336 if self.copies.as_ref().map(|m| m.load(AtomicOrdering::SeqCst)) == Some(1) {
337 let data = Box::from_raw(self.data as *mut DecodedImage);
338 let _ = Box::from_raw(self.copies as *mut AtomicUsize);
339 core::mem::forget(self); Some(*data)
341 } else {
342 None
343 }
344 }
345 }
346
347 pub fn get_data<'a>(&'a self) -> &'a DecodedImage {
348 unsafe { &*self.data }
349 }
350
351 pub fn get_image_callback<'a>(&'a self) -> Option<&'a CoreImageCallback> {
352 if unsafe { self.copies.as_ref().map(|m| m.load(AtomicOrdering::SeqCst)) != Some(1) } {
353 return None; }
355
356 match unsafe { &*self.data } {
357 DecodedImage::Callback(gl_texture_callback) => Some(gl_texture_callback),
358 _ => None,
359 }
360 }
361
362 pub fn get_image_callback_mut<'a>(&'a mut self) -> Option<&'a mut CoreImageCallback> {
363 if unsafe { self.copies.as_ref().map(|m| m.load(AtomicOrdering::SeqCst)) != Some(1) } {
364 return None; }
366
367 match unsafe { &mut *(self.data as *mut DecodedImage) } {
368 DecodedImage::Callback(gl_texture_callback) => Some(gl_texture_callback),
369 _ => None,
370 }
371 }
372
373 pub fn deep_copy(&self) -> Self {
375 let new_data = match self.get_data() {
376 DecodedImage::NullImage {
377 width,
378 height,
379 format,
380 tag,
381 } => DecodedImage::NullImage {
382 width: *width,
383 height: *height,
384 format: *format,
385 tag: tag.clone(),
386 },
387 DecodedImage::Gl(tex) => DecodedImage::NullImage {
391 width: tex.size.width as usize,
392 height: tex.size.height as usize,
393 format: tex.format,
394 tag: Vec::new(),
395 },
396 DecodedImage::Raw((descriptor, data)) => {
399 DecodedImage::Raw((descriptor.clone(), data.clone()))
400 }
401 DecodedImage::Callback(cb) => DecodedImage::Callback(cb.clone()),
402 };
403
404 Self::new(new_data)
405 }
406
407 pub fn is_null_image(&self) -> bool {
408 match self.get_data() {
409 DecodedImage::NullImage { .. } => true,
410 _ => false,
411 }
412 }
413
414 pub fn is_gl_texture(&self) -> bool {
415 match self.get_data() {
416 DecodedImage::Gl(_) => true,
417 _ => false,
418 }
419 }
420
421 pub fn is_raw_image(&self) -> bool {
422 match self.get_data() {
423 DecodedImage::Raw((_, _)) => true,
424 _ => false,
425 }
426 }
427
428 pub fn is_callback(&self) -> bool {
429 match self.get_data() {
430 DecodedImage::Callback(_) => true,
431 _ => false,
432 }
433 }
434
435 pub fn get_rawimage(&self) -> Option<RawImage> {
437 match self.get_data() {
438 DecodedImage::Raw((image_descriptor, image_data)) => Some(RawImage {
439 pixels: match image_data {
440 ImageData::Raw(shared_data) => {
441 let data_clone = shared_data.clone();
444 if let Some(u8vec) = data_clone.into_inner() {
445 RawImageData::U8(u8vec)
446 } else {
447 RawImageData::U8(shared_data.as_ref().to_vec().into())
449 }
450 }
451 ImageData::External(_) => return None,
452 },
453 width: image_descriptor.width,
454 height: image_descriptor.height,
455 premultiplied_alpha: true,
456 data_format: image_descriptor.format,
457 tag: Vec::new().into(),
458 }),
459 _ => None,
460 }
461 }
462
463 pub fn get_bytes(&self) -> Option<&[u8]> {
466 match self.get_data() {
467 DecodedImage::Raw((_, image_data)) => match image_data {
468 ImageData::Raw(shared_data) => Some(shared_data.as_ref()),
469 ImageData::External(_) => None,
470 },
471 _ => None,
472 }
473 }
474
475 pub fn get_bytes_ptr(&self) -> *const u8 {
478 match self.get_data() {
479 DecodedImage::Raw((_, image_data)) => match image_data {
480 ImageData::Raw(shared_data) => shared_data.as_ptr(),
481 ImageData::External(_) => core::ptr::null(),
482 },
483 _ => core::ptr::null(),
484 }
485 }
486
487 pub fn get_size(&self) -> LogicalSize {
489 match self.get_data() {
490 DecodedImage::NullImage { width, height, .. } => {
491 LogicalSize::new(*width as f32, *height as f32)
492 }
493 DecodedImage::Gl(tex) => {
494 LogicalSize::new(tex.size.width as f32, tex.size.height as f32)
495 }
496 DecodedImage::Raw((image_descriptor, _)) => LogicalSize::new(
497 image_descriptor.width as f32,
498 image_descriptor.height as f32,
499 ),
500 DecodedImage::Callback(_) => LogicalSize::new(0.0, 0.0),
501 }
502 }
503
504 pub fn null_image(width: usize, height: usize, format: RawImageFormat, tag: Vec<u8>) -> Self {
505 Self::new(DecodedImage::NullImage {
506 width,
507 height,
508 format,
509 tag,
510 })
511 }
512
513 pub fn callback<C: Into<CoreRenderImageCallback>>(callback: C, data: RefAny) -> Self {
514 Self::new(DecodedImage::Callback(CoreImageCallback {
515 callback: callback.into(),
516 refany: data,
517 }))
518 }
519
520 pub fn new_rawimage(image_data: RawImage) -> Option<Self> {
521 let (image_data, image_descriptor) = image_data.into_loaded_image_source()?;
522 Some(Self::new(DecodedImage::Raw((image_descriptor, image_data))))
523 }
524
525 pub fn new_gltexture(texture: Texture) -> Self {
526 Self::new(DecodedImage::Gl(texture))
527 }
528
529 fn new(data: DecodedImage) -> Self {
530 Self {
531 data: Box::into_raw(Box::new(data)),
532 copies: Box::into_raw(Box::new(AtomicUsize::new(1))),
533 run_destructor: true,
534 }
535 }
536
537 }
539
540unsafe impl Send for ImageRef {}
541unsafe impl Sync for ImageRef {}
542
543impl PartialEq for ImageRef {
544 fn eq(&self, rhs: &Self) -> bool {
545 self.data as usize == rhs.data as usize
546 }
547}
548
549impl PartialOrd for ImageRef {
550 fn partial_cmp(&self, other: &Self) -> Option<::core::cmp::Ordering> {
551 Some((self.data as usize).cmp(&(other.data as usize)))
552 }
553}
554
555impl Ord for ImageRef {
556 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
557 let self_data = self.data as usize;
558 let other_data = other.data as usize;
559 self_data.cmp(&other_data)
560 }
561}
562
563impl Eq for ImageRef {}
564
565impl Hash for ImageRef {
566 fn hash<H>(&self, state: &mut H)
567 where
568 H: Hasher,
569 {
570 let self_data = self.data as usize;
571 self_data.hash(state)
572 }
573}
574
575impl Clone for ImageRef {
576 fn clone(&self) -> Self {
577 unsafe {
578 self.copies
579 .as_ref()
580 .map(|m| m.fetch_add(1, AtomicOrdering::SeqCst));
581 }
582 Self {
583 data: self.data, copies: self.copies, run_destructor: true,
586 }
587 }
588}
589
590impl Drop for ImageRef {
591 fn drop(&mut self) {
592 self.run_destructor = false;
593 unsafe {
594 let copies = unsafe { (*self.copies).fetch_sub(1, AtomicOrdering::SeqCst) };
595 if copies == 1 {
596 let _ = Box::from_raw(self.data as *mut DecodedImage);
597 let _ = Box::from_raw(self.copies as *mut AtomicUsize);
598 }
599 }
600 }
601}
602
603pub fn image_ref_get_hash(ir: &ImageRef) -> ImageRefHash {
604 ImageRefHash {
605 inner: ir.data as usize,
606 }
607}
608
609pub fn image_ref_hash_to_image_key(hash: ImageRefHash, namespace: IdNamespace) -> ImageKey {
613 ImageKey {
614 namespace,
615 key: hash.inner as u32,
616 }
617}
618
619pub fn font_ref_get_hash(fr: &FontRef) -> u64 {
620 fr.get_hash()
621}
622
623#[derive(Debug)]
629pub struct ImageCache {
630 pub image_id_map: FastHashMap<AzString, ImageRef>,
636}
637
638impl Default for ImageCache {
639 fn default() -> Self {
640 Self {
641 image_id_map: FastHashMap::default(),
642 }
643 }
644}
645
646impl ImageCache {
647 pub fn new() -> Self {
648 Self::default()
649 }
650
651 pub fn add_css_image_id(&mut self, css_id: AzString, image: ImageRef) {
654 self.image_id_map.insert(css_id, image);
655 }
656
657 pub fn get_css_image_id(&self, css_id: &AzString) -> Option<&ImageRef> {
658 self.image_id_map.get(css_id)
659 }
660
661 pub fn delete_css_image_id(&mut self, css_id: &AzString) {
662 self.image_id_map.remove(css_id);
663 }
664}
665
666#[derive(Debug, Copy, Clone, PartialEq)]
668pub enum ImageType {
669 Background,
671 Content,
673 ClipMask,
675}
676
677#[derive(Debug, Copy, Clone, PartialEq)]
678pub struct ResolvedImage {
679 pub key: ImageKey,
680 pub descriptor: ImageDescriptor,
681}
682
683#[derive(Debug, Clone, PartialEq, PartialOrd)]
685pub struct TextExclusionArea {
686 pub rect: LogicalRect,
687 pub side: ExclusionSide,
688}
689
690#[derive(Debug, Clone, PartialEq, PartialOrd)]
692pub enum ExclusionSide {
693 Left,
694 Right,
695 Both,
696 None,
697}
698
699pub trait RendererResourcesTrait: core::fmt::Debug {
701 fn get_font_family(
703 &self,
704 style_font_families_hash: &StyleFontFamiliesHash,
705 ) -> Option<&StyleFontFamilyHash>;
706
707 fn get_font_key(&self, style_font_family_hash: &StyleFontFamilyHash) -> Option<&FontKey>;
709
710 fn get_registered_font(
712 &self,
713 font_key: &FontKey,
714 ) -> Option<&(FontRef, FastHashMap<(Au, DpiScaleFactor), FontInstanceKey>)>;
715
716 fn get_image(&self, hash: &ImageRefHash) -> Option<&ResolvedImage>;
718
719 fn update_image(
721 &mut self,
722 image_ref_hash: &ImageRefHash,
723 descriptor: crate::resources::ImageDescriptor,
724 );
725}
726
727impl RendererResourcesTrait for RendererResources {
729 fn get_font_family(
730 &self,
731 style_font_families_hash: &StyleFontFamiliesHash,
732 ) -> Option<&StyleFontFamilyHash> {
733 self.font_families_map.get(style_font_families_hash)
734 }
735
736 fn get_font_key(&self, style_font_family_hash: &StyleFontFamilyHash) -> Option<&FontKey> {
737 self.font_id_map.get(style_font_family_hash)
738 }
739
740 fn get_registered_font(
741 &self,
742 font_key: &FontKey,
743 ) -> Option<&(FontRef, FastHashMap<(Au, DpiScaleFactor), FontInstanceKey>)> {
744 self.currently_registered_fonts.get(font_key)
745 }
746
747 fn get_image(&self, hash: &ImageRefHash) -> Option<&ResolvedImage> {
748 self.currently_registered_images.get(hash)
749 }
750
751 fn update_image(
752 &mut self,
753 image_ref_hash: &ImageRefHash,
754 descriptor: crate::resources::ImageDescriptor,
755 ) {
756 if let Some(s) = self.currently_registered_images.get_mut(image_ref_hash) {
757 s.descriptor = descriptor;
758 }
759 }
760}
761
762pub struct RendererResources {
769 pub currently_registered_images: FastHashMap<ImageRefHash, ResolvedImage>,
771 pub image_key_map: FastHashMap<ImageKey, ImageRefHash>,
773 pub currently_registered_fonts:
775 FastHashMap<FontKey, (FontRef, FastHashMap<(Au, DpiScaleFactor), FontInstanceKey>)>,
776 pub last_frame_registered_fonts:
783 FastHashMap<FontKey, FastHashMap<(Au, DpiScaleFactor), FontInstanceKey>>,
784 pub font_families_map: FastHashMap<StyleFontFamiliesHash, StyleFontFamilyHash>,
789 pub font_id_map: FastHashMap<StyleFontFamilyHash, FontKey>,
791 pub font_hash_map: FastHashMap<u64, FontKey>,
794}
795
796impl fmt::Debug for RendererResources {
797 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
798 write!(
799 f,
800 "RendererResources {{
801 currently_registered_images: {:#?},
802 currently_registered_fonts: {:#?},
803 font_families_map: {:#?},
804 font_id_map: {:#?},
805 }}",
806 self.currently_registered_images.keys().collect::<Vec<_>>(),
807 self.currently_registered_fonts.keys().collect::<Vec<_>>(),
808 self.font_families_map.keys().collect::<Vec<_>>(),
809 self.font_id_map.keys().collect::<Vec<_>>(),
810 )
811 }
812}
813
814impl Default for RendererResources {
815 fn default() -> Self {
816 Self {
817 currently_registered_images: FastHashMap::default(),
818 image_key_map: FastHashMap::default(),
819 currently_registered_fonts: FastHashMap::default(),
820 last_frame_registered_fonts: FastHashMap::default(),
821 font_families_map: FastHashMap::default(),
822 font_id_map: FastHashMap::default(),
823 font_hash_map: FastHashMap::default(),
824 }
825 }
826}
827
828impl RendererResources {
829 pub fn get_renderable_font_data(
830 &self,
831 font_instance_key: &FontInstanceKey,
832 ) -> Option<(&FontRef, Au, DpiScaleFactor)> {
833 self.currently_registered_fonts
834 .iter()
835 .find_map(|(font_key, (font_ref, instances))| {
836 instances.iter().find_map(|((au, dpi), instance_key)| {
837 if *instance_key == *font_instance_key {
838 Some((font_ref, *au, *dpi))
839 } else {
840 None
841 }
842 })
843 })
844 }
845
846 pub fn get_image(&self, hash: &ImageRefHash) -> Option<&ResolvedImage> {
847 self.currently_registered_images.get(hash)
848 }
849
850 pub fn get_font_family(
851 &self,
852 style_font_families_hash: &StyleFontFamiliesHash,
853 ) -> Option<&StyleFontFamilyHash> {
854 self.font_families_map.get(style_font_families_hash)
855 }
856
857 pub fn get_font_key(&self, style_font_family_hash: &StyleFontFamilyHash) -> Option<&FontKey> {
858 self.font_id_map.get(style_font_family_hash)
859 }
860
861 pub fn get_registered_font(
862 &self,
863 font_key: &FontKey,
864 ) -> Option<&(FontRef, FastHashMap<(Au, DpiScaleFactor), FontInstanceKey>)> {
865 self.currently_registered_fonts.get(font_key)
866 }
867
868 pub fn update_image(&mut self, image_ref_hash: &ImageRefHash, descriptor: ImageDescriptor) {
869 if let Some(s) = self.currently_registered_images.get_mut(image_ref_hash) {
870 s.descriptor = descriptor; }
872 }
873
874 pub fn get_font_instance_key_for_text(
875 &self,
876 font_size_px: f32,
877 css_property_cache: &CssPropertyCache,
878 node_data: &NodeData,
879 node_id: &NodeId,
880 styled_node_state: &StyledNodeState,
881 dpi_scale: f32,
882 ) -> Option<FontInstanceKey> {
883 let font_size = StyleFontSize {
885 inner: azul_css::props::basic::PixelValue::const_px(font_size_px as isize),
886 };
887
888 let font_size_au = font_size_to_au(font_size);
890
891 let dpi_scale_factor = DpiScaleFactor {
893 inner: FloatValue::new(dpi_scale),
894 };
895
896 let font_family =
898 css_property_cache.get_font_id_or_default(node_data, node_id, styled_node_state);
899
900 let font_families_hash = StyleFontFamiliesHash::new(font_family.as_ref());
902
903 self.get_font_instance_key(&font_families_hash, font_size_au, dpi_scale_factor)
904 }
905
906 pub fn get_font_instance_key(
907 &self,
908 font_families_hash: &StyleFontFamiliesHash,
909 font_size_au: Au,
910 dpi_scale: DpiScaleFactor,
911 ) -> Option<FontInstanceKey> {
912 let font_family_hash = self.get_font_family(font_families_hash)?;
913 let font_key = self.get_font_key(font_family_hash)?;
914 let (_, instances) = self.get_registered_font(font_key)?;
915 instances.get(&(font_size_au, dpi_scale)).copied()
916 }
917
918 fn remove_font_families_with_zero_references(&mut self) {
920 let font_family_to_delete = self
921 .font_id_map
922 .iter()
923 .filter_map(|(font_family, font_key)| {
924 if !self.currently_registered_fonts.contains_key(font_key) {
925 Some(font_family.clone())
926 } else {
927 None
928 }
929 })
930 .collect::<Vec<_>>();
931
932 for f in font_family_to_delete {
933 self.font_id_map.remove(&f); }
935
936 let font_families_to_delete = self
937 .font_families_map
938 .iter()
939 .filter_map(|(font_families, font_family)| {
940 if !self.font_id_map.contains_key(font_family) {
941 Some(font_families.clone())
942 } else {
943 None
944 }
945 })
946 .collect::<Vec<_>>();
947
948 for f in font_families_to_delete {
949 self.font_families_map.remove(&f); }
951 }
952}
953
954#[derive(Debug, Clone)]
965pub struct UpdateImageResult {
966 pub key_to_update: ImageKey,
967 pub new_descriptor: ImageDescriptor,
968 pub new_image_data: ImageData,
969}
970
971#[derive(Debug, Default)]
972pub struct GlTextureCache {
973 pub solved_textures:
974 BTreeMap<DomId, BTreeMap<NodeId, (ImageKey, ImageDescriptor, ExternalImageId)>>,
975 pub hashes: BTreeMap<(DomId, NodeId, ImageRefHash), ImageRefHash>,
976}
977
978unsafe impl Send for GlTextureCache {}
980
981impl GlTextureCache {
982 pub fn empty() -> Self {
984 Self {
985 solved_textures: BTreeMap::new(),
986 hashes: BTreeMap::new(),
987 }
988 }
989
990 pub fn update_texture(
1009 &mut self,
1010 dom_id: DomId,
1011 node_id: NodeId,
1012 document_id: DocumentId,
1013 epoch: Epoch,
1014 new_texture: Texture,
1015 insert_into_active_gl_textures_fn: &GlStoreImageFn,
1016 ) -> Option<ExternalImageId> {
1017 let new_descriptor = new_texture.get_descriptor();
1018 let di_map = self.solved_textures.get_mut(&dom_id)?;
1019 let entry = di_map.get_mut(&node_id)?;
1020
1021 entry.1 = new_descriptor;
1023
1024 let external_image_id =
1026 (insert_into_active_gl_textures_fn)(document_id, epoch, new_texture);
1027
1028 entry.2 = external_image_id;
1030
1031 Some(external_image_id)
1032 }
1033}
1034
1035macro_rules! unique_id {
1036 ($struct_name:ident, $counter_name:ident) => {
1037 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)]
1038 #[repr(C)]
1039 pub struct $struct_name {
1040 pub id: usize,
1041 }
1042
1043 impl $struct_name {
1044 pub fn unique() -> Self {
1045 Self {
1046 id: $counter_name.fetch_add(1, AtomicOrdering::SeqCst),
1047 }
1048 }
1049 }
1050 };
1051}
1052
1053static PROPERTY_KEY_COUNTER: AtomicUsize = AtomicUsize::new(0);
1055unique_id!(TransformKey, PROPERTY_KEY_COUNTER);
1056unique_id!(ColorKey, PROPERTY_KEY_COUNTER);
1057unique_id!(OpacityKey, PROPERTY_KEY_COUNTER);
1058
1059static IMAGE_ID_COUNTER: AtomicUsize = AtomicUsize::new(0);
1060unique_id!(ImageId, IMAGE_ID_COUNTER);
1061static FONT_ID_COUNTER: AtomicUsize = AtomicUsize::new(0);
1062unique_id!(FontId, FONT_ID_COUNTER);
1063
1064#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1065#[repr(C)]
1066pub struct ImageMask {
1067 pub image: ImageRef,
1068 pub rect: LogicalRect,
1069 pub repeat: bool,
1070}
1071
1072impl_option!(
1073 ImageMask,
1074 OptionImageMask,
1075 copy = false,
1076 [Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash]
1077);
1078
1079#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1080pub enum ImmediateFontId {
1081 Resolved((StyleFontFamilyHash, FontKey)),
1082 Unresolved(StyleFontFamilyVec),
1083}
1084
1085#[derive(Debug, Clone, PartialEq, PartialOrd)]
1086#[repr(C, u8)]
1087pub enum RawImageData {
1088 U8(U8Vec),
1090 U16(U16Vec),
1092 F32(F32Vec),
1094}
1095
1096impl RawImageData {
1097 pub fn get_u8_vec_ref(&self) -> Option<&U8Vec> {
1098 match self {
1099 RawImageData::U8(v) => Some(v),
1100 _ => None,
1101 }
1102 }
1103
1104 pub fn get_u16_vec_ref(&self) -> Option<&U16Vec> {
1105 match self {
1106 RawImageData::U16(v) => Some(v),
1107 _ => None,
1108 }
1109 }
1110
1111 pub fn get_f32_vec_ref(&self) -> Option<&F32Vec> {
1112 match self {
1113 RawImageData::F32(v) => Some(v),
1114 _ => None,
1115 }
1116 }
1117
1118 fn get_u8_vec(self) -> Option<U8Vec> {
1119 match self {
1120 RawImageData::U8(v) => Some(v),
1121 _ => None,
1122 }
1123 }
1124
1125 fn get_u16_vec(self) -> Option<U16Vec> {
1126 match self {
1127 RawImageData::U16(v) => Some(v),
1128 _ => None,
1129 }
1130 }
1131}
1132
1133#[derive(Debug, Clone, PartialEq, PartialOrd)]
1134#[repr(C)]
1135pub struct RawImage {
1136 pub pixels: RawImageData,
1137 pub width: usize,
1138 pub height: usize,
1139 pub premultiplied_alpha: bool,
1140 pub data_format: RawImageFormat,
1141 pub tag: U8Vec,
1142}
1143
1144impl RawImage {
1145 pub fn null_image() -> Self {
1147 Self {
1148 pixels: RawImageData::U8(Vec::new().into()),
1149 width: 0,
1150 height: 0,
1151 premultiplied_alpha: true,
1152 data_format: RawImageFormat::BGRA8,
1153 tag: Vec::new().into(),
1154 }
1155 }
1156
1157 pub fn allocate_mask(size: LayoutSize) -> Self {
1159 Self {
1160 pixels: RawImageData::U8(
1161 vec![0; size.width.max(0) as usize * size.height.max(0) as usize].into(),
1162 ),
1163 width: size.width as usize,
1164 height: size.height as usize,
1165 premultiplied_alpha: true,
1166 data_format: RawImageFormat::R8,
1167 tag: Vec::new().into(),
1168 }
1169 }
1170
1171 pub fn into_loaded_image_source(self) -> Option<(ImageData, ImageDescriptor)> {
1177 #[inline(always)]
1180 fn premultiply_alpha(array: &mut [u8]) {
1181 if array.len() != 4 {
1182 return;
1183 }
1184 let a = u32::from(array[3]);
1185 array[0] = (((array[0] as u32 * a) + 128) / 255) as u8;
1186 array[1] = (((array[1] as u32 * a) + 128) / 255) as u8;
1187 array[2] = (((array[2] as u32 * a) + 128) / 255) as u8;
1188 }
1189
1190 #[inline(always)]
1191 fn normalize_u16(i: u16) -> u8 {
1192 ((core::u16::MAX as f32 / i as f32) * core::u8::MAX as f32) as u8
1193 }
1194
1195 let RawImage {
1196 width,
1197 height,
1198 pixels,
1199 mut data_format,
1200 premultiplied_alpha,
1201 tag,
1202 } = self;
1203
1204 const FOUR_BPP: usize = 4;
1205 const TWO_CHANNELS: usize = 2;
1206 const THREE_CHANNELS: usize = 3;
1207 const FOUR_CHANNELS: usize = 4;
1208
1209 let mut is_opaque = true;
1210
1211 let expected_len = width * height;
1212
1213 let bytes: U8Vec = match data_format {
1214 RawImageFormat::R8 => {
1215 let pixels = pixels.get_u8_vec()?;
1217
1218 if pixels.len() != expected_len {
1219 return None;
1220 }
1221
1222 let pixels_ref = pixels.as_ref();
1223 let mut px = vec![0; pixels_ref.len() * 4];
1224 for (i, r) in pixels_ref.iter().enumerate() {
1225 px[i * 4 + 0] = *r;
1226 px[i * 4 + 1] = *r;
1227 px[i * 4 + 2] = *r;
1228 px[i * 4 + 3] = 0xff;
1229 }
1230
1231 data_format = RawImageFormat::BGRA8;
1232 px.into()
1233 }
1234 RawImageFormat::RG8 => {
1235 let pixels = pixels.get_u8_vec()?;
1236
1237 if pixels.len() != expected_len * TWO_CHANNELS {
1238 return None;
1239 }
1240
1241 let mut px = vec![0; expected_len * FOUR_BPP];
1242
1243 for (pixel_index, greyalpha) in
1246 pixels.as_ref().chunks_exact(TWO_CHANNELS).enumerate()
1247 {
1248 let grey = greyalpha[0];
1249 let alpha = greyalpha[1];
1250
1251 if alpha != 255 {
1252 is_opaque = false;
1253 }
1254
1255 px[pixel_index * FOUR_BPP] = grey;
1256 px[(pixel_index * FOUR_BPP) + 1] = grey;
1257 px[(pixel_index * FOUR_BPP) + 2] = grey;
1258 px[(pixel_index * FOUR_BPP) + 3] = alpha;
1259 }
1260
1261 data_format = RawImageFormat::BGRA8;
1262 px.into()
1263 }
1264 RawImageFormat::RGB8 => {
1265 let pixels = pixels.get_u8_vec()?;
1266
1267 if pixels.len() != expected_len * THREE_CHANNELS {
1268 return None;
1269 }
1270
1271 let mut px = vec![0; expected_len * FOUR_BPP];
1272
1273 for (pixel_index, rgb) in pixels.as_ref().chunks_exact(THREE_CHANNELS).enumerate() {
1275 let red = rgb[0];
1276 let green = rgb[1];
1277 let blue = rgb[2];
1278
1279 px[pixel_index * FOUR_BPP] = blue;
1280 px[(pixel_index * FOUR_BPP) + 1] = green;
1281 px[(pixel_index * FOUR_BPP) + 2] = red;
1282 px[(pixel_index * FOUR_BPP) + 3] = 0xff;
1283 }
1284
1285 data_format = RawImageFormat::BGRA8;
1286 px.into()
1287 }
1288 RawImageFormat::RGBA8 => {
1289 let mut pixels: Vec<u8> = pixels.get_u8_vec()?.into_library_owned_vec();
1290
1291 if pixels.len() != expected_len * FOUR_CHANNELS {
1292 return None;
1293 }
1294
1295 if premultiplied_alpha {
1298 for rgba in pixels.chunks_exact_mut(4) {
1299 let (r, gba) = rgba.split_first_mut()?;
1300 core::mem::swap(r, gba.get_mut(1)?);
1301 let a = rgba.get_mut(3)?;
1302 if *a != 255 {
1303 is_opaque = false;
1304 }
1305 }
1306 } else {
1307 for rgba in pixels.chunks_exact_mut(4) {
1308 let (r, gba) = rgba.split_first_mut()?;
1310 core::mem::swap(r, gba.get_mut(1)?);
1311 let a = rgba.get_mut(3)?;
1312 if *a != 255 {
1313 is_opaque = false;
1314 }
1315 premultiply_alpha(rgba); }
1317 }
1318
1319 data_format = RawImageFormat::BGRA8;
1320 pixels.into()
1321 }
1322 RawImageFormat::R16 => {
1323 let pixels = pixels.get_u16_vec()?;
1324
1325 if pixels.len() != expected_len {
1326 return None;
1327 }
1328
1329 let mut px = vec![0; expected_len * FOUR_BPP];
1330
1331 for (pixel_index, grey_u16) in pixels.as_ref().iter().enumerate() {
1333 let grey_u8 = normalize_u16(*grey_u16);
1334 px[pixel_index * FOUR_BPP] = grey_u8;
1335 px[(pixel_index * FOUR_BPP) + 1] = grey_u8;
1336 px[(pixel_index * FOUR_BPP) + 2] = grey_u8;
1337 px[(pixel_index * FOUR_BPP) + 3] = 0xff;
1338 }
1339
1340 data_format = RawImageFormat::BGRA8;
1341 px.into()
1342 }
1343 RawImageFormat::RG16 => {
1344 let pixels = pixels.get_u16_vec()?;
1345
1346 if pixels.len() != expected_len * TWO_CHANNELS {
1347 return None;
1348 }
1349
1350 let mut px = vec![0; expected_len * FOUR_BPP];
1351
1352 for (pixel_index, greyalpha) in
1354 pixels.as_ref().chunks_exact(TWO_CHANNELS).enumerate()
1355 {
1356 let grey_u8 = normalize_u16(greyalpha[0]);
1357 let alpha_u8 = normalize_u16(greyalpha[1]);
1358
1359 if alpha_u8 != 255 {
1360 is_opaque = false;
1361 }
1362
1363 px[pixel_index * FOUR_BPP] = grey_u8;
1364 px[(pixel_index * FOUR_BPP) + 1] = grey_u8;
1365 px[(pixel_index * FOUR_BPP) + 2] = grey_u8;
1366 px[(pixel_index * FOUR_BPP) + 3] = alpha_u8;
1367 }
1368
1369 data_format = RawImageFormat::BGRA8;
1370 px.into()
1371 }
1372 RawImageFormat::RGB16 => {
1373 let pixels = pixels.get_u16_vec()?;
1374
1375 if pixels.len() != expected_len * THREE_CHANNELS {
1376 return None;
1377 }
1378
1379 let mut px = vec![0; expected_len * FOUR_BPP];
1380
1381 for (pixel_index, rgb) in pixels.as_ref().chunks_exact(THREE_CHANNELS).enumerate() {
1383 let red_u8 = normalize_u16(rgb[0]);
1384 let green_u8 = normalize_u16(rgb[1]);
1385 let blue_u8 = normalize_u16(rgb[2]);
1386
1387 px[pixel_index * FOUR_BPP] = blue_u8;
1388 px[(pixel_index * FOUR_BPP) + 1] = green_u8;
1389 px[(pixel_index * FOUR_BPP) + 2] = red_u8;
1390 px[(pixel_index * FOUR_BPP) + 3] = 0xff;
1391 }
1392
1393 data_format = RawImageFormat::BGRA8;
1394 px.into()
1395 }
1396 RawImageFormat::RGBA16 => {
1397 let pixels = pixels.get_u16_vec()?;
1398
1399 if pixels.len() != expected_len * FOUR_CHANNELS {
1400 return None;
1401 }
1402
1403 let mut px = vec![0; expected_len * FOUR_BPP];
1404
1405 if premultiplied_alpha {
1407 for (pixel_index, rgba) in
1408 pixels.as_ref().chunks_exact(FOUR_CHANNELS).enumerate()
1409 {
1410 let red_u8 = normalize_u16(rgba[0]);
1411 let green_u8 = normalize_u16(rgba[1]);
1412 let blue_u8 = normalize_u16(rgba[2]);
1413 let alpha_u8 = normalize_u16(rgba[3]);
1414
1415 if alpha_u8 != 255 {
1416 is_opaque = false;
1417 }
1418
1419 px[pixel_index * FOUR_BPP] = blue_u8;
1420 px[(pixel_index * FOUR_BPP) + 1] = green_u8;
1421 px[(pixel_index * FOUR_BPP) + 2] = red_u8;
1422 px[(pixel_index * FOUR_BPP) + 3] = alpha_u8;
1423 }
1424 } else {
1425 for (pixel_index, rgba) in
1426 pixels.as_ref().chunks_exact(FOUR_CHANNELS).enumerate()
1427 {
1428 let red_u8 = normalize_u16(rgba[0]);
1429 let green_u8 = normalize_u16(rgba[1]);
1430 let blue_u8 = normalize_u16(rgba[2]);
1431 let alpha_u8 = normalize_u16(rgba[3]);
1432
1433 if alpha_u8 != 255 {
1434 is_opaque = false;
1435 }
1436
1437 px[pixel_index * FOUR_BPP] = blue_u8;
1438 px[(pixel_index * FOUR_BPP) + 1] = green_u8;
1439 px[(pixel_index * FOUR_BPP) + 2] = red_u8;
1440 px[(pixel_index * FOUR_BPP) + 3] = alpha_u8;
1441 premultiply_alpha(
1442 &mut px
1443 [(pixel_index * FOUR_BPP)..((pixel_index * FOUR_BPP) + FOUR_BPP)],
1444 );
1445 }
1446 }
1447
1448 data_format = RawImageFormat::BGRA8;
1449 px.into()
1450 }
1451 RawImageFormat::BGR8 => {
1452 let pixels = pixels.get_u8_vec()?;
1453
1454 if pixels.len() != expected_len * THREE_CHANNELS {
1455 return None;
1456 }
1457
1458 let mut px = vec![0; expected_len * FOUR_BPP];
1459
1460 for (pixel_index, bgr) in pixels.as_ref().chunks_exact(THREE_CHANNELS).enumerate() {
1462 let blue = bgr[0];
1463 let green = bgr[1];
1464 let red = bgr[2];
1465
1466 px[pixel_index * FOUR_BPP] = blue;
1467 px[(pixel_index * FOUR_BPP) + 1] = green;
1468 px[(pixel_index * FOUR_BPP) + 2] = red;
1469 px[(pixel_index * FOUR_BPP) + 3] = 0xff;
1470 }
1471
1472 data_format = RawImageFormat::BGRA8;
1473 px.into()
1474 }
1475 RawImageFormat::BGRA8 => {
1476 if premultiplied_alpha {
1477 let pixels = pixels.get_u8_vec()?;
1479
1480 is_opaque = pixels
1481 .as_ref()
1482 .chunks_exact(FOUR_CHANNELS)
1483 .all(|bgra| bgra[3] == 255);
1484
1485 pixels
1486 } else {
1487 let mut pixels: Vec<u8> = pixels.get_u8_vec()?.into_library_owned_vec();
1488
1489 if pixels.len() != expected_len * FOUR_BPP {
1490 return None;
1491 }
1492
1493 for bgra in pixels.chunks_exact_mut(FOUR_CHANNELS) {
1494 if bgra[3] != 255 {
1495 is_opaque = false;
1496 }
1497 premultiply_alpha(bgra);
1498 }
1499 data_format = RawImageFormat::BGRA8;
1500 pixels.into()
1501 }
1502 }
1503 RawImageFormat::RGBF32 => {
1504 let pixels = pixels.get_f32_vec_ref()?;
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_u8 = (rgb[0] * 255.0) as u8;
1515 let green_u8 = (rgb[1] * 255.0) as u8;
1516 let blue_u8 = (rgb[2] * 255.0) as u8;
1517
1518 px[pixel_index * FOUR_BPP] = blue_u8;
1519 px[(pixel_index * FOUR_BPP) + 1] = green_u8;
1520 px[(pixel_index * FOUR_BPP) + 2] = red_u8;
1521 px[(pixel_index * FOUR_BPP) + 3] = 0xff;
1522 }
1523
1524 data_format = RawImageFormat::BGRA8;
1525 px.into()
1526 }
1527 RawImageFormat::RGBAF32 => {
1528 let pixels = pixels.get_f32_vec_ref()?;
1529
1530 if pixels.len() != expected_len * FOUR_CHANNELS {
1531 return None;
1532 }
1533
1534 let mut px = vec![0; expected_len * FOUR_BPP];
1535
1536 if premultiplied_alpha {
1538 for (pixel_index, rgba) in
1539 pixels.as_ref().chunks_exact(FOUR_CHANNELS).enumerate()
1540 {
1541 let red_u8 = (rgba[0] * 255.0) as u8;
1542 let green_u8 = (rgba[1] * 255.0) as u8;
1543 let blue_u8 = (rgba[2] * 255.0) as u8;
1544 let alpha_u8 = (rgba[3] * 255.0) as u8;
1545
1546 if alpha_u8 != 255 {
1547 is_opaque = false;
1548 }
1549
1550 px[pixel_index * FOUR_BPP] = blue_u8;
1551 px[(pixel_index * FOUR_BPP) + 1] = green_u8;
1552 px[(pixel_index * FOUR_BPP) + 2] = red_u8;
1553 px[(pixel_index * FOUR_BPP) + 3] = alpha_u8;
1554 }
1555 } else {
1556 for (pixel_index, rgba) in
1557 pixels.as_ref().chunks_exact(FOUR_CHANNELS).enumerate()
1558 {
1559 let red_u8 = (rgba[0] * 255.0) as u8;
1560 let green_u8 = (rgba[1] * 255.0) as u8;
1561 let blue_u8 = (rgba[2] * 255.0) as u8;
1562 let alpha_u8 = (rgba[3] * 255.0) as u8;
1563
1564 if alpha_u8 != 255 {
1565 is_opaque = false;
1566 }
1567
1568 px[pixel_index * FOUR_BPP] = blue_u8;
1569 px[(pixel_index * FOUR_BPP) + 1] = green_u8;
1570 px[(pixel_index * FOUR_BPP) + 2] = red_u8;
1571 px[(pixel_index * FOUR_BPP) + 3] = alpha_u8;
1572 premultiply_alpha(
1573 &mut px
1574 [(pixel_index * FOUR_BPP)..((pixel_index * FOUR_BPP) + FOUR_BPP)],
1575 );
1576 }
1577 }
1578
1579 data_format = RawImageFormat::BGRA8;
1580 px.into()
1581 }
1582 };
1583
1584 let image_data = ImageData::Raw(SharedRawImageData::new(bytes));
1585 let image_descriptor = ImageDescriptor {
1586 format: data_format,
1587 width,
1588 height,
1589 offset: 0,
1590 stride: None.into(),
1591 flags: ImageDescriptorFlags {
1592 is_opaque,
1593 allow_mipmaps: true,
1594 },
1595 };
1596
1597 Some((image_data, image_descriptor))
1598 }
1599}
1600
1601impl_option!(
1602 RawImage,
1603 OptionRawImage,
1604 copy = false,
1605 [Debug, Clone, PartialEq, PartialOrd]
1606);
1607
1608pub fn font_size_to_au(font_size: StyleFontSize) -> Au {
1609 Au::from_px(font_size.inner.to_pixels_internal(0.0, DEFAULT_FONT_SIZE))
1610}
1611
1612pub type FontInstanceFlags = u32;
1613
1614pub const FONT_INSTANCE_FLAG_SYNTHETIC_BOLD: u32 = 1 << 1;
1616pub const FONT_INSTANCE_FLAG_EMBEDDED_BITMAPS: u32 = 1 << 2;
1617pub const FONT_INSTANCE_FLAG_SUBPIXEL_BGR: u32 = 1 << 3;
1618pub const FONT_INSTANCE_FLAG_TRANSPOSE: u32 = 1 << 4;
1619pub const FONT_INSTANCE_FLAG_FLIP_X: u32 = 1 << 5;
1620pub const FONT_INSTANCE_FLAG_FLIP_Y: u32 = 1 << 6;
1621pub const FONT_INSTANCE_FLAG_SUBPIXEL_POSITION: u32 = 1 << 7;
1622
1623pub const FONT_INSTANCE_FLAG_FORCE_GDI: u32 = 1 << 16;
1625
1626pub const FONT_INSTANCE_FLAG_FONT_SMOOTHING: u32 = 1 << 16;
1628
1629pub const FONT_INSTANCE_FLAG_FORCE_AUTOHINT: u32 = 1 << 16;
1631pub const FONT_INSTANCE_FLAG_NO_AUTOHINT: u32 = 1 << 17;
1632pub const FONT_INSTANCE_FLAG_VERTICAL_LAYOUT: u32 = 1 << 18;
1633pub const FONT_INSTANCE_FLAG_LCD_VERTICAL: u32 = 1 << 19;
1634
1635#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
1636pub struct GlyphOptions {
1637 pub render_mode: FontRenderMode,
1638 pub flags: FontInstanceFlags,
1639}
1640
1641#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
1642pub enum FontRenderMode {
1643 Mono,
1644 Alpha,
1645 Subpixel,
1646}
1647
1648#[cfg(target_arch = "wasm32")]
1649#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
1650pub struct FontInstancePlatformOptions {
1651 }
1653
1654#[cfg(target_os = "windows")]
1655#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
1656pub struct FontInstancePlatformOptions {
1657 pub gamma: u16,
1658 pub contrast: u8,
1659 pub cleartype_level: u8,
1660}
1661
1662#[cfg(target_os = "macos")]
1663#[derive(Default, Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
1664pub struct FontInstancePlatformOptions {
1665 pub unused: u32,
1666}
1667
1668#[cfg(target_os = "linux")]
1669#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
1670pub struct FontInstancePlatformOptions {
1671 pub lcd_filter: FontLCDFilter,
1672 pub hinting: FontHinting,
1673}
1674
1675#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
1676pub enum FontHinting {
1677 None,
1678 Mono,
1679 Light,
1680 Normal,
1681 LCD,
1682}
1683
1684#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
1685pub enum FontLCDFilter {
1686 None,
1687 Default,
1688 Light,
1689 Legacy,
1690}
1691
1692impl Default for FontLCDFilter {
1693 fn default() -> Self {
1694 FontLCDFilter::Default
1695 }
1696}
1697
1698#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
1699pub struct FontInstanceOptions {
1700 pub render_mode: FontRenderMode,
1701 pub flags: FontInstanceFlags,
1702 pub bg_color: ColorU,
1703 pub synthetic_italics: SyntheticItalics,
1707}
1708
1709impl Default for FontInstanceOptions {
1710 fn default() -> FontInstanceOptions {
1711 FontInstanceOptions {
1712 render_mode: FontRenderMode::Subpixel,
1713 flags: 0,
1714 bg_color: ColorU::TRANSPARENT,
1715 synthetic_italics: SyntheticItalics::default(),
1716 }
1717 }
1718}
1719
1720#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
1721pub struct SyntheticItalics {
1722 pub angle: i16,
1723}
1724
1725impl Default for SyntheticItalics {
1726 fn default() -> Self {
1727 Self { angle: 0 }
1728 }
1729}
1730
1731#[derive(Debug)]
1737#[repr(C)]
1738pub struct SharedRawImageData {
1739 pub data: *const U8Vec,
1741 pub copies: *const AtomicUsize,
1743 pub run_destructor: bool,
1745}
1746
1747impl SharedRawImageData {
1748 pub fn new(data: U8Vec) -> Self {
1750 Self {
1751 data: Box::into_raw(Box::new(data)),
1752 copies: Box::into_raw(Box::new(AtomicUsize::new(1))),
1753 run_destructor: true,
1754 }
1755 }
1756
1757 pub fn as_ref(&self) -> &[u8] {
1759 unsafe { (*self.data).as_ref() }
1760 }
1761
1762 pub fn get_bytes(&self) -> &[u8] {
1764 self.as_ref()
1765 }
1766
1767 pub fn as_ptr(&self) -> *const u8 {
1769 unsafe { (*self.data).as_ref().as_ptr() }
1770 }
1771
1772 pub fn len(&self) -> usize {
1774 unsafe { (*self.data).len() }
1775 }
1776
1777 pub fn is_empty(&self) -> bool {
1779 self.len() == 0
1780 }
1781
1782 pub fn into_inner(self) -> Option<U8Vec> {
1785 unsafe {
1786 if self.copies.as_ref().map(|m| m.load(AtomicOrdering::SeqCst)) == Some(1) {
1787 let data = Box::from_raw(self.data as *mut U8Vec);
1788 let _ = Box::from_raw(self.copies as *mut AtomicUsize);
1789 core::mem::forget(self); Some(*data)
1791 } else {
1792 None
1793 }
1794 }
1795 }
1796}
1797
1798unsafe impl Send for SharedRawImageData {}
1799unsafe impl Sync for SharedRawImageData {}
1800
1801impl Clone for SharedRawImageData {
1802 fn clone(&self) -> Self {
1803 unsafe {
1804 self.copies
1805 .as_ref()
1806 .map(|m| m.fetch_add(1, AtomicOrdering::SeqCst));
1807 }
1808 Self {
1809 data: self.data,
1810 copies: self.copies,
1811 run_destructor: true,
1812 }
1813 }
1814}
1815
1816impl Drop for SharedRawImageData {
1817 fn drop(&mut self) {
1818 self.run_destructor = false;
1819 unsafe {
1820 let copies = (*self.copies).fetch_sub(1, AtomicOrdering::SeqCst);
1821 if copies == 1 {
1822 let _ = Box::from_raw(self.data as *mut U8Vec);
1823 let _ = Box::from_raw(self.copies as *mut AtomicUsize);
1824 }
1825 }
1826 }
1827}
1828
1829impl PartialEq for SharedRawImageData {
1830 fn eq(&self, rhs: &Self) -> bool {
1831 self.data as usize == rhs.data as usize
1832 }
1833}
1834
1835impl Eq for SharedRawImageData {}
1836
1837impl PartialOrd for SharedRawImageData {
1838 fn partial_cmp(&self, other: &Self) -> Option<::core::cmp::Ordering> {
1839 Some(self.cmp(other))
1840 }
1841}
1842
1843impl Ord for SharedRawImageData {
1844 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
1845 (self.data as usize).cmp(&(other.data as usize))
1846 }
1847}
1848
1849impl Hash for SharedRawImageData {
1850 fn hash<H>(&self, state: &mut H)
1851 where
1852 H: Hasher,
1853 {
1854 (self.data as usize).hash(state)
1855 }
1856}
1857
1858#[derive(Debug, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
1861#[repr(C, u8)]
1862pub enum ImageData {
1863 Raw(SharedRawImageData),
1866 External(ExternalImageData),
1869}
1870
1871#[derive(Debug, Copy, Clone, Eq, Hash, PartialEq, PartialOrd, Ord)]
1873#[repr(C, u8)]
1874pub enum ExternalImageType {
1875 TextureHandle(ImageBufferKind),
1877 Buffer,
1879}
1880
1881#[repr(C)]
1885#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, PartialOrd, Ord)]
1886pub struct ExternalImageId {
1887 pub inner: u64,
1888}
1889
1890static LAST_EXTERNAL_IMAGE_ID: AtomicUsize = AtomicUsize::new(0);
1891
1892impl ExternalImageId {
1893 pub fn new() -> Self {
1895 Self {
1896 inner: LAST_EXTERNAL_IMAGE_ID.fetch_add(1, AtomicOrdering::SeqCst) as u64,
1897 }
1898 }
1899}
1900
1901#[derive(Debug, Clone, PartialEq, PartialOrd)]
1902#[repr(C, u8)]
1903pub enum GlyphOutlineOperation {
1904 MoveTo(OutlineMoveTo),
1905 LineTo(OutlineLineTo),
1906 QuadraticCurveTo(OutlineQuadTo),
1907 CubicCurveTo(OutlineCubicTo),
1908 ClosePath,
1909}
1910
1911#[derive(Debug, Clone, PartialEq, PartialOrd)]
1913#[repr(C)]
1914pub struct OutlineMoveTo {
1915 pub x: i16,
1916 pub y: i16,
1917}
1918
1919#[derive(Debug, Clone, PartialEq, PartialOrd)]
1921#[repr(C)]
1922pub struct OutlineLineTo {
1923 pub x: i16,
1924 pub y: i16,
1925}
1926
1927#[derive(Debug, Clone, PartialEq, PartialOrd)]
1929#[repr(C)]
1930pub struct OutlineQuadTo {
1931 pub ctrl_1_x: i16,
1932 pub ctrl_1_y: i16,
1933 pub end_x: i16,
1934 pub end_y: i16,
1935}
1936
1937#[derive(Debug, Clone, PartialEq, PartialOrd)]
1939#[repr(C)]
1940pub struct OutlineCubicTo {
1941 pub ctrl_1_x: i16,
1942 pub ctrl_1_y: i16,
1943 pub ctrl_2_x: i16,
1944 pub ctrl_2_y: i16,
1945 pub end_x: i16,
1946 pub end_y: i16,
1947}
1948
1949#[derive(Debug, Clone, PartialEq, PartialOrd)]
1950#[repr(C)]
1951pub struct GlyphOutline {
1952 pub operations: GlyphOutlineOperationVec,
1953}
1954
1955azul_css::impl_vec!(
1956 GlyphOutlineOperation,
1957 GlyphOutlineOperationVec,
1958 GlyphOutlineOperationVecDestructor,
1959 GlyphOutlineOperationVecDestructorType
1960);
1961azul_css::impl_vec_clone!(
1962 GlyphOutlineOperation,
1963 GlyphOutlineOperationVec,
1964 GlyphOutlineOperationVecDestructor
1965);
1966azul_css::impl_vec_debug!(GlyphOutlineOperation, GlyphOutlineOperationVec);
1967azul_css::impl_vec_partialord!(GlyphOutlineOperation, GlyphOutlineOperationVec);
1968azul_css::impl_vec_partialeq!(GlyphOutlineOperation, GlyphOutlineOperationVec);
1969
1970#[derive(Debug, Clone)]
1971#[repr(C)]
1972pub struct OwnedGlyphBoundingBox {
1973 pub max_x: i16,
1974 pub max_y: i16,
1975 pub min_x: i16,
1976 pub min_y: i16,
1977}
1978
1979#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
1981#[repr(C)]
1982pub enum ImageBufferKind {
1983 Texture2D = 0,
1985 TextureRect = 1,
1992 TextureExternal = 2,
1997}
1998
1999#[repr(C)]
2001#[derive(Debug, Clone, Eq, Hash, PartialEq, PartialOrd, Ord)]
2002pub struct ExternalImageData {
2003 pub id: ExternalImageId,
2005 pub channel_index: u8,
2008 pub image_type: ExternalImageType,
2010}
2011
2012pub type TileSize = u16;
2013
2014#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
2015pub enum ImageDirtyRect {
2016 All,
2017 Partial(LayoutRect),
2018}
2019
2020#[derive(Debug, Clone, PartialEq, PartialOrd)]
2021pub enum ResourceUpdate {
2022 AddFont(AddFont),
2023 DeleteFont(FontKey),
2024 AddFontInstance(AddFontInstance),
2025 DeleteFontInstance(FontInstanceKey),
2026 AddImage(AddImage),
2027 UpdateImage(UpdateImage),
2028 DeleteImage(ImageKey),
2029}
2030
2031#[derive(Debug, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
2032pub struct AddImage {
2033 pub key: ImageKey,
2034 pub descriptor: ImageDescriptor,
2035 pub data: ImageData,
2036 pub tiling: Option<TileSize>,
2037}
2038
2039#[derive(Debug, Clone, PartialEq, PartialOrd)]
2040pub struct UpdateImage {
2041 pub key: ImageKey,
2042 pub descriptor: ImageDescriptor,
2043 pub data: ImageData,
2044 pub dirty_rect: ImageDirtyRect,
2045}
2046
2047#[derive(Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
2050pub struct AddFont {
2051 pub key: FontKey,
2052 pub font: azul_css::props::basic::FontRef,
2053}
2054
2055impl fmt::Debug for AddFont {
2056 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2057 write!(
2058 f,
2059 "AddFont {{ key: {:?}, font: {:?} }}",
2060 self.key, self.font
2061 )
2062 }
2063}
2064
2065#[derive(Debug, Clone, PartialEq, PartialOrd)]
2066pub struct AddFontInstance {
2067 pub key: FontInstanceKey,
2068 pub font_key: FontKey,
2069 pub glyph_size: (Au, DpiScaleFactor),
2070 pub options: Option<FontInstanceOptions>,
2071 pub platform_options: Option<FontInstancePlatformOptions>,
2072 pub variations: Vec<FontVariation>,
2073}
2074
2075#[repr(C)]
2076#[derive(Clone, Copy, Debug, PartialOrd, PartialEq)]
2077pub struct FontVariation {
2078 pub tag: u32,
2079 pub value: f32,
2080}
2081
2082#[repr(C)]
2083#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
2084pub struct Epoch {
2085 inner: u32,
2086}
2087
2088impl fmt::Display for Epoch {
2089 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2090 write!(f, "{}", self.inner)
2091 }
2092}
2093
2094impl Epoch {
2095 pub const fn new() -> Self {
2099 Self { inner: 0 }
2100 }
2101 pub const fn from(i: u32) -> Self {
2102 Self { inner: i }
2103 }
2104 pub const fn into_u32(&self) -> u32 {
2105 self.inner
2106 }
2107
2108 pub fn increment(&mut self) {
2111 use core::u32;
2112 const MAX_ID: u32 = u32::MAX - 1;
2113 *self = match self.inner {
2114 MAX_ID => Epoch { inner: 0 },
2115 other => Epoch {
2116 inner: other.saturating_add(1),
2117 },
2118 };
2119 }
2120}
2121
2122#[derive(Debug, Clone, Copy, Hash, PartialEq, PartialOrd, Eq, Ord)]
2124pub struct Au(pub i32);
2125
2126pub const AU_PER_PX: i32 = 60;
2127pub const MAX_AU: i32 = (1 << 30) - 1;
2128pub const MIN_AU: i32 = -(1 << 30) - 1;
2129
2130impl Au {
2131 pub fn from_px(px: f32) -> Self {
2132 let target_app_units = (px * AU_PER_PX as f32) as i32;
2133 Au(target_app_units.min(MAX_AU).max(MIN_AU))
2134 }
2135 pub fn into_px(&self) -> f32 {
2136 self.0 as f32 / AU_PER_PX as f32
2137 }
2138}
2139
2140#[derive(Debug)]
2142pub enum AddFontMsg {
2143 Font(FontKey, StyleFontFamilyHash, FontRef),
2145 Instance(AddFontInstance, (Au, DpiScaleFactor)),
2146}
2147
2148impl AddFontMsg {
2149 pub fn into_resource_update(&self) -> ResourceUpdate {
2150 use self::AddFontMsg::*;
2151 match self {
2152 Font(font_key, _, font_ref) => ResourceUpdate::AddFont(AddFont {
2153 key: *font_key,
2154 font: font_ref.clone(),
2155 }),
2156 Instance(fi, _) => ResourceUpdate::AddFontInstance(fi.clone()),
2157 }
2158 }
2159}
2160
2161#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
2162pub enum DeleteFontMsg {
2163 Font(FontKey),
2164 Instance(FontInstanceKey, (Au, DpiScaleFactor)),
2165}
2166
2167impl DeleteFontMsg {
2168 pub fn into_resource_update(&self) -> ResourceUpdate {
2169 use self::DeleteFontMsg::*;
2170 match self {
2171 Font(f) => ResourceUpdate::DeleteFont(*f),
2172 Instance(fi, _) => ResourceUpdate::DeleteFontInstance(*fi),
2173 }
2174 }
2175}
2176
2177#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
2178pub struct AddImageMsg(pub AddImage);
2179
2180impl AddImageMsg {
2181 pub fn into_resource_update(&self) -> ResourceUpdate {
2182 ResourceUpdate::AddImage(self.0.clone())
2183 }
2184}
2185
2186#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
2187pub struct DeleteImageMsg(ImageKey);
2188
2189impl DeleteImageMsg {
2190 pub fn into_resource_update(&self) -> ResourceUpdate {
2191 ResourceUpdate::DeleteImage(self.0.clone())
2192 }
2193}
2194
2195#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2196#[repr(C)]
2197pub struct LoadedFontSource {
2198 pub data: U8Vec,
2199 pub index: u32,
2200 pub load_outlines: bool,
2201}
2202
2203pub type LoadFontFn = fn(&StyleFontFamily, &FcFontCache) -> Option<LoadedFontSource>;
2205
2206pub type ParseFontFn = fn(LoadedFontSource) -> Option<FontRef>; pub type GlStoreImageFn = fn(DocumentId, Epoch, Texture) -> ExternalImageId;
2210
2211pub fn build_add_font_resource_updates(
2220 renderer_resources: &mut RendererResources,
2221 dpi: DpiScaleFactor,
2222 fc_cache: &FcFontCache,
2223 id_namespace: IdNamespace,
2224 fonts_in_dom: &FastHashMap<ImmediateFontId, FastBTreeSet<Au>>,
2225 font_source_load_fn: LoadFontFn,
2226 parse_font_fn: ParseFontFn,
2227) -> Vec<(StyleFontFamilyHash, AddFontMsg)> {
2228 let mut resource_updates = alloc::vec::Vec::new();
2229 let mut font_instances_added_this_frame = FastBTreeSet::new();
2230
2231 'outer: for (im_font_id, font_sizes) in fonts_in_dom {
2232 macro_rules! insert_font_instances {
2233 ($font_family_hash:expr, $font_key:expr, $font_size:expr) => {{
2234 let font_instance_key_exists = renderer_resources
2235 .currently_registered_fonts
2236 .get(&$font_key)
2237 .and_then(|(_, font_instances)| font_instances.get(&($font_size, dpi)))
2238 .is_some()
2239 || font_instances_added_this_frame.contains(&($font_key, ($font_size, dpi)));
2240
2241 if !font_instance_key_exists {
2242 let font_instance_key = FontInstanceKey::unique(id_namespace);
2243
2244 #[cfg(target_os = "windows")]
2246 let platform_options = FontInstancePlatformOptions {
2247 gamma: 300,
2248 contrast: 100,
2249 cleartype_level: 100,
2250 };
2251
2252 #[cfg(target_os = "linux")]
2253 let platform_options = FontInstancePlatformOptions {
2254 lcd_filter: FontLCDFilter::Default,
2255 hinting: FontHinting::Normal,
2256 };
2257
2258 #[cfg(target_os = "macos")]
2259 let platform_options = FontInstancePlatformOptions::default();
2260
2261 #[cfg(target_arch = "wasm32")]
2262 let platform_options = FontInstancePlatformOptions::default();
2263
2264 let options = FontInstanceOptions {
2265 render_mode: FontRenderMode::Subpixel,
2266 flags: 0 | FONT_INSTANCE_FLAG_NO_AUTOHINT,
2267 ..Default::default()
2268 };
2269
2270 font_instances_added_this_frame.insert(($font_key, ($font_size, dpi)));
2271 resource_updates.push((
2272 $font_family_hash,
2273 AddFontMsg::Instance(
2274 AddFontInstance {
2275 key: font_instance_key,
2276 font_key: $font_key,
2277 glyph_size: ($font_size, dpi),
2278 options: Some(options),
2279 platform_options: Some(platform_options),
2280 variations: alloc::vec::Vec::new(),
2281 },
2282 ($font_size, dpi),
2283 ),
2284 ));
2285 }
2286 }};
2287 }
2288
2289 match im_font_id {
2290 ImmediateFontId::Resolved((font_family_hash, font_id)) => {
2291 for font_size in font_sizes.iter() {
2294 insert_font_instances!(*font_family_hash, *font_id, *font_size);
2295 }
2296 }
2297 ImmediateFontId::Unresolved(style_font_families) => {
2298 let mut font_family_hash = None;
2308 let font_families_hash = StyleFontFamiliesHash::new(style_font_families.as_ref());
2309
2310 'inner: for family in style_font_families.as_ref().iter() {
2312 let current_family_hash = StyleFontFamilyHash::new(&family);
2313
2314 if let Some(font_id) = renderer_resources.font_id_map.get(¤t_family_hash)
2315 {
2316 for font_size in font_sizes {
2318 insert_font_instances!(current_family_hash, *font_id, *font_size);
2319 }
2320 continue 'outer;
2321 }
2322
2323 let font_ref = match family {
2324 StyleFontFamily::Ref(r) => r.clone(), other => {
2326 let font_data = match (font_source_load_fn)(&other, fc_cache) {
2328 Some(s) => s,
2329 None => continue 'inner,
2330 };
2331
2332 let font_ref = match (parse_font_fn)(font_data) {
2333 Some(s) => s,
2334 None => continue 'inner,
2335 };
2336
2337 font_ref
2338 }
2339 };
2340
2341 font_family_hash = Some((current_family_hash, font_ref));
2343 break 'inner;
2344 }
2345
2346 let (font_family_hash, font_ref) = match font_family_hash {
2347 None => continue 'outer, Some(s) => s,
2349 };
2350
2351 let font_key = FontKey::unique(id_namespace);
2353 let add_font_msg = AddFontMsg::Font(font_key, font_family_hash, font_ref);
2354
2355 renderer_resources
2356 .font_id_map
2357 .insert(font_family_hash, font_key);
2358 renderer_resources
2359 .font_families_map
2360 .insert(font_families_hash, font_family_hash);
2361 resource_updates.push((font_family_hash, add_font_msg));
2362
2363 for font_size in font_sizes {
2365 insert_font_instances!(font_family_hash, font_key, *font_size);
2366 }
2367 }
2368 }
2369 }
2370
2371 resource_updates
2372}
2373
2374#[allow(unused_variables)]
2390pub fn build_add_image_resource_updates(
2391 renderer_resources: &RendererResources,
2392 id_namespace: IdNamespace,
2393 epoch: Epoch,
2394 document_id: &DocumentId,
2395 images_in_dom: &FastBTreeSet<ImageRef>,
2396 insert_into_active_gl_textures: GlStoreImageFn,
2397) -> Vec<(ImageRefHash, AddImageMsg)> {
2398 images_in_dom
2399 .iter()
2400 .filter_map(|image_ref| {
2401 let image_ref_hash = image_ref_get_hash(&image_ref);
2402
2403 if renderer_resources
2404 .currently_registered_images
2405 .contains_key(&image_ref_hash)
2406 {
2407 return None;
2408 }
2409
2410 match image_ref.get_data() {
2413 DecodedImage::Gl(texture) => {
2414 let descriptor = texture.get_descriptor();
2415 let key = image_ref_hash_to_image_key(image_ref_hash, id_namespace);
2416 let external_image_id =
2418 (insert_into_active_gl_textures)(*document_id, epoch, texture.clone());
2419 Some((
2420 image_ref_hash,
2421 AddImageMsg(AddImage {
2422 key,
2423 data: ImageData::External(ExternalImageData {
2424 id: external_image_id,
2425 channel_index: 0,
2426 image_type: ExternalImageType::TextureHandle(
2427 ImageBufferKind::Texture2D,
2428 ),
2429 }),
2430 descriptor,
2431 tiling: None,
2432 }),
2433 ))
2434 }
2435 DecodedImage::Raw((descriptor, data)) => {
2436 let key = image_ref_hash_to_image_key(image_ref_hash, id_namespace);
2437 Some((
2438 image_ref_hash,
2439 AddImageMsg(AddImage {
2440 key,
2441 data: data.clone(), descriptor: descriptor.clone(), tiling: None,
2445 }),
2446 ))
2447 }
2448 DecodedImage::NullImage {
2449 width: _,
2450 height: _,
2451 format: _,
2452 tag: _,
2453 } => None,
2454 DecodedImage::Callback(_) => None, }
2457 })
2458 .collect()
2459}
2460
2461fn add_gl_resources(
2462 renderer_resources: &mut RendererResources,
2463 all_resource_updates: &mut Vec<ResourceUpdate>,
2464 add_image_resources: Vec<(ImageRefHash, ImageRefHash, AddImageMsg)>,
2465) {
2466 let add_image_resources = add_image_resources
2467 .into_iter()
2468 .map(|(_, k, v)| (k, v))
2470 .collect::<Vec<_>>();
2471
2472 add_resources(
2473 renderer_resources,
2474 all_resource_updates,
2475 Vec::new(),
2476 add_image_resources,
2477 );
2478}
2479
2480pub fn add_resources(
2485 renderer_resources: &mut RendererResources,
2486 all_resource_updates: &mut Vec<ResourceUpdate>,
2487 add_font_resources: Vec<(StyleFontFamilyHash, AddFontMsg)>,
2488 add_image_resources: Vec<(ImageRefHash, AddImageMsg)>,
2489) {
2490 all_resource_updates.extend(
2491 add_font_resources
2492 .iter()
2493 .map(|(_, f)| f.into_resource_update()),
2494 );
2495 all_resource_updates.extend(
2496 add_image_resources
2497 .iter()
2498 .map(|(_, i)| i.into_resource_update()),
2499 );
2500
2501 for (image_ref_hash, add_image_msg) in add_image_resources.iter() {
2502 renderer_resources.currently_registered_images.insert(
2503 *image_ref_hash,
2504 ResolvedImage {
2505 key: add_image_msg.0.key,
2506 descriptor: add_image_msg.0.descriptor,
2507 },
2508 );
2509 }
2510
2511 for (_, add_font_msg) in add_font_resources {
2512 use self::AddFontMsg::*;
2513 match add_font_msg {
2514 Font(fk, font_family_hash, font_ref) => {
2515 renderer_resources
2516 .currently_registered_fonts
2517 .entry(fk)
2518 .or_insert_with(|| (font_ref.clone(), FastHashMap::default()));
2519
2520 renderer_resources
2522 .font_hash_map
2523 .insert(font_ref.get_hash(), fk);
2524 }
2525 Instance(fi, size) => {
2526 if let Some((_, instances)) = renderer_resources
2527 .currently_registered_fonts
2528 .get_mut(&fi.font_key)
2529 {
2530 instances.insert(size, fi.key);
2531 }
2532 }
2533 }
2534 }
2535}