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
10pub use azul_css::FontMetrics;
11use azul_css::{
12 AzString, ColorU, F32Vec, FloatValue, FontRef, LayoutRect, LayoutSize, OptionI32,
13 StyleFontFamily, StyleFontFamilyVec, StyleFontSize, U16Vec, U32Vec, U8Vec,
14};
15use rust_fontconfig::FcFontCache;
16
17use crate::{
18 callbacks::{
19 DocumentId, DomNodeId, InlineText, RefAny, RenderImageCallback, RenderImageCallbackType,
20 UpdateImageType,
21 },
22 display_list::{GlStoreImageFn, GlyphInstance, RenderCallbacks},
23 dom::NodeType,
24 gl::{OptionGlContextPtr, Texture},
25 id_tree::NodeId,
26 styled_dom::{
27 DomId, NodeHierarchyItemId, StyleFontFamiliesHash, StyleFontFamilyHash, StyledDom,
28 },
29 task::ExternalSystemCallbacks,
30 ui_solver::{InlineTextLayout, InlineTextLine, LayoutResult, ResolvedTextLayoutOptions},
31 window::{LogicalPosition, LogicalRect, LogicalSize, OptionChar},
32 FastBTreeSet, FastHashMap,
33};
34
35#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
36#[repr(C)]
37pub struct DpiScaleFactor {
38 pub inner: FloatValue,
39}
40
41#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
43#[repr(C)]
44pub struct AppConfig {
45 pub layout_solver: LayoutSolverVersion,
48 pub log_level: AppLogLevel,
52 pub enable_visual_panic_hook: bool,
55 pub enable_logging_on_panic: bool,
58 pub enable_tab_navigation: bool,
61 pub system_callbacks: ExternalSystemCallbacks,
63}
64
65impl AppConfig {
66 pub fn new(layout_solver: LayoutSolverVersion) -> Self {
67 Self {
68 layout_solver,
69 log_level: AppLogLevel::Error,
70 enable_visual_panic_hook: true,
71 enable_logging_on_panic: true,
72 enable_tab_navigation: true,
73 system_callbacks: ExternalSystemCallbacks::rust_internal(),
74 }
75 }
76}
77
78#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
79#[repr(C)]
80pub enum LayoutSolverVersion {
81 Default,
83}
84
85#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
86#[repr(C)]
87pub enum AppLogLevel {
88 Off,
89 Error,
90 Warn,
91 Info,
92 Debug,
93 Trace,
94}
95
96pub type WordIndex = usize;
97pub type GlyphIndex = usize;
98pub type LineLength = f32;
99pub type IndexOfLineBreak = usize;
100pub type RemainingSpaceToRight = f32;
101pub type LineBreaks = Vec<(GlyphIndex, RemainingSpaceToRight)>;
102
103#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
104pub struct PrimitiveFlags {
105 pub is_backface_visible: bool,
107 pub is_scrollbar_container: bool,
109 pub is_scrollbar_thumb: bool,
111 pub prefer_compositor_surface: bool,
115 pub supports_external_compositor_surface: bool,
119}
120
121#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
123#[repr(C)]
124pub struct ImageDescriptor {
125 pub format: RawImageFormat,
127 pub width: usize,
129 pub height: usize,
130 pub stride: OptionI32,
135 pub offset: i32,
141 pub flags: ImageDescriptorFlags,
143}
144
145#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
147#[repr(C)]
148pub struct ImageDescriptorFlags {
149 pub is_opaque: bool,
152 pub allow_mipmaps: bool,
158}
159
160#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
161pub struct IdNamespace(pub u32);
162
163impl ::core::fmt::Display for IdNamespace {
164 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
165 write!(f, "IdNamespace({})", self.0)
166 }
167}
168
169impl ::core::fmt::Debug for IdNamespace {
170 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
171 write!(f, "{}", self)
172 }
173}
174
175#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
176#[repr(C)]
177pub enum RawImageFormat {
178 R8,
179 RG8,
180 RGB8,
181 RGBA8,
182 R16,
183 RG16,
184 RGB16,
185 RGBA16,
186 BGR8,
187 BGRA8,
188 RGBF32,
189 RGBAF32,
190}
191
192static IMAGE_KEY: AtomicU32 = AtomicU32::new(1); static FONT_KEY: AtomicU32 = AtomicU32::new(0);
194static FONT_INSTANCE_KEY: AtomicU32 = AtomicU32::new(0);
195
196#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
197pub struct ImageKey {
198 pub namespace: IdNamespace,
199 pub key: u32,
200}
201
202impl ImageKey {
203 pub const DUMMY: Self = Self {
204 namespace: IdNamespace(0),
205 key: 0,
206 };
207
208 pub fn unique(render_api_namespace: IdNamespace) -> Self {
209 Self {
210 namespace: render_api_namespace,
211 key: IMAGE_KEY.fetch_add(1, AtomicOrdering::SeqCst),
212 }
213 }
214}
215
216#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
217pub struct FontKey {
218 pub namespace: IdNamespace,
219 pub key: u32,
220}
221
222impl FontKey {
223 pub fn unique(render_api_namespace: IdNamespace) -> Self {
224 Self {
225 namespace: render_api_namespace,
226 key: FONT_KEY.fetch_add(1, AtomicOrdering::SeqCst),
227 }
228 }
229}
230
231#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
232pub struct FontInstanceKey {
233 pub namespace: IdNamespace,
234 pub key: u32,
235}
236
237impl FontInstanceKey {
238 pub fn unique(render_api_namespace: IdNamespace) -> Self {
239 Self {
240 namespace: render_api_namespace,
241 key: FONT_INSTANCE_KEY.fetch_add(1, AtomicOrdering::SeqCst),
242 }
243 }
244}
245
246#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
247#[repr(C)]
248pub struct ImageCallback {
249 pub data: RefAny,
250 pub callback: RenderImageCallback,
251}
252
253#[derive(Debug)]
256pub enum DecodedImage {
257 NullImage {
260 width: usize,
261 height: usize,
262 format: RawImageFormat,
263 tag: Vec<u8>,
265 },
266 Gl(Texture),
268 Raw((ImageDescriptor, ImageData)),
270 Callback(ImageCallback),
272 }
277
278#[derive(Debug)]
279#[repr(C)]
280pub struct ImageRef {
281 pub data: *const DecodedImage,
283 pub copies: *const AtomicUsize,
285 pub run_destructor: bool,
286}
287
288#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Hash, Ord, Eq)]
289pub struct ImageRefHash(pub usize);
290
291impl_option!(
292 ImageRef,
293 OptionImageRef,
294 copy = false,
295 [Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
296);
297
298impl ImageRef {
299 pub fn into_inner(self) -> Option<DecodedImage> {
301 unsafe {
302 if self.copies.as_ref().map(|m| m.load(AtomicOrdering::SeqCst)) == Some(1) {
303 let data = Box::from_raw(self.data as *mut DecodedImage);
304 let _ = Box::from_raw(self.copies as *mut AtomicUsize);
305 core::mem::forget(self); Some(*data)
307 } else {
308 None
309 }
310 }
311 }
312
313 pub fn get_data<'a>(&'a self) -> &'a DecodedImage {
314 unsafe { &*self.data }
315 }
316
317 pub fn get_image_callback<'a>(&'a self) -> Option<&'a ImageCallback> {
318 if unsafe { self.copies.as_ref().map(|m| m.load(AtomicOrdering::SeqCst)) != Some(1) } {
319 return None; }
321
322 match unsafe { &*self.data } {
323 DecodedImage::Callback(gl_texture_callback) => Some(gl_texture_callback),
324 _ => None,
325 }
326 }
327
328 pub fn get_image_callback_mut<'a>(&'a mut self) -> Option<&'a mut ImageCallback> {
329 if unsafe { self.copies.as_ref().map(|m| m.load(AtomicOrdering::SeqCst)) != Some(1) } {
330 return None; }
332
333 match unsafe { &mut *(self.data as *mut DecodedImage) } {
334 DecodedImage::Callback(gl_texture_callback) => Some(gl_texture_callback),
335 _ => None,
336 }
337 }
338
339 pub fn deep_copy(&self) -> Self {
341 let new_data = match self.get_data() {
342 DecodedImage::NullImage {
343 width,
344 height,
345 format,
346 tag,
347 } => DecodedImage::NullImage {
348 width: *width,
349 height: *height,
350 format: *format,
351 tag: tag.clone(),
352 },
353 DecodedImage::Gl(tex) => DecodedImage::NullImage {
357 width: tex.size.width as usize,
358 height: tex.size.height as usize,
359 format: tex.format,
360 tag: Vec::new(),
361 },
362 DecodedImage::Raw((descriptor, data)) => {
365 DecodedImage::Raw((descriptor.clone(), data.clone()))
366 }
367 DecodedImage::Callback(cb) => DecodedImage::Callback(cb.clone()),
368 };
369
370 Self::new(new_data)
371 }
372
373 pub fn is_null_image(&self) -> bool {
374 match self.get_data() {
375 DecodedImage::NullImage { .. } => true,
376 _ => false,
377 }
378 }
379
380 pub fn is_gl_texture(&self) -> bool {
381 match self.get_data() {
382 DecodedImage::Gl(_) => true,
383 _ => false,
384 }
385 }
386
387 pub fn is_raw_image(&self) -> bool {
388 match self.get_data() {
389 DecodedImage::Raw((_, _)) => true,
390 _ => false,
391 }
392 }
393
394 pub fn is_callback(&self) -> bool {
395 match self.get_data() {
396 DecodedImage::Callback(_) => true,
397 _ => false,
398 }
399 }
400
401 pub fn get_rawimage(&self) -> Option<RawImage> {
403 match self.get_data() {
404 DecodedImage::Raw((image_descriptor, image_data)) => Some(RawImage {
405 pixels: match image_data {
406 ImageData::Raw(u8_bytes) => RawImageData::U8(u8_bytes.clone()),
407 ImageData::External(_) => return None,
408 },
409 width: image_descriptor.width,
410 height: image_descriptor.height,
411 premultiplied_alpha: true,
412 data_format: image_descriptor.format,
413 tag: Vec::new().into(),
414 }),
415 _ => None,
416 }
417 }
418
419 pub fn get_size(&self) -> LogicalSize {
421 match self.get_data() {
422 DecodedImage::NullImage { width, height, .. } => {
423 LogicalSize::new(*width as f32, *height as f32)
424 }
425 DecodedImage::Gl(tex) => {
426 LogicalSize::new(tex.size.width as f32, tex.size.height as f32)
427 }
428 DecodedImage::Raw((image_descriptor, _)) => LogicalSize::new(
429 image_descriptor.width as f32,
430 image_descriptor.height as f32,
431 ),
432 DecodedImage::Callback(_) => LogicalSize::new(0.0, 0.0),
433 }
434 }
435
436 pub fn get_hash(&self) -> ImageRefHash {
437 ImageRefHash(self.data as usize)
438 }
439
440 pub fn null_image(width: usize, height: usize, format: RawImageFormat, tag: Vec<u8>) -> Self {
441 Self::new(DecodedImage::NullImage {
442 width,
443 height,
444 format,
445 tag,
446 })
447 }
448
449 pub fn callback(gl_callback: RenderImageCallbackType, data: RefAny) -> Self {
450 Self::new(DecodedImage::Callback(ImageCallback {
451 callback: RenderImageCallback { cb: gl_callback },
452 data,
453 }))
454 }
455
456 pub fn new_rawimage(image_data: RawImage) -> Option<Self> {
457 let (image_data, image_descriptor) = image_data.into_loaded_image_source()?;
458 Some(Self::new(DecodedImage::Raw((image_descriptor, image_data))))
459 }
460
461 pub fn new_gltexture(texture: Texture) -> Self {
462 Self::new(DecodedImage::Gl(texture))
463 }
464
465 fn new(data: DecodedImage) -> Self {
466 Self {
467 data: Box::into_raw(Box::new(data)),
468 copies: Box::into_raw(Box::new(AtomicUsize::new(1))),
469 run_destructor: true,
470 }
471 }
472
473 }
475
476unsafe impl Send for ImageRef {}
477unsafe impl Sync for ImageRef {}
478
479impl PartialEq for ImageRef {
480 fn eq(&self, rhs: &Self) -> bool {
481 self.data as usize == rhs.data as usize
482 }
483}
484
485impl PartialOrd for ImageRef {
486 fn partial_cmp(&self, other: &Self) -> Option<::core::cmp::Ordering> {
487 Some((self.data as usize).cmp(&(other.data as usize)))
488 }
489}
490
491impl Ord for ImageRef {
492 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
493 let self_data = self.data as usize;
494 let other_data = other.data as usize;
495 self_data.cmp(&other_data)
496 }
497}
498
499impl Eq for ImageRef {}
500
501impl Hash for ImageRef {
502 fn hash<H>(&self, state: &mut H)
503 where
504 H: Hasher,
505 {
506 let self_data = self.data as usize;
507 self_data.hash(state)
508 }
509}
510
511impl Clone for ImageRef {
512 fn clone(&self) -> Self {
513 unsafe {
514 self.copies
515 .as_ref()
516 .map(|m| m.fetch_add(1, AtomicOrdering::SeqCst));
517 }
518 Self {
519 data: self.data, copies: self.copies, run_destructor: true,
522 }
523 }
524}
525
526impl Drop for ImageRef {
527 fn drop(&mut self) {
528 self.run_destructor = false;
529 unsafe {
530 let copies = unsafe { (*self.copies).fetch_sub(1, AtomicOrdering::SeqCst) };
531 if copies == 1 {
532 let _ = Box::from_raw(self.data as *mut DecodedImage);
533 let _ = Box::from_raw(self.copies as *mut AtomicUsize);
534 }
535 }
536 }
537}
538
539pub fn font_ref_get_hash(fr: &FontRef) -> u64 {
540 use crate::css::GetHash;
541 fr.get_hash()
542}
543
544#[derive(Debug)]
550pub struct ImageCache {
551 pub image_id_map: FastHashMap<AzString, ImageRef>,
557}
558
559impl Default for ImageCache {
560 fn default() -> Self {
561 Self {
562 image_id_map: FastHashMap::default(),
563 }
564 }
565}
566
567impl ImageCache {
568 pub fn new() -> Self {
569 Self::default()
570 }
571
572 pub fn add_css_image_id(&mut self, css_id: AzString, image: ImageRef) {
575 self.image_id_map.insert(css_id, image);
576 }
577
578 pub fn get_css_image_id(&self, css_id: &AzString) -> Option<&ImageRef> {
579 self.image_id_map.get(css_id)
580 }
581
582 pub fn delete_css_image_id(&mut self, css_id: &AzString) {
583 self.image_id_map.remove(css_id);
584 }
585}
586
587#[derive(Debug, Copy, Clone, PartialEq)]
589pub enum ImageType {
590 Background,
592 Content,
594 ClipMask,
596}
597
598#[derive(Debug, Copy, Clone, PartialEq)]
599pub struct ResolvedImage {
600 pub key: ImageKey,
601 pub descriptor: ImageDescriptor,
602}
603
604pub struct RendererResources {
611 currently_registered_images: FastHashMap<ImageRefHash, ResolvedImage>,
613 currently_registered_fonts:
615 FastHashMap<FontKey, (FontRef, FastHashMap<(Au, DpiScaleFactor), FontInstanceKey>)>,
616 last_frame_registered_fonts:
623 FastHashMap<FontKey, FastHashMap<(Au, DpiScaleFactor), FontInstanceKey>>,
624 font_families_map: FastHashMap<StyleFontFamiliesHash, StyleFontFamilyHash>,
629 font_id_map: FastHashMap<StyleFontFamilyHash, FontKey>,
631}
632
633impl fmt::Debug for RendererResources {
634 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
635 write!(
636 f,
637 "RendererResources {{
638 currently_registered_images: {:#?},
639 currently_registered_fonts: {:#?},
640 font_families_map: {:#?},
641 font_id_map: {:#?},
642 }}",
643 self.currently_registered_images.keys().collect::<Vec<_>>(),
644 self.currently_registered_fonts.keys().collect::<Vec<_>>(),
645 self.font_families_map.keys().collect::<Vec<_>>(),
646 self.font_id_map.keys().collect::<Vec<_>>(),
647 )
648 }
649}
650
651impl Default for RendererResources {
652 fn default() -> Self {
653 Self {
654 currently_registered_images: FastHashMap::default(),
655 currently_registered_fonts: FastHashMap::default(),
656 last_frame_registered_fonts: FastHashMap::default(),
657 font_families_map: FastHashMap::default(),
658 font_id_map: FastHashMap::default(),
659 }
660 }
661}
662
663impl RendererResources {
664 pub fn get_image(&self, hash: &ImageRefHash) -> Option<&ResolvedImage> {
665 self.currently_registered_images.get(hash)
666 }
667
668 pub fn get_font_family(
669 &self,
670 style_font_families_hash: &StyleFontFamiliesHash,
671 ) -> Option<&StyleFontFamilyHash> {
672 self.font_families_map.get(style_font_families_hash)
673 }
674
675 pub fn get_font_key(&self, style_font_family_hash: &StyleFontFamilyHash) -> Option<&FontKey> {
676 self.font_id_map.get(style_font_family_hash)
677 }
678
679 pub fn get_registered_font(
680 &self,
681 font_key: &FontKey,
682 ) -> Option<&(FontRef, FastHashMap<(Au, DpiScaleFactor), FontInstanceKey>)> {
683 self.currently_registered_fonts.get(font_key)
684 }
685
686 pub fn update_image(&mut self, image_ref_hash: &ImageRefHash, descriptor: ImageDescriptor) {
687 if let Some(s) = self.currently_registered_images.get_mut(image_ref_hash) {
688 s.descriptor = descriptor; }
690 }
691
692 pub fn do_gc(
703 &mut self,
704 all_resource_updates: &mut Vec<ResourceUpdate>,
705 css_image_cache: &ImageCache,
706 new_layout_results: &[LayoutResult],
708 gl_texture_cache: &GlTextureCache,
710 ) {
711 use alloc::collections::btree_set::BTreeSet;
712
713 let mut next_frame_image_keys = BTreeSet::new();
715
716 for layout_result in new_layout_results {
717 for image_key in layout_result
718 .styled_dom
719 .scan_for_image_keys(css_image_cache)
720 {
721 let hash = image_key.get_hash();
722 next_frame_image_keys.insert(hash);
723 }
724 }
725
726 for ((_dom_id, _node_id, _callback_imageref_hash), image_ref_hash) in
727 gl_texture_cache.hashes.iter()
728 {
729 next_frame_image_keys.insert(*image_ref_hash);
730 }
731
732 let mut delete_font_resources = Vec::new();
734 for (font_key, font_instances) in self.last_frame_registered_fonts.iter() {
735 delete_font_resources.extend(
736 font_instances
737 .iter()
738 .filter(|(au, _)| {
739 !(self
740 .currently_registered_fonts
741 .get(font_key)
742 .map(|f| f.1.contains_key(au))
743 .unwrap_or(false))
744 })
745 .map(|(au, font_instance_key)| {
746 (
747 font_key.clone(),
748 DeleteFontMsg::Instance(*font_instance_key, *au),
749 )
750 }),
751 );
752 if !self.currently_registered_fonts.contains_key(font_key) || font_instances.is_empty()
756 {
757 delete_font_resources
758 .push((font_key.clone(), DeleteFontMsg::Font(font_key.clone())));
759 }
760 }
761
762 let delete_image_resources = self
764 .currently_registered_images
765 .iter()
766 .filter(|(image_ref_hash, _)| !next_frame_image_keys.contains(image_ref_hash))
767 .map(|(image_ref_hash, resolved_image)| {
768 (
769 image_ref_hash.clone(),
770 DeleteImageMsg(resolved_image.key.clone()),
771 )
772 })
773 .collect::<Vec<_>>();
774
775 for (image_ref_hash_to_delete, _) in delete_image_resources.iter() {
776 self.currently_registered_images
777 .remove(image_ref_hash_to_delete);
778 }
779
780 all_resource_updates.extend(
781 delete_font_resources
782 .iter()
783 .map(|(_, f)| f.into_resource_update()),
784 );
785 all_resource_updates.extend(
786 delete_image_resources
787 .iter()
788 .map(|(_, i)| i.into_resource_update()),
789 );
790
791 self.last_frame_registered_fonts = self
792 .currently_registered_fonts
793 .iter()
794 .map(|(fk, (_, fi))| (fk.clone(), fi.clone()))
795 .collect();
796
797 self.remove_font_families_with_zero_references();
798 }
799
800 fn remove_font_families_with_zero_references(&mut self) {
802 let font_family_to_delete = self
803 .font_id_map
804 .iter()
805 .filter_map(|(font_family, font_key)| {
806 if !self.currently_registered_fonts.contains_key(font_key) {
807 Some(font_family.clone())
808 } else {
809 None
810 }
811 })
812 .collect::<Vec<_>>();
813
814 for f in font_family_to_delete {
815 self.font_id_map.remove(&f); }
817
818 let font_families_to_delete = self
819 .font_families_map
820 .iter()
821 .filter_map(|(font_families, font_family)| {
822 if !self.font_id_map.contains_key(font_family) {
823 Some(font_families.clone())
824 } else {
825 None
826 }
827 })
828 .collect::<Vec<_>>();
829
830 for f in font_families_to_delete {
831 self.font_families_map.remove(&f); }
833 }
834
835 #[must_use]
839 pub fn rerender_image_callback(
840 &mut self,
841 dom_id: DomId,
842 node_id: NodeId,
843 document_id: DocumentId,
844 epoch: Epoch,
845 id_namespace: IdNamespace,
846 gl_context: &OptionGlContextPtr,
847 image_cache: &ImageCache,
848 system_fonts: &FcFontCache,
849 hidpi_factor: f32,
850 callbacks: &RenderCallbacks,
851 layout_results: &mut [LayoutResult],
852 gl_texture_cache: &mut GlTextureCache,
853 ) -> Option<UpdateImageResult> {
854 use crate::{
855 callbacks::{HidpiAdjustedBounds, RenderImageCallbackInfo},
856 gl::{insert_into_active_gl_textures, remove_single_texture_from_active_gl_textures},
857 };
858
859 let mut layout_result = layout_results.get_mut(dom_id.inner)?;
860 let mut node_data_vec = layout_result.styled_dom.node_data.as_container_mut();
861 let mut node_data = node_data_vec.get_mut(node_id)?;
862 let (mut render_image_callback, render_image_callback_hash) =
863 node_data.get_render_image_callback_node()?;
864
865 let callback_domnode_id = DomNodeId {
866 dom: dom_id,
867 node: NodeHierarchyItemId::from_crate_internal(Some(node_id)),
868 };
869
870 let rect_size = layout_result.rects.as_ref().get(node_id)?.size.clone();
871
872 let size = LayoutSize::new(
873 rect_size.width.round() as isize,
874 rect_size.height.round() as isize,
875 );
876
877 let mut gl_callback_info = RenderImageCallbackInfo::new(
882 gl_context,
883 image_cache,
884 system_fonts,
885 &layout_result.styled_dom.node_hierarchy,
886 &layout_result.words_cache,
887 &layout_result.shaped_words_cache,
888 &layout_result.positioned_words_cache,
889 &layout_result.rects,
890 HidpiAdjustedBounds::from_bounds(size, hidpi_factor),
891 callback_domnode_id,
892 );
893
894 let new_imageref = (render_image_callback.callback.cb)(
895 &mut render_image_callback.data,
896 &mut gl_callback_info,
897 );
898
899 let existing_image_key = gl_texture_cache
901 .solved_textures
902 .get(&dom_id)
903 .and_then(|m| m.get(&node_id))
904 .map(|k| k.0.clone())
905 .or(self
906 .currently_registered_images
907 .get(&render_image_callback_hash)
908 .map(|i| i.key.clone()))?;
909
910 if let Some(dom_map) = gl_texture_cache.solved_textures.get_mut(&dom_id) {
911 if let Some((image_key, image_descriptor, external_image_id)) = dom_map.remove(&node_id)
912 {
913 remove_single_texture_from_active_gl_textures(
914 &document_id,
915 &epoch,
916 &external_image_id,
917 );
918 }
919 }
920
921 match new_imageref.into_inner()? {
922 DecodedImage::Gl(new_tex) => {
923 let new_descriptor = new_tex.get_descriptor();
925 let new_external_id = insert_into_active_gl_textures(document_id, epoch, new_tex);
926 let new_image_data = ImageData::External(ExternalImageData {
927 id: new_external_id,
928 channel_index: 0,
929 image_type: ExternalImageType::TextureHandle(ImageBufferKind::Texture2D),
930 });
931
932 gl_texture_cache
933 .solved_textures
934 .entry(dom_id)
935 .or_insert_with(|| BTreeMap::new())
936 .insert(
937 node_id,
938 (existing_image_key, new_descriptor.clone(), new_external_id),
939 );
940
941 Some(UpdateImageResult {
942 key_to_update: existing_image_key,
943 new_descriptor,
944 new_image_data,
945 })
946 }
947 DecodedImage::Raw((descriptor, data)) => {
948 if let Some(existing_image) = self
949 .currently_registered_images
950 .get_mut(&render_image_callback_hash)
951 {
952 existing_image.descriptor = descriptor.clone(); Some(UpdateImageResult {
954 key_to_update: existing_image_key,
955 new_descriptor: descriptor,
956 new_image_data: data,
957 })
958 } else {
959 None
960 }
961 }
962 _ => None,
963 }
964 }
965
966 #[must_use]
969 pub fn update_image_resources(
970 &mut self,
971 layout_results: &[LayoutResult],
972 images_to_update: BTreeMap<DomId, BTreeMap<NodeId, (ImageRef, UpdateImageType)>>,
973 image_masks_to_update: BTreeMap<DomId, BTreeMap<NodeId, ImageMask>>,
974 callbacks: &RenderCallbacks,
975 image_cache: &ImageCache,
976 gl_texture_cache: &mut GlTextureCache,
977 document_id: DocumentId,
978 epoch: Epoch,
979 ) -> Vec<UpdateImageResult> {
980 use crate::dom::NodeType;
981
982 let mut updated_images = Vec::new();
983 let mut renderer_resources: &mut RendererResources = self;
984
985 for (dom_id, image_map) in images_to_update {
987 let layout_result = match layout_results.get(dom_id.inner) {
988 Some(s) => s,
989 None => continue,
990 };
991
992 for (node_id, (image_ref, image_type)) in image_map {
993 let existing_image_ref_hash = match image_type {
995 UpdateImageType::Content => {
996 match layout_result
997 .styled_dom
998 .node_data
999 .as_container()
1000 .get(node_id)
1001 .map(|n| n.get_node_type())
1002 {
1003 Some(NodeType::Image(image_ref)) => image_ref.get_hash(),
1004 _ => continue,
1005 }
1006 }
1007 UpdateImageType::Background => {
1008 let node_data = layout_result.styled_dom.node_data.as_container();
1009 let node_data = match node_data.get(node_id) {
1010 Some(s) => s,
1011 None => continue,
1012 };
1013
1014 let styled_node_states =
1015 layout_result.styled_dom.styled_nodes.as_container();
1016 let node_state = match styled_node_states.get(node_id) {
1017 Some(s) => s.state.clone(),
1018 None => continue,
1019 };
1020
1021 let default = azul_css::StyleBackgroundContentVec::from_const_slice(&[]);
1022
1023 let bg_hash = layout_result
1025 .styled_dom
1026 .css_property_cache
1027 .ptr
1028 .get_background_content(node_data, &node_id, &node_state)
1029 .and_then(|bg| {
1030 bg.get_property()
1031 .unwrap_or(&default)
1032 .as_ref()
1033 .iter()
1034 .find_map(|b| match b {
1035 azul_css::StyleBackgroundContent::Image(id) => {
1036 let image_ref = image_cache.get_css_image_id(id)?;
1037 Some(image_ref.get_hash())
1038 }
1039 _ => None,
1040 })
1041 });
1042
1043 match bg_hash {
1044 Some(h) => h,
1045 None => continue,
1046 }
1047 }
1048 };
1049
1050 let new_image_ref_hash = image_ref.get_hash();
1051
1052 let decoded_image = match image_ref.into_inner() {
1053 Some(s) => s,
1054 None => continue,
1055 };
1056
1057 let existing_key = gl_texture_cache
1060 .solved_textures
1061 .get(&dom_id)
1062 .and_then(|map| map.get(&node_id))
1063 .map(|val| val.0);
1064
1065 let existing_key = match existing_key {
1066 Some(s) => Some(s),
1067 None => renderer_resources
1068 .get_image(&existing_image_ref_hash)
1069 .map(|resolved_image| resolved_image.key),
1070 };
1071
1072 let key = match existing_key {
1073 Some(s) => s,
1074 None => continue, };
1077
1078 let (descriptor, data) = match decoded_image {
1079 DecodedImage::Gl(texture) => {
1080 let descriptor = texture.get_descriptor();
1081 let new_external_image_id = match gl_texture_cache.update_texture(
1082 dom_id,
1083 node_id,
1084 document_id,
1085 epoch,
1086 texture,
1087 callbacks,
1088 ) {
1089 Some(s) => s,
1090 None => continue,
1091 };
1092
1093 let data = ImageData::External(ExternalImageData {
1094 id: new_external_image_id,
1095 channel_index: 0,
1096 image_type: ExternalImageType::TextureHandle(
1097 ImageBufferKind::Texture2D,
1098 ),
1099 });
1100
1101 (descriptor, data)
1102 }
1103 DecodedImage::Raw((descriptor, data)) => {
1104 renderer_resources.update_image(&existing_image_ref_hash, descriptor);
1107 (descriptor, data)
1108 }
1109 DecodedImage::NullImage { .. } => continue, DecodedImage::Callback(callback) => {
1111 continue;
1119 }
1120 };
1121
1122 updated_images.push(UpdateImageResult {
1125 key_to_update: key,
1126 new_descriptor: descriptor,
1127 new_image_data: data,
1128 });
1129 }
1130 }
1131
1132 for (dom_id, image_mask_map) in image_masks_to_update {}
1134
1135 updated_images
1136 }
1137}
1138
1139#[derive(Debug, Clone)]
1150pub struct UpdateImageResult {
1151 pub key_to_update: ImageKey,
1152 pub new_descriptor: ImageDescriptor,
1153 pub new_image_data: ImageData,
1154}
1155
1156#[derive(Debug, Default)]
1157pub struct GlTextureCache {
1158 pub solved_textures:
1159 BTreeMap<DomId, BTreeMap<NodeId, (ImageKey, ImageDescriptor, ExternalImageId)>>,
1160 pub hashes: BTreeMap<(DomId, NodeId, ImageRefHash), ImageRefHash>,
1161}
1162
1163unsafe impl Send for GlTextureCache {}
1165
1166impl GlTextureCache {
1167 pub fn empty() -> Self {
1169 Self {
1170 solved_textures: BTreeMap::new(),
1171 hashes: BTreeMap::new(),
1172 }
1173 }
1174
1175 pub fn new(
1178 layout_results: &mut [LayoutResult],
1179 gl_context: &OptionGlContextPtr,
1180 id_namespace: IdNamespace,
1181 document_id: &DocumentId,
1182 epoch: Epoch,
1183 hidpi_factor: f32,
1184 image_cache: &ImageCache,
1185 system_fonts: &FcFontCache,
1186 callbacks: &RenderCallbacks,
1187 all_resource_updates: &mut Vec<ResourceUpdate>,
1188 renderer_resources: &mut RendererResources,
1189 ) -> Self {
1190 use gl_context_loader::gl;
1191
1192 use crate::{
1193 app_resources::{
1194 add_resources, AddImage, DecodedImage, ExternalImageData, ExternalImageType,
1195 ImageBufferKind, ImageData, ImageRef,
1196 },
1197 callbacks::{HidpiAdjustedBounds, RenderImageCallbackInfo},
1198 dom::NodeType,
1199 };
1200
1201 let mut solved_image_callbacks = BTreeMap::new();
1202
1203 for (dom_id, layout_result) in layout_results.iter_mut().enumerate() {
1205 for callback_node_id in layout_result.styled_dom.scan_for_gltexture_callbacks() {
1206 let rect_size = layout_result.rects.as_ref()[callback_node_id].size;
1208
1209 let callback_image = {
1210 let callback_domnode_id = DomNodeId {
1211 dom: DomId { inner: dom_id },
1212 node: NodeHierarchyItemId::from_crate_internal(Some(callback_node_id)),
1213 };
1214
1215 let size = LayoutSize::new(
1216 rect_size.width.round() as isize,
1217 rect_size.height.round() as isize,
1218 );
1219
1220 let mut gl_callback_info = RenderImageCallbackInfo::new(
1225 &gl_context,
1226 image_cache,
1227 system_fonts,
1228 &layout_result.styled_dom.node_hierarchy,
1229 &layout_result.words_cache,
1230 &layout_result.shaped_words_cache,
1231 &layout_result.positioned_words_cache,
1232 &layout_result.rects,
1233 HidpiAdjustedBounds::from_bounds(size, hidpi_factor),
1234 callback_domnode_id,
1235 );
1236
1237 let callback_image: Option<(ImageRef, ImageRefHash)> = {
1238 let mut node_data_mut =
1240 layout_result.styled_dom.node_data.as_container_mut();
1241 match &mut node_data_mut[callback_node_id].node_type {
1242 NodeType::Image(img) => {
1243 let callback_imageref_hash = img.get_hash();
1244
1245 img.get_image_callback_mut().map(|gl_texture_callback| {
1246 (
1247 (gl_texture_callback.callback.cb)(
1248 &mut gl_texture_callback.data,
1249 &mut gl_callback_info,
1250 ),
1251 callback_imageref_hash,
1252 )
1253 })
1254 }
1255 _ => None,
1256 }
1257 };
1258
1259 if let Some(gl) = gl_context.as_ref() {
1261 gl.bind_framebuffer(gl::FRAMEBUFFER, 0);
1262 gl.disable(gl::FRAMEBUFFER_SRGB);
1263 gl.disable(gl::MULTISAMPLE);
1264 }
1265
1266 callback_image
1267 };
1268
1269 if let Some((image_ref, callback_imageref_hash)) = callback_image {
1270 solved_image_callbacks
1271 .entry(layout_result.dom_id.clone())
1272 .or_insert_with(|| BTreeMap::default())
1273 .insert(callback_node_id, (callback_imageref_hash, image_ref));
1274 }
1275 }
1276 }
1277
1278 let mut image_resource_updates = Vec::new();
1279 let mut gl_texture_cache = Self::empty();
1280
1281 for (dom_id, image_refs) in solved_image_callbacks {
1282 for (node_id, (callback_imageref_hash, image_ref)) in image_refs {
1283 let image_ref_hash = image_ref.get_hash();
1290 let image_data = match image_ref.into_inner() {
1291 Some(s) => s,
1292 None => continue,
1293 };
1294
1295 let image_result = match image_data {
1296 DecodedImage::Gl(texture) => {
1297 let descriptor = texture.get_descriptor();
1298 let key = ImageKey::unique(id_namespace);
1299 let external_image_id = (callbacks.insert_into_active_gl_textures_fn)(
1300 *document_id,
1301 epoch,
1302 texture,
1303 );
1304
1305 gl_texture_cache
1306 .solved_textures
1307 .entry(dom_id.clone())
1308 .or_insert_with(|| BTreeMap::new())
1309 .insert(node_id, (key, descriptor, external_image_id));
1310
1311 gl_texture_cache
1312 .hashes
1313 .insert((dom_id, node_id, callback_imageref_hash), image_ref_hash);
1314
1315 Some((
1316 image_ref_hash,
1317 AddImageMsg(AddImage {
1318 key,
1319 data: ImageData::External(ExternalImageData {
1320 id: external_image_id,
1321 channel_index: 0,
1322 image_type: ExternalImageType::TextureHandle(
1323 ImageBufferKind::Texture2D,
1324 ),
1325 }),
1326 descriptor,
1327 tiling: None,
1328 }),
1329 ))
1330 }
1331 DecodedImage::Raw((descriptor, data)) => {
1332 let key = ImageKey::unique(id_namespace);
1333 Some((
1334 image_ref_hash,
1335 AddImageMsg(AddImage {
1336 key,
1337 data,
1338 descriptor,
1339 tiling: None,
1340 }),
1341 ))
1342 }
1343 DecodedImage::NullImage {
1344 width: _,
1345 height: _,
1346 format: _,
1347 tag: _,
1348 } => None,
1349 DecodedImage::Callback(_) => None,
1351 };
1352
1353 if let Some((image_ref_hash, add_img_msg)) = image_result {
1354 image_resource_updates.push((
1355 callback_imageref_hash,
1356 image_ref_hash,
1357 add_img_msg,
1358 ));
1359 }
1360 }
1361 }
1362
1363 add_gl_resources(
1365 renderer_resources,
1366 all_resource_updates,
1367 image_resource_updates,
1368 );
1369
1370 gl_texture_cache
1371 }
1372
1373 pub fn update_texture(
1375 &mut self,
1376 dom_id: DomId,
1377 node_id: NodeId,
1378 document_id: DocumentId,
1379 epoch: Epoch,
1380 new_texture: Texture,
1381 callbacks: &RenderCallbacks,
1382 ) -> Option<ExternalImageId> {
1383 let new_descriptor = new_texture.get_descriptor();
1384 let di_map = self.solved_textures.get_mut(&dom_id)?;
1385 let i = di_map.get_mut(&node_id)?;
1386 i.1 = new_descriptor;
1387 let external_image_id =
1388 (callbacks.insert_into_active_gl_textures_fn)(document_id, epoch, new_texture);
1389 Some(external_image_id)
1390 }
1391}
1392
1393macro_rules! unique_id {
1394 ($struct_name:ident, $counter_name:ident) => {
1395 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)]
1396 #[repr(C)]
1397 pub struct $struct_name {
1398 pub id: usize,
1399 }
1400
1401 impl $struct_name {
1402 pub fn unique() -> Self {
1403 Self {
1404 id: $counter_name.fetch_add(1, AtomicOrdering::SeqCst),
1405 }
1406 }
1407 }
1408 };
1409}
1410
1411static PROPERTY_KEY_COUNTER: AtomicUsize = AtomicUsize::new(0);
1413unique_id!(TransformKey, PROPERTY_KEY_COUNTER);
1414unique_id!(ColorKey, PROPERTY_KEY_COUNTER);
1415unique_id!(OpacityKey, PROPERTY_KEY_COUNTER);
1416
1417static IMAGE_ID_COUNTER: AtomicUsize = AtomicUsize::new(0);
1418unique_id!(ImageId, IMAGE_ID_COUNTER);
1419static FONT_ID_COUNTER: AtomicUsize = AtomicUsize::new(0);
1420unique_id!(FontId, FONT_ID_COUNTER);
1421
1422#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1423#[repr(C)]
1424pub struct ImageMask {
1425 pub image: ImageRef,
1426 pub rect: LogicalRect,
1427 pub repeat: bool,
1428}
1429
1430impl_option!(
1431 ImageMask,
1432 OptionImageMask,
1433 copy = false,
1434 [Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash]
1435);
1436
1437#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1438pub enum ImmediateFontId {
1439 Resolved((StyleFontFamilyHash, FontKey)),
1440 Unresolved(StyleFontFamilyVec),
1441}
1442
1443#[derive(Debug, Clone, PartialEq, PartialOrd)]
1444#[repr(C, u8)]
1445pub enum RawImageData {
1446 U8(U8Vec),
1448 U16(U16Vec),
1450 F32(F32Vec),
1452}
1453
1454impl RawImageData {
1455 pub fn get_u8_vec_ref(&self) -> Option<&U8Vec> {
1456 match self {
1457 RawImageData::U8(v) => Some(v),
1458 _ => None,
1459 }
1460 }
1461
1462 pub fn get_u16_vec_ref(&self) -> Option<&U16Vec> {
1463 match self {
1464 RawImageData::U16(v) => Some(v),
1465 _ => None,
1466 }
1467 }
1468
1469 pub fn get_f32_vec_ref(&self) -> Option<&F32Vec> {
1470 match self {
1471 RawImageData::F32(v) => Some(v),
1472 _ => None,
1473 }
1474 }
1475
1476 fn get_u8_vec(self) -> Option<U8Vec> {
1477 match self {
1478 RawImageData::U8(v) => Some(v),
1479 _ => None,
1480 }
1481 }
1482
1483 fn get_u16_vec(self) -> Option<U16Vec> {
1484 match self {
1485 RawImageData::U16(v) => Some(v),
1486 _ => None,
1487 }
1488 }
1489}
1490
1491#[derive(Debug, Clone, PartialEq, PartialOrd)]
1492#[repr(C)]
1493pub struct RawImage {
1494 pub pixels: RawImageData,
1495 pub width: usize,
1496 pub height: usize,
1497 pub premultiplied_alpha: bool,
1498 pub data_format: RawImageFormat,
1499 pub tag: U8Vec,
1500}
1501
1502impl RawImage {
1503 pub fn null_image() -> Self {
1505 Self {
1506 pixels: RawImageData::U8(Vec::new().into()),
1507 width: 0,
1508 height: 0,
1509 premultiplied_alpha: true,
1510 data_format: RawImageFormat::BGRA8,
1511 tag: Vec::new().into(),
1512 }
1513 }
1514
1515 pub fn allocate_mask(size: LayoutSize) -> Self {
1517 Self {
1518 pixels: RawImageData::U8(
1519 vec![0; size.width.max(0) as usize * size.height.max(0) as usize].into(),
1520 ),
1521 width: size.width as usize,
1522 height: size.height as usize,
1523 premultiplied_alpha: true,
1524 data_format: RawImageFormat::R8,
1525 tag: Vec::new().into(),
1526 }
1527 }
1528
1529 pub fn into_loaded_image_source(self) -> Option<(ImageData, ImageDescriptor)> {
1535 #[inline(always)]
1538 fn premultiply_alpha(array: &mut [u8]) {
1539 if array.len() != 4 {
1540 return;
1541 }
1542 let a = u32::from(array[3]);
1543 array[0] = (((array[0] as u32 * a) + 128) / 255) as u8;
1544 array[1] = (((array[1] as u32 * a) + 128) / 255) as u8;
1545 array[2] = (((array[2] as u32 * a) + 128) / 255) as u8;
1546 }
1547
1548 #[inline(always)]
1549 fn normalize_u16(i: u16) -> u8 {
1550 ((core::u16::MAX as f32 / i as f32) * core::u8::MAX as f32) as u8
1551 }
1552
1553 let RawImage {
1554 width,
1555 height,
1556 pixels,
1557 mut data_format,
1558 premultiplied_alpha,
1559 tag,
1560 } = self;
1561
1562 const FOUR_BPP: usize = 4;
1563 const TWO_CHANNELS: usize = 2;
1564 const THREE_CHANNELS: usize = 3;
1565 const FOUR_CHANNELS: usize = 4;
1566
1567 let mut is_opaque = true;
1568
1569 let expected_len = width * height;
1570
1571 let bytes: U8Vec = match data_format {
1572 RawImageFormat::R8 => {
1573 let pixels = pixels.get_u8_vec()?;
1575
1576 if pixels.len() != expected_len {
1577 return None;
1578 }
1579
1580 let pixels_ref = pixels.as_ref();
1581 let mut px = vec![0; pixels_ref.len() * 4];
1582 for (i, r) in pixels_ref.iter().enumerate() {
1583 px[i * 4 + 0] = *r;
1584 px[i * 4 + 1] = *r;
1585 px[i * 4 + 2] = *r;
1586 px[i * 4 + 3] = 0xff;
1587 }
1588
1589 data_format = RawImageFormat::BGRA8;
1590 px.into()
1591 }
1592 RawImageFormat::RG8 => {
1593 let pixels = pixels.get_u8_vec()?;
1594
1595 if pixels.len() != expected_len * TWO_CHANNELS {
1596 return None;
1597 }
1598
1599 let mut px = vec![0; expected_len * FOUR_BPP];
1600
1601 for (pixel_index, greyalpha) in
1604 pixels.as_ref().chunks_exact(TWO_CHANNELS).enumerate()
1605 {
1606 let grey = greyalpha[0];
1607 let alpha = greyalpha[1];
1608
1609 if alpha != 255 {
1610 is_opaque = false;
1611 }
1612
1613 px[pixel_index * FOUR_BPP] = grey;
1614 px[(pixel_index * FOUR_BPP) + 1] = grey;
1615 px[(pixel_index * FOUR_BPP) + 2] = grey;
1616 px[(pixel_index * FOUR_BPP) + 3] = alpha;
1617 }
1618
1619 data_format = RawImageFormat::BGRA8;
1620 px.into()
1621 }
1622 RawImageFormat::RGB8 => {
1623 let pixels = pixels.get_u8_vec()?;
1624
1625 if pixels.len() != expected_len * THREE_CHANNELS {
1626 return None;
1627 }
1628
1629 let mut px = vec![0; expected_len * FOUR_BPP];
1630
1631 for (pixel_index, rgb) in pixels.as_ref().chunks_exact(THREE_CHANNELS).enumerate() {
1633 let red = rgb[0];
1634 let green = rgb[1];
1635 let blue = rgb[2];
1636
1637 px[pixel_index * FOUR_BPP] = blue;
1638 px[(pixel_index * FOUR_BPP) + 1] = green;
1639 px[(pixel_index * FOUR_BPP) + 2] = red;
1640 px[(pixel_index * FOUR_BPP) + 3] = 0xff;
1641 }
1642
1643 data_format = RawImageFormat::BGRA8;
1644 px.into()
1645 }
1646 RawImageFormat::RGBA8 => {
1647 let mut pixels: Vec<u8> = pixels.get_u8_vec()?.into_library_owned_vec();
1648
1649 if pixels.len() != expected_len * FOUR_CHANNELS {
1650 return None;
1651 }
1652
1653 if premultiplied_alpha {
1656 for rgba in pixels.chunks_exact_mut(4) {
1657 let (r, gba) = rgba.split_first_mut()?;
1658 core::mem::swap(r, gba.get_mut(1)?);
1659 let a = rgba.get_mut(3)?;
1660 if *a != 255 {
1661 is_opaque = false;
1662 }
1663 }
1664 } else {
1665 for rgba in pixels.chunks_exact_mut(4) {
1666 let (r, gba) = rgba.split_first_mut()?;
1668 core::mem::swap(r, gba.get_mut(1)?);
1669 let a = rgba.get_mut(3)?;
1670 if *a != 255 {
1671 is_opaque = false;
1672 }
1673 premultiply_alpha(rgba); }
1675 }
1676
1677 data_format = RawImageFormat::BGRA8;
1678 pixels.into()
1679 }
1680 RawImageFormat::R16 => {
1681 let pixels = pixels.get_u16_vec()?;
1682
1683 if pixels.len() != expected_len {
1684 return None;
1685 }
1686
1687 let mut px = vec![0; expected_len * FOUR_BPP];
1688
1689 for (pixel_index, grey_u16) in pixels.as_ref().iter().enumerate() {
1691 let grey_u8 = normalize_u16(*grey_u16);
1692 px[pixel_index * FOUR_BPP] = grey_u8;
1693 px[(pixel_index * FOUR_BPP) + 1] = grey_u8;
1694 px[(pixel_index * FOUR_BPP) + 2] = grey_u8;
1695 px[(pixel_index * FOUR_BPP) + 3] = 0xff;
1696 }
1697
1698 data_format = RawImageFormat::BGRA8;
1699 px.into()
1700 }
1701 RawImageFormat::RG16 => {
1702 let pixels = pixels.get_u16_vec()?;
1703
1704 if pixels.len() != expected_len * TWO_CHANNELS {
1705 return None;
1706 }
1707
1708 let mut px = vec![0; expected_len * FOUR_BPP];
1709
1710 for (pixel_index, greyalpha) in
1712 pixels.as_ref().chunks_exact(TWO_CHANNELS).enumerate()
1713 {
1714 let grey_u8 = normalize_u16(greyalpha[0]);
1715 let alpha_u8 = normalize_u16(greyalpha[1]);
1716
1717 if alpha_u8 != 255 {
1718 is_opaque = false;
1719 }
1720
1721 px[pixel_index * FOUR_BPP] = grey_u8;
1722 px[(pixel_index * FOUR_BPP) + 1] = grey_u8;
1723 px[(pixel_index * FOUR_BPP) + 2] = grey_u8;
1724 px[(pixel_index * FOUR_BPP) + 3] = alpha_u8;
1725 }
1726
1727 data_format = RawImageFormat::BGRA8;
1728 px.into()
1729 }
1730 RawImageFormat::RGB16 => {
1731 let pixels = pixels.get_u16_vec()?;
1732
1733 if pixels.len() != expected_len * THREE_CHANNELS {
1734 return None;
1735 }
1736
1737 let mut px = vec![0; expected_len * FOUR_BPP];
1738
1739 for (pixel_index, rgb) in pixels.as_ref().chunks_exact(THREE_CHANNELS).enumerate() {
1741 let red_u8 = normalize_u16(rgb[0]);
1742 let green_u8 = normalize_u16(rgb[1]);
1743 let blue_u8 = normalize_u16(rgb[2]);
1744
1745 px[pixel_index * FOUR_BPP] = blue_u8;
1746 px[(pixel_index * FOUR_BPP) + 1] = green_u8;
1747 px[(pixel_index * FOUR_BPP) + 2] = red_u8;
1748 px[(pixel_index * FOUR_BPP) + 3] = 0xff;
1749 }
1750
1751 data_format = RawImageFormat::BGRA8;
1752 px.into()
1753 }
1754 RawImageFormat::RGBA16 => {
1755 let pixels = pixels.get_u16_vec()?;
1756
1757 if pixels.len() != expected_len * FOUR_CHANNELS {
1758 return None;
1759 }
1760
1761 let mut px = vec![0; expected_len * FOUR_BPP];
1762
1763 if premultiplied_alpha {
1765 for (pixel_index, rgba) in
1766 pixels.as_ref().chunks_exact(FOUR_CHANNELS).enumerate()
1767 {
1768 let red_u8 = normalize_u16(rgba[0]);
1769 let green_u8 = normalize_u16(rgba[1]);
1770 let blue_u8 = normalize_u16(rgba[2]);
1771 let alpha_u8 = normalize_u16(rgba[3]);
1772
1773 if alpha_u8 != 255 {
1774 is_opaque = false;
1775 }
1776
1777 px[pixel_index * FOUR_BPP] = blue_u8;
1778 px[(pixel_index * FOUR_BPP) + 1] = green_u8;
1779 px[(pixel_index * FOUR_BPP) + 2] = red_u8;
1780 px[(pixel_index * FOUR_BPP) + 3] = alpha_u8;
1781 }
1782 } else {
1783 for (pixel_index, rgba) in
1784 pixels.as_ref().chunks_exact(FOUR_CHANNELS).enumerate()
1785 {
1786 let red_u8 = normalize_u16(rgba[0]);
1787 let green_u8 = normalize_u16(rgba[1]);
1788 let blue_u8 = normalize_u16(rgba[2]);
1789 let alpha_u8 = normalize_u16(rgba[3]);
1790
1791 if alpha_u8 != 255 {
1792 is_opaque = false;
1793 }
1794
1795 px[pixel_index * FOUR_BPP] = blue_u8;
1796 px[(pixel_index * FOUR_BPP) + 1] = green_u8;
1797 px[(pixel_index * FOUR_BPP) + 2] = red_u8;
1798 px[(pixel_index * FOUR_BPP) + 3] = alpha_u8;
1799 premultiply_alpha(
1800 &mut px
1801 [(pixel_index * FOUR_BPP)..((pixel_index * FOUR_BPP) + FOUR_BPP)],
1802 );
1803 }
1804 }
1805
1806 data_format = RawImageFormat::BGRA8;
1807 px.into()
1808 }
1809 RawImageFormat::BGR8 => {
1810 let pixels = pixels.get_u8_vec()?;
1811
1812 if pixels.len() != expected_len * THREE_CHANNELS {
1813 return None;
1814 }
1815
1816 let mut px = vec![0; expected_len * FOUR_BPP];
1817
1818 for (pixel_index, bgr) in pixels.as_ref().chunks_exact(THREE_CHANNELS).enumerate() {
1820 let blue = bgr[0];
1821 let green = bgr[1];
1822 let red = bgr[2];
1823
1824 px[pixel_index * FOUR_BPP] = blue;
1825 px[(pixel_index * FOUR_BPP) + 1] = green;
1826 px[(pixel_index * FOUR_BPP) + 2] = red;
1827 px[(pixel_index * FOUR_BPP) + 3] = 0xff;
1828 }
1829
1830 data_format = RawImageFormat::BGRA8;
1831 px.into()
1832 }
1833 RawImageFormat::BGRA8 => {
1834 if premultiplied_alpha {
1835 let pixels = pixels.get_u8_vec()?;
1837
1838 is_opaque = pixels
1839 .as_ref()
1840 .chunks_exact(FOUR_CHANNELS)
1841 .all(|bgra| bgra[3] == 255);
1842
1843 pixels
1844 } else {
1845 let mut pixels: Vec<u8> = pixels.get_u8_vec()?.into_library_owned_vec();
1846
1847 if pixels.len() != expected_len * FOUR_BPP {
1848 return None;
1849 }
1850
1851 for bgra in pixels.chunks_exact_mut(FOUR_CHANNELS) {
1852 if bgra[3] != 255 {
1853 is_opaque = false;
1854 }
1855 premultiply_alpha(bgra);
1856 }
1857 data_format = RawImageFormat::BGRA8;
1858 pixels.into()
1859 }
1860 }
1861 RawImageFormat::RGBF32 => {
1862 let pixels = pixels.get_f32_vec_ref()?;
1863
1864 if pixels.len() != expected_len * THREE_CHANNELS {
1865 return None;
1866 }
1867
1868 let mut px = vec![0; expected_len * FOUR_BPP];
1869
1870 for (pixel_index, rgb) in pixels.as_ref().chunks_exact(THREE_CHANNELS).enumerate() {
1872 let red_u8 = (rgb[0] * 255.0) as u8;
1873 let green_u8 = (rgb[1] * 255.0) as u8;
1874 let blue_u8 = (rgb[2] * 255.0) as u8;
1875
1876 px[pixel_index * FOUR_BPP] = blue_u8;
1877 px[(pixel_index * FOUR_BPP) + 1] = green_u8;
1878 px[(pixel_index * FOUR_BPP) + 2] = red_u8;
1879 px[(pixel_index * FOUR_BPP) + 3] = 0xff;
1880 }
1881
1882 data_format = RawImageFormat::BGRA8;
1883 px.into()
1884 }
1885 RawImageFormat::RGBAF32 => {
1886 let pixels = pixels.get_f32_vec_ref()?;
1887
1888 if pixels.len() != expected_len * FOUR_CHANNELS {
1889 return None;
1890 }
1891
1892 let mut px = vec![0; expected_len * FOUR_BPP];
1893
1894 if premultiplied_alpha {
1896 for (pixel_index, rgba) in
1897 pixels.as_ref().chunks_exact(FOUR_CHANNELS).enumerate()
1898 {
1899 let red_u8 = (rgba[0] * 255.0) as u8;
1900 let green_u8 = (rgba[1] * 255.0) as u8;
1901 let blue_u8 = (rgba[2] * 255.0) as u8;
1902 let alpha_u8 = (rgba[3] * 255.0) as u8;
1903
1904 if alpha_u8 != 255 {
1905 is_opaque = false;
1906 }
1907
1908 px[pixel_index * FOUR_BPP] = blue_u8;
1909 px[(pixel_index * FOUR_BPP) + 1] = green_u8;
1910 px[(pixel_index * FOUR_BPP) + 2] = red_u8;
1911 px[(pixel_index * FOUR_BPP) + 3] = alpha_u8;
1912 }
1913 } else {
1914 for (pixel_index, rgba) in
1915 pixels.as_ref().chunks_exact(FOUR_CHANNELS).enumerate()
1916 {
1917 let red_u8 = (rgba[0] * 255.0) as u8;
1918 let green_u8 = (rgba[1] * 255.0) as u8;
1919 let blue_u8 = (rgba[2] * 255.0) as u8;
1920 let alpha_u8 = (rgba[3] * 255.0) as u8;
1921
1922 if alpha_u8 != 255 {
1923 is_opaque = false;
1924 }
1925
1926 px[pixel_index * FOUR_BPP] = blue_u8;
1927 px[(pixel_index * FOUR_BPP) + 1] = green_u8;
1928 px[(pixel_index * FOUR_BPP) + 2] = red_u8;
1929 px[(pixel_index * FOUR_BPP) + 3] = alpha_u8;
1930 premultiply_alpha(
1931 &mut px
1932 [(pixel_index * FOUR_BPP)..((pixel_index * FOUR_BPP) + FOUR_BPP)],
1933 );
1934 }
1935 }
1936
1937 data_format = RawImageFormat::BGRA8;
1938 px.into()
1939 }
1940 };
1941
1942 let image_data = ImageData::Raw(bytes);
1943 let image_descriptor = ImageDescriptor {
1944 format: data_format,
1945 width,
1946 height,
1947 offset: 0,
1948 stride: None.into(),
1949 flags: ImageDescriptorFlags {
1950 is_opaque,
1951 allow_mipmaps: true,
1952 },
1953 };
1954
1955 Some((image_data, image_descriptor))
1956 }
1957}
1958
1959impl_option!(
1960 RawImage,
1961 OptionRawImage,
1962 copy = false,
1963 [Debug, Clone, PartialEq, PartialOrd]
1964);
1965
1966#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1968#[repr(C)]
1969pub struct Words {
1970 pub items: WordVec,
1972 pub internal_str: AzString,
1974 pub internal_chars: U32Vec,
1977}
1978
1979impl Words {
1980 pub fn get_substr(&self, word: &Word) -> String {
1981 self.internal_chars.as_ref()[word.start..word.end]
1982 .iter()
1983 .filter_map(|c| core::char::from_u32(*c))
1984 .collect()
1985 }
1986
1987 pub fn get_str(&self) -> &str {
1988 &self.internal_str.as_str()
1989 }
1990
1991 pub fn get_char(&self, idx: usize) -> Option<char> {
1992 self.internal_chars
1993 .as_ref()
1994 .get(idx)
1995 .and_then(|c| core::char::from_u32(*c))
1996 }
1997}
1998
1999#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2001#[repr(C)]
2002pub struct Word {
2003 pub start: usize,
2004 pub end: usize,
2005 pub word_type: WordType,
2006}
2007
2008impl_vec!(Word, WordVec, WordVecDestructor);
2009impl_vec_clone!(Word, WordVec, WordVecDestructor);
2010impl_vec_debug!(Word, WordVec);
2011impl_vec_partialeq!(Word, WordVec);
2012impl_vec_eq!(Word, WordVec);
2013impl_vec_ord!(Word, WordVec);
2014impl_vec_partialord!(Word, WordVec);
2015impl_vec_hash!(Word, WordVec);
2016
2017#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2019#[repr(C)]
2020pub enum WordType {
2021 Word,
2023 Tab,
2025 Return,
2027 Space,
2029}
2030
2031#[derive(Debug, Clone)]
2034#[repr(C)]
2035pub struct ShapedWords {
2036 pub items: ShapedWordVec,
2038 pub longest_word_width: usize,
2041 pub space_advance: usize,
2043 pub font_metrics_units_per_em: u16,
2045 pub font_metrics_ascender: i16,
2047 pub font_metrics_descender: i16,
2048 pub font_metrics_line_gap: i16,
2049}
2050
2051impl ShapedWords {
2052 pub fn get_longest_word_width_px(&self, target_font_size: f32) -> f32 {
2053 self.longest_word_width as f32 / self.font_metrics_units_per_em as f32 * target_font_size
2054 }
2055 pub fn get_space_advance_px(&self, target_font_size: f32) -> f32 {
2056 self.space_advance as f32 / self.font_metrics_units_per_em as f32 * target_font_size
2057 }
2058 pub fn get_baseline_px(&self, target_font_size: f32) -> f32 {
2060 target_font_size + self.get_descender(target_font_size)
2061 }
2062 pub fn get_descender(&self, target_font_size: f32) -> f32 {
2064 self.font_metrics_descender as f32 / self.font_metrics_units_per_em as f32
2065 * target_font_size
2066 }
2067
2068 pub fn get_line_height(&self, target_font_size: f32) -> f32 {
2070 self.font_metrics_ascender as f32 / self.font_metrics_units_per_em as f32
2071 - self.font_metrics_descender as f32 / self.font_metrics_units_per_em as f32
2072 + self.font_metrics_line_gap as f32 / self.font_metrics_units_per_em as f32
2073 * target_font_size
2074 }
2075
2076 pub fn get_ascender(&self, target_font_size: f32) -> f32 {
2077 self.font_metrics_ascender as f32 / self.font_metrics_units_per_em as f32 * target_font_size
2078 }
2079}
2080
2081#[derive(Debug, Copy, PartialEq, PartialOrd, Clone, Hash)]
2085#[repr(C)]
2086pub enum VariationSelector {
2087 VS01 = 1,
2089 VS02 = 2,
2091 VS03 = 3,
2093 VS15 = 15,
2095 VS16 = 16,
2097}
2098
2099impl_option!(
2100 VariationSelector,
2101 OptionVariationSelector,
2102 [Debug, Copy, PartialEq, PartialOrd, Clone, Hash]
2103);
2104
2105#[derive(Debug, Copy, PartialEq, PartialOrd, Clone, Hash)]
2106#[repr(C, u8)]
2107pub enum GlyphOrigin {
2108 Char(char),
2109 Direct,
2110}
2111
2112#[derive(Debug, Copy, PartialEq, PartialOrd, Clone, Hash)]
2113#[repr(C)]
2114pub struct PlacementDistance {
2115 pub x: i32,
2116 pub y: i32,
2117}
2118
2119#[derive(Debug, Copy, PartialEq, PartialOrd, Clone, Hash)]
2122#[repr(C, u8)]
2123pub enum Placement {
2124 None,
2125 Distance(PlacementDistance),
2126 MarkAnchor(MarkAnchorPlacement),
2127 MarkOverprint(usize),
2133 CursiveAnchor(CursiveAnchorPlacement),
2134}
2135
2136#[derive(Debug, Copy, PartialEq, PartialOrd, Clone, Hash)]
2140#[repr(C)]
2141pub struct CursiveAnchorPlacement {
2142 pub exit_glyph_index: usize,
2144 pub right_to_left: bool,
2146 pub exit_glyph_anchor: Anchor,
2148 pub entry_glyph_anchor: Anchor,
2150}
2151
2152#[derive(Debug, Copy, PartialEq, PartialOrd, Clone, Hash)]
2156#[repr(C)]
2157pub struct MarkAnchorPlacement {
2158 pub base_glyph_index: usize,
2160 pub base_glyph_anchor: Anchor,
2162 pub mark_anchor: Anchor,
2164}
2165
2166#[derive(Debug, Copy, PartialEq, PartialOrd, Clone, Hash)]
2167#[repr(C)]
2168pub struct Anchor {
2169 pub x: i16,
2170 pub y: i16,
2171}
2172
2173#[derive(Debug, Copy, PartialEq, PartialOrd, Clone, Hash)]
2174#[repr(C)]
2175pub struct RawGlyph {
2176 pub unicode_codepoint: OptionChar, pub glyph_index: u16,
2178 pub liga_component_pos: u16,
2179 pub glyph_origin: GlyphOrigin,
2180 pub small_caps: bool,
2181 pub multi_subst_dup: bool,
2182 pub is_vert_alt: bool,
2183 pub fake_bold: bool,
2184 pub fake_italic: bool,
2185 pub variation: OptionVariationSelector,
2186}
2187
2188impl RawGlyph {
2189 pub fn has_codepoint(&self) -> bool {
2190 self.unicode_codepoint.is_some()
2191 }
2192
2193 pub fn get_codepoint(&self) -> Option<char> {
2194 self.unicode_codepoint
2195 .as_ref()
2196 .and_then(|u| core::char::from_u32(*u))
2197 }
2198}
2199
2200#[derive(Debug, PartialEq, PartialOrd, Clone, Hash)]
2201#[repr(C)]
2202pub struct GlyphInfo {
2203 pub glyph: RawGlyph,
2204 pub size: Advance,
2205 pub kerning: i16,
2206 pub placement: Placement,
2207}
2208
2209pub fn get_inline_text(
2210 words: &Words,
2211 shaped_words: &ShapedWords,
2212 word_positions: &WordPositions,
2213 inline_text_layout: &InlineTextLayout,
2214) -> InlineText {
2215 use crate::callbacks::{InlineGlyph, InlineLine, InlineTextContents, InlineWord};
2216
2217 fn get_range_checked_inclusive_end(
2219 input: &[Word],
2220 word_start: usize,
2221 word_end: usize,
2222 ) -> Option<&[Word]> {
2223 if word_start < input.len() && word_end < input.len() && word_start <= word_end {
2224 Some(&input[word_start..=word_end])
2225 } else {
2226 None
2227 }
2228 }
2229
2230 let font_size_px = word_positions.text_layout_options.font_size_px;
2231 let descender_px = &shaped_words.get_descender(font_size_px); let letter_spacing_px = word_positions
2233 .text_layout_options
2234 .letter_spacing
2235 .as_ref()
2236 .copied()
2237 .unwrap_or(0.0);
2238 let units_per_em = shaped_words.font_metrics_units_per_em;
2239
2240 let inline_lines = inline_text_layout
2241 .lines
2242 .as_ref()
2243 .iter()
2244 .filter_map(|line| {
2245 let word_items = words.items.as_ref();
2246 let word_start = line.word_start.min(line.word_end);
2247 let word_end = line.word_end.max(line.word_start);
2248
2249 let words = get_range_checked_inclusive_end(word_items, word_start, word_end)?
2250 .iter()
2251 .enumerate()
2252 .filter_map(|(word_idx, word)| {
2253 let word_idx = word_start + word_idx;
2254 match word.word_type {
2255 WordType::Word => {
2256 let word_position = word_positions.word_positions.get(word_idx)?;
2257 let shaped_word_index = word_position.shaped_word_index?;
2258 let shaped_word = shaped_words.items.get(shaped_word_index)?;
2259
2260 let mut all_glyphs_in_this_word = Vec::<InlineGlyph>::with_capacity(16);
2263 let mut x_pos_in_word_px = 0.0;
2264
2265 for glyph_info in shaped_word.glyph_infos.iter() {
2268 let mut displacement = LogicalPosition::zero();
2271
2272 let (letter_spacing_for_glyph, origin) = match glyph_info.placement
2276 {
2277 Placement::None => (
2278 letter_spacing_px,
2279 LogicalPosition::new(
2280 x_pos_in_word_px + displacement.x,
2281 displacement.y,
2282 ),
2283 ),
2284 Placement::Distance(PlacementDistance { x, y }) => {
2285 let font_metrics_divisor =
2286 units_per_em as f32 / font_size_px;
2287 displacement = LogicalPosition {
2288 x: x as f32 / font_metrics_divisor,
2289 y: y as f32 / font_metrics_divisor,
2290 };
2291 (
2292 letter_spacing_px,
2293 LogicalPosition::new(
2294 x_pos_in_word_px + displacement.x,
2295 displacement.y,
2296 ),
2297 )
2298 }
2299 Placement::MarkAnchor(MarkAnchorPlacement {
2300 base_glyph_index,
2301 ..
2302 }) => {
2303 let anchor = &all_glyphs_in_this_word[base_glyph_index];
2304 (0.0, anchor.bounds.origin + displacement)
2305 }
2307 Placement::MarkOverprint(index) => {
2308 let anchor = &all_glyphs_in_this_word[index];
2309 (0.0, anchor.bounds.origin + displacement)
2310 }
2311 Placement::CursiveAnchor(CursiveAnchorPlacement {
2312 exit_glyph_index,
2313 ..
2314 }) => {
2315 let anchor = &all_glyphs_in_this_word[exit_glyph_index];
2316 (0.0, anchor.bounds.origin + displacement)
2317 }
2319 };
2320
2321 let glyph_scale_x = glyph_info
2322 .size
2323 .get_x_size_scaled(units_per_em, font_size_px);
2324 let glyph_scale_y = glyph_info
2325 .size
2326 .get_y_size_scaled(units_per_em, font_size_px);
2327
2328 let glyph_advance_x = glyph_info
2329 .size
2330 .get_x_advance_scaled(units_per_em, font_size_px);
2331 let kerning_x = glyph_info
2332 .size
2333 .get_kerning_scaled(units_per_em, font_size_px);
2334
2335 let inline_char = InlineGlyph {
2336 bounds: LogicalRect::new(
2337 origin,
2338 LogicalSize::new(glyph_scale_x, glyph_scale_y),
2339 ),
2340 unicode_codepoint: glyph_info.glyph.unicode_codepoint,
2341 glyph_index: glyph_info.glyph.glyph_index as u32,
2342 };
2343
2344 x_pos_in_word_px +=
2345 glyph_advance_x + kerning_x + letter_spacing_for_glyph;
2346
2347 all_glyphs_in_this_word.push(inline_char);
2348 }
2349
2350 let inline_word = InlineWord::Word(InlineTextContents {
2351 glyphs: all_glyphs_in_this_word.into(),
2352 bounds: LogicalRect::new(
2353 word_position.position,
2354 word_position.size,
2355 ),
2356 });
2357
2358 Some(inline_word)
2359 }
2360 WordType::Tab => Some(InlineWord::Tab),
2361 WordType::Return => Some(InlineWord::Return),
2362 WordType::Space => Some(InlineWord::Space),
2363 }
2364 })
2365 .collect::<Vec<InlineWord>>();
2366
2367 Some(InlineLine {
2368 words: words.into(),
2369 bounds: line.bounds,
2370 })
2371 })
2372 .collect::<Vec<InlineLine>>();
2373
2374 InlineText {
2375 lines: inline_lines.into(), content_size: word_positions.content_size,
2377 font_size_px,
2378 last_word_index: word_positions.number_of_shaped_words,
2379 baseline_descender_px: *descender_px,
2380 }
2381}
2382
2383impl_vec!(GlyphInfo, GlyphInfoVec, GlyphInfoVecDestructor);
2384impl_vec_clone!(GlyphInfo, GlyphInfoVec, GlyphInfoVecDestructor);
2385impl_vec_debug!(GlyphInfo, GlyphInfoVec);
2386impl_vec_partialeq!(GlyphInfo, GlyphInfoVec);
2387impl_vec_partialord!(GlyphInfo, GlyphInfoVec);
2388impl_vec_hash!(GlyphInfo, GlyphInfoVec);
2389
2390#[derive(Debug, Default, Copy, PartialEq, PartialOrd, Clone, Hash)]
2391#[repr(C)]
2392pub struct Advance {
2393 pub advance_x: u16,
2394 pub size_x: i32,
2395 pub size_y: i32,
2396 pub kerning: i16,
2397}
2398
2399impl Advance {
2400 #[inline]
2401 pub const fn get_x_advance_total_unscaled(&self) -> i32 {
2402 self.advance_x as i32 + self.kerning as i32
2403 }
2404 #[inline]
2405 pub const fn get_x_advance_unscaled(&self) -> u16 {
2406 self.advance_x
2407 }
2408 #[inline]
2409 pub const fn get_x_size_unscaled(&self) -> i32 {
2410 self.size_x
2411 }
2412 #[inline]
2413 pub const fn get_y_size_unscaled(&self) -> i32 {
2414 self.size_y
2415 }
2416 #[inline]
2417 pub const fn get_kerning_unscaled(&self) -> i16 {
2418 self.kerning
2419 }
2420
2421 #[inline]
2422 pub fn get_x_advance_total_scaled(&self, units_per_em: u16, target_font_size: f32) -> f32 {
2423 self.get_x_advance_total_unscaled() as f32 / units_per_em as f32 * target_font_size
2424 }
2425 #[inline]
2426 pub fn get_x_advance_scaled(&self, units_per_em: u16, target_font_size: f32) -> f32 {
2427 self.get_x_advance_unscaled() as f32 / units_per_em as f32 * target_font_size
2428 }
2429 #[inline]
2430 pub fn get_x_size_scaled(&self, units_per_em: u16, target_font_size: f32) -> f32 {
2431 self.get_x_size_unscaled() as f32 / units_per_em as f32 * target_font_size
2432 }
2433 #[inline]
2434 pub fn get_y_size_scaled(&self, units_per_em: u16, target_font_size: f32) -> f32 {
2435 self.get_y_size_unscaled() as f32 / units_per_em as f32 * target_font_size
2436 }
2437 #[inline]
2438 pub fn get_kerning_scaled(&self, units_per_em: u16, target_font_size: f32) -> f32 {
2439 self.get_kerning_unscaled() as f32 / units_per_em as f32 * target_font_size
2440 }
2441}
2442
2443#[derive(PartialEq, PartialOrd, Clone)]
2445#[repr(C)]
2446pub struct ShapedWord {
2447 pub glyph_infos: GlyphInfoVec,
2449 pub word_width: usize,
2451}
2452
2453impl fmt::Debug for ShapedWord {
2454 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2455 write!(
2456 f,
2457 "ShapedWord {{ glyph_infos: {} glyphs, word_width: {} }}",
2458 self.glyph_infos.len(),
2459 self.word_width
2460 )
2461 }
2462}
2463
2464impl_vec!(ShapedWord, ShapedWordVec, ShapedWordVecDestructor);
2465impl_vec_clone!(ShapedWord, ShapedWordVec, ShapedWordVecDestructor);
2466impl_vec_partialeq!(ShapedWord, ShapedWordVec);
2467impl_vec_partialord!(ShapedWord, ShapedWordVec);
2468impl_vec_debug!(ShapedWord, ShapedWordVec);
2469
2470impl ShapedWord {
2471 pub fn get_word_width(&self, units_per_em: u16, target_font_size: f32) -> f32 {
2472 self.word_width as f32 / units_per_em as f32 * target_font_size
2473 }
2474 pub fn number_of_glyphs(&self) -> usize {
2476 self.glyph_infos
2477 .iter()
2478 .filter(|i| i.placement == Placement::None)
2479 .count()
2480 }
2481}
2482
2483#[derive(Debug, Clone, PartialEq)]
2485pub struct WordPositions {
2486 pub text_layout_options: ResolvedTextLayoutOptions,
2489 pub word_positions: Vec<WordPosition>,
2491 pub line_breaks: Vec<InlineTextLine>,
2494 pub trailing: f32,
2500 pub number_of_shaped_words: usize,
2502 pub number_of_lines: usize,
2504 pub content_size: LogicalSize,
2509}
2510
2511#[derive(Debug, Clone, PartialEq)]
2512pub struct WordPosition {
2513 pub shaped_word_index: Option<usize>,
2514 pub position: LogicalPosition,
2515 pub size: LogicalSize,
2516}
2517
2518#[derive(Debug, Clone, PartialEq)]
2520pub struct LayoutedGlyphs {
2521 pub glyphs: Vec<GlyphInstance>,
2522}
2523
2524pub fn add_fonts_and_images(
2528 image_cache: &ImageCache,
2529 renderer_resources: &mut RendererResources,
2530 current_window_dpi: DpiScaleFactor,
2531 fc_cache: &FcFontCache,
2532 render_api_namespace: IdNamespace,
2533 epoch: Epoch,
2534 document_id: &DocumentId,
2535 all_resource_updates: &mut Vec<ResourceUpdate>,
2536 styled_dom: &StyledDom,
2537 load_font_fn: LoadFontFn,
2538 parse_font_fn: ParseFontFn,
2539 insert_into_active_gl_textures: GlStoreImageFn,
2540) {
2541 let new_image_keys = styled_dom.scan_for_image_keys(&image_cache);
2542 let new_font_keys = styled_dom.scan_for_font_keys(&renderer_resources);
2543
2544 let add_image_resource_updates = build_add_image_resource_updates(
2545 renderer_resources,
2546 render_api_namespace,
2547 epoch,
2548 document_id,
2549 &new_image_keys,
2550 insert_into_active_gl_textures,
2551 );
2552
2553 let add_font_resource_updates = build_add_font_resource_updates(
2554 renderer_resources,
2555 current_window_dpi,
2556 fc_cache,
2557 render_api_namespace,
2558 &new_font_keys,
2559 load_font_fn,
2560 parse_font_fn,
2561 );
2562
2563 add_resources(
2564 renderer_resources,
2565 all_resource_updates,
2566 add_font_resource_updates,
2567 add_image_resource_updates,
2568 );
2569}
2570
2571pub fn font_size_to_au(font_size: StyleFontSize) -> Au {
2572 use crate::ui_solver::DEFAULT_FONT_SIZE_PX;
2573 Au::from_px(font_size.inner.to_pixels(DEFAULT_FONT_SIZE_PX as f32))
2574}
2575
2576pub type FontInstanceFlags = u32;
2577
2578pub const FONT_INSTANCE_FLAG_SYNTHETIC_BOLD: u32 = 1 << 1;
2580pub const FONT_INSTANCE_FLAG_EMBEDDED_BITMAPS: u32 = 1 << 2;
2581pub const FONT_INSTANCE_FLAG_SUBPIXEL_BGR: u32 = 1 << 3;
2582pub const FONT_INSTANCE_FLAG_TRANSPOSE: u32 = 1 << 4;
2583pub const FONT_INSTANCE_FLAG_FLIP_X: u32 = 1 << 5;
2584pub const FONT_INSTANCE_FLAG_FLIP_Y: u32 = 1 << 6;
2585pub const FONT_INSTANCE_FLAG_SUBPIXEL_POSITION: u32 = 1 << 7;
2586
2587pub const FONT_INSTANCE_FLAG_FORCE_GDI: u32 = 1 << 16;
2589
2590pub const FONT_INSTANCE_FLAG_FONT_SMOOTHING: u32 = 1 << 16;
2592
2593pub const FONT_INSTANCE_FLAG_FORCE_AUTOHINT: u32 = 1 << 16;
2595pub const FONT_INSTANCE_FLAG_NO_AUTOHINT: u32 = 1 << 17;
2596pub const FONT_INSTANCE_FLAG_VERTICAL_LAYOUT: u32 = 1 << 18;
2597pub const FONT_INSTANCE_FLAG_LCD_VERTICAL: u32 = 1 << 19;
2598
2599#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
2600pub struct GlyphOptions {
2601 pub render_mode: FontRenderMode,
2602 pub flags: FontInstanceFlags,
2603}
2604
2605#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
2606pub enum FontRenderMode {
2607 Mono,
2608 Alpha,
2609 Subpixel,
2610}
2611
2612#[cfg(target_arch = "wasm32")]
2613#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
2614pub struct FontInstancePlatformOptions {
2615 }
2617
2618#[cfg(target_os = "windows")]
2619#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
2620pub struct FontInstancePlatformOptions {
2621 pub gamma: u16,
2622 pub contrast: u8,
2623 pub cleartype_level: u8,
2624}
2625
2626#[cfg(target_os = "macos")]
2627#[derive(Default, Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
2628pub struct FontInstancePlatformOptions {
2629 pub unused: u32,
2630}
2631
2632#[cfg(target_os = "linux")]
2633#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
2634pub struct FontInstancePlatformOptions {
2635 pub lcd_filter: FontLCDFilter,
2636 pub hinting: FontHinting,
2637}
2638
2639#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
2640pub enum FontHinting {
2641 None,
2642 Mono,
2643 Light,
2644 Normal,
2645 LCD,
2646}
2647
2648#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
2649pub enum FontLCDFilter {
2650 None,
2651 Default,
2652 Light,
2653 Legacy,
2654}
2655
2656impl Default for FontLCDFilter {
2657 fn default() -> Self {
2658 FontLCDFilter::Default
2659 }
2660}
2661
2662#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
2663pub struct FontInstanceOptions {
2664 pub render_mode: FontRenderMode,
2665 pub flags: FontInstanceFlags,
2666 pub bg_color: ColorU,
2667 pub synthetic_italics: SyntheticItalics,
2671}
2672
2673impl Default for FontInstanceOptions {
2674 fn default() -> FontInstanceOptions {
2675 FontInstanceOptions {
2676 render_mode: FontRenderMode::Subpixel,
2677 flags: 0,
2678 bg_color: ColorU::TRANSPARENT,
2679 synthetic_italics: SyntheticItalics::default(),
2680 }
2681 }
2682}
2683
2684#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
2685pub struct SyntheticItalics {
2686 pub angle: i16,
2687}
2688
2689impl Default for SyntheticItalics {
2690 fn default() -> Self {
2691 Self { angle: 0 }
2692 }
2693}
2694
2695#[derive(Debug, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
2698#[repr(C, u8)]
2699pub enum ImageData {
2700 Raw(U8Vec),
2703 External(ExternalImageData),
2706}
2707
2708#[derive(Debug, Copy, Clone, Eq, Hash, PartialEq, PartialOrd, Ord)]
2710#[repr(C, u8)]
2711pub enum ExternalImageType {
2712 TextureHandle(ImageBufferKind),
2714 Buffer,
2716}
2717
2718#[repr(C)]
2722#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, PartialOrd, Ord)]
2723pub struct ExternalImageId {
2724 pub inner: u64,
2725}
2726
2727static LAST_EXTERNAL_IMAGE_ID: AtomicUsize = AtomicUsize::new(0);
2728
2729impl ExternalImageId {
2730 pub fn new() -> Self {
2732 Self {
2733 inner: LAST_EXTERNAL_IMAGE_ID.fetch_add(1, AtomicOrdering::SeqCst) as u64,
2734 }
2735 }
2736}
2737
2738#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
2740#[repr(C)]
2741pub enum ImageBufferKind {
2742 Texture2D = 0,
2744 TextureRect = 1,
2751 TextureExternal = 2,
2756}
2757
2758#[repr(C)]
2760#[derive(Debug, Clone, Eq, Hash, PartialEq, PartialOrd, Ord)]
2761pub struct ExternalImageData {
2762 pub id: ExternalImageId,
2764 pub channel_index: u8,
2767 pub image_type: ExternalImageType,
2769}
2770
2771pub type TileSize = u16;
2772
2773#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
2774pub enum ImageDirtyRect {
2775 All,
2776 Partial(LayoutRect),
2777}
2778
2779#[derive(Debug, Clone, PartialEq, PartialOrd)]
2780pub enum ResourceUpdate {
2781 AddFont(AddFont),
2782 DeleteFont(FontKey),
2783 AddFontInstance(AddFontInstance),
2784 DeleteFontInstance(FontInstanceKey),
2785 AddImage(AddImage),
2786 UpdateImage(UpdateImage),
2787 DeleteImage(ImageKey),
2788}
2789
2790#[derive(Debug, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
2791pub struct AddImage {
2792 pub key: ImageKey,
2793 pub descriptor: ImageDescriptor,
2794 pub data: ImageData,
2795 pub tiling: Option<TileSize>,
2796}
2797
2798#[derive(Debug, Clone, PartialEq, PartialOrd)]
2799pub struct UpdateImage {
2800 pub key: ImageKey,
2801 pub descriptor: ImageDescriptor,
2802 pub data: ImageData,
2803 pub dirty_rect: ImageDirtyRect,
2804}
2805
2806#[derive(Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
2807pub struct AddFont {
2808 pub key: FontKey,
2809 pub font_bytes: U8Vec,
2810 pub font_index: u32,
2811}
2812
2813impl fmt::Debug for AddFont {
2814 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2815 write!(
2816 f,
2817 "AddFont {{ key: {:?}, font_bytes: [u8;{}], font_index: {} }}",
2818 self.key,
2819 self.font_bytes.len(),
2820 self.font_index
2821 )
2822 }
2823}
2824
2825#[derive(Debug, Clone, PartialEq, PartialOrd)]
2826pub struct AddFontInstance {
2827 pub key: FontInstanceKey,
2828 pub font_key: FontKey,
2829 pub glyph_size: (Au, DpiScaleFactor),
2830 pub options: Option<FontInstanceOptions>,
2831 pub platform_options: Option<FontInstancePlatformOptions>,
2832 pub variations: Vec<FontVariation>,
2833}
2834
2835#[repr(C)]
2836#[derive(Clone, Copy, Debug, PartialOrd, PartialEq)]
2837pub struct FontVariation {
2838 pub tag: u32,
2839 pub value: f32,
2840}
2841
2842#[repr(C)]
2843#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
2844pub struct Epoch {
2845 inner: u32,
2846}
2847
2848impl fmt::Display for Epoch {
2849 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2850 write!(f, "{}", self.inner)
2851 }
2852}
2853
2854impl Epoch {
2855 pub const fn new() -> Self {
2859 Self { inner: 0 }
2860 }
2861 pub const fn from(i: u32) -> Self {
2862 Self { inner: i }
2863 }
2864 pub const fn into_u32(&self) -> u32 {
2865 self.inner
2866 }
2867
2868 pub fn increment(&mut self) {
2871 use core::u32;
2872 const MAX_ID: u32 = u32::MAX - 1;
2873 *self = match self.inner {
2874 MAX_ID => Epoch { inner: 0 },
2875 other => Epoch {
2876 inner: other.saturating_add(1),
2877 },
2878 };
2879 }
2880}
2881
2882#[derive(Debug, Clone, Copy, Hash, PartialEq, PartialOrd, Eq, Ord)]
2884pub struct Au(pub i32);
2885
2886pub const AU_PER_PX: i32 = 60;
2887pub const MAX_AU: i32 = (1 << 30) - 1;
2888pub const MIN_AU: i32 = -(1 << 30) - 1;
2889
2890impl Au {
2891 pub fn from_px(px: f32) -> Self {
2892 let target_app_units = (px * AU_PER_PX as f32) as i32;
2893 Au(target_app_units.min(MAX_AU).max(MIN_AU))
2894 }
2895 pub fn into_px(&self) -> f32 {
2896 self.0 as f32 / AU_PER_PX as f32
2897 }
2898}
2899
2900#[derive(Debug)]
2902pub enum AddFontMsg {
2903 Font(FontKey, StyleFontFamilyHash, FontRef),
2905 Instance(AddFontInstance, (Au, DpiScaleFactor)),
2906}
2907
2908impl AddFontMsg {
2909 pub fn into_resource_update(&self) -> ResourceUpdate {
2910 use self::AddFontMsg::*;
2911 match self {
2912 Font(font_key, _, font_ref) => ResourceUpdate::AddFont(AddFont {
2913 key: *font_key,
2914 font_bytes: font_ref.get_data().bytes.clone(),
2915 font_index: font_ref.get_data().font_index,
2916 }),
2917 Instance(fi, _) => ResourceUpdate::AddFontInstance(fi.clone()),
2918 }
2919 }
2920}
2921
2922#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
2923pub enum DeleteFontMsg {
2924 Font(FontKey),
2925 Instance(FontInstanceKey, (Au, DpiScaleFactor)),
2926}
2927
2928impl DeleteFontMsg {
2929 pub fn into_resource_update(&self) -> ResourceUpdate {
2930 use self::DeleteFontMsg::*;
2931 match self {
2932 Font(f) => ResourceUpdate::DeleteFont(*f),
2933 Instance(fi, _) => ResourceUpdate::DeleteFontInstance(*fi),
2934 }
2935 }
2936}
2937
2938#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
2939pub struct AddImageMsg(pub AddImage);
2940
2941impl AddImageMsg {
2942 pub fn into_resource_update(&self) -> ResourceUpdate {
2943 ResourceUpdate::AddImage(self.0.clone())
2944 }
2945}
2946
2947#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
2948pub struct DeleteImageMsg(ImageKey);
2949
2950impl DeleteImageMsg {
2951 pub fn into_resource_update(&self) -> ResourceUpdate {
2952 ResourceUpdate::DeleteImage(self.0.clone())
2953 }
2954}
2955
2956#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2957#[repr(C)]
2958pub struct LoadedFontSource {
2959 pub data: U8Vec,
2960 pub index: u32,
2961 pub load_outlines: bool,
2962}
2963
2964pub type LoadFontFn = fn(&StyleFontFamily, &FcFontCache) -> Option<LoadedFontSource>;
2966
2967pub type ParseFontFn = fn(LoadedFontSource) -> Option<FontRef>; pub fn build_add_font_resource_updates(
2979 renderer_resources: &mut RendererResources,
2980 dpi: DpiScaleFactor,
2981 fc_cache: &FcFontCache,
2982 id_namespace: IdNamespace,
2983 fonts_in_dom: &FastHashMap<ImmediateFontId, FastBTreeSet<Au>>,
2984 font_source_load_fn: LoadFontFn,
2985 parse_font_fn: ParseFontFn,
2986) -> Vec<(StyleFontFamilyHash, AddFontMsg)> {
2987 let mut resource_updates = alloc::vec::Vec::new();
2988 let mut font_instances_added_this_frame = FastBTreeSet::new();
2989
2990 'outer: for (im_font_id, font_sizes) in fonts_in_dom {
2991 macro_rules! insert_font_instances {
2992 ($font_family_hash:expr, $font_key:expr, $font_size:expr) => {{
2993 let font_instance_key_exists = renderer_resources
2994 .currently_registered_fonts
2995 .get(&$font_key)
2996 .and_then(|(_, font_instances)| font_instances.get(&($font_size, dpi)))
2997 .is_some()
2998 || font_instances_added_this_frame.contains(&($font_key, ($font_size, dpi)));
2999
3000 if !font_instance_key_exists {
3001 let font_instance_key = FontInstanceKey::unique(id_namespace);
3002
3003 #[cfg(target_os = "windows")]
3005 let platform_options = FontInstancePlatformOptions {
3006 gamma: 300,
3007 contrast: 100,
3008 cleartype_level: 100,
3009 };
3010
3011 #[cfg(target_os = "linux")]
3012 let platform_options = FontInstancePlatformOptions {
3013 lcd_filter: FontLCDFilter::Default,
3014 hinting: FontHinting::Normal,
3015 };
3016
3017 #[cfg(target_os = "macos")]
3018 let platform_options = FontInstancePlatformOptions::default();
3019
3020 #[cfg(target_arch = "wasm32")]
3021 let platform_options = FontInstancePlatformOptions::default();
3022
3023 let options = FontInstanceOptions {
3024 render_mode: FontRenderMode::Subpixel,
3025 flags: 0 | FONT_INSTANCE_FLAG_NO_AUTOHINT,
3026 ..Default::default()
3027 };
3028
3029 font_instances_added_this_frame.insert(($font_key, ($font_size, dpi)));
3030 resource_updates.push((
3031 $font_family_hash,
3032 AddFontMsg::Instance(
3033 AddFontInstance {
3034 key: font_instance_key,
3035 font_key: $font_key,
3036 glyph_size: ($font_size, dpi),
3037 options: Some(options),
3038 platform_options: Some(platform_options),
3039 variations: alloc::vec::Vec::new(),
3040 },
3041 ($font_size, dpi),
3042 ),
3043 ));
3044 }
3045 }};
3046 }
3047
3048 match im_font_id {
3049 ImmediateFontId::Resolved((font_family_hash, font_id)) => {
3050 for font_size in font_sizes.iter() {
3053 insert_font_instances!(*font_family_hash, *font_id, *font_size);
3054 }
3055 }
3056 ImmediateFontId::Unresolved(style_font_families) => {
3057 let mut font_family_hash = None;
3067 let font_families_hash = StyleFontFamiliesHash::new(style_font_families.as_ref());
3068
3069 'inner: for family in style_font_families.as_ref().iter() {
3071 let current_family_hash = StyleFontFamilyHash::new(&family);
3072
3073 if let Some(font_id) = renderer_resources.font_id_map.get(¤t_family_hash)
3074 {
3075 for font_size in font_sizes {
3077 insert_font_instances!(current_family_hash, *font_id, *font_size);
3078 }
3079 continue 'outer;
3080 }
3081
3082 let font_ref = match family {
3083 StyleFontFamily::Ref(r) => r.clone(), other => {
3085 let font_data = match (font_source_load_fn)(&other, fc_cache) {
3087 Some(s) => s,
3088 None => continue 'inner,
3089 };
3090
3091 let font_ref = match (parse_font_fn)(font_data) {
3092 Some(s) => s,
3093 None => continue 'inner,
3094 };
3095
3096 font_ref
3097 }
3098 };
3099
3100 font_family_hash = Some((current_family_hash, font_ref));
3102 break 'inner;
3103 }
3104
3105 let (font_family_hash, font_ref) = match font_family_hash {
3106 None => continue 'outer, Some(s) => s,
3108 };
3109
3110 let font_key = FontKey::unique(id_namespace);
3112 let add_font_msg = AddFontMsg::Font(font_key, font_family_hash, font_ref);
3113
3114 renderer_resources
3115 .font_id_map
3116 .insert(font_family_hash, font_key);
3117 renderer_resources
3118 .font_families_map
3119 .insert(font_families_hash, font_family_hash);
3120 resource_updates.push((font_family_hash, add_font_msg));
3121
3122 for font_size in font_sizes {
3124 insert_font_instances!(font_family_hash, font_key, *font_size);
3125 }
3126 }
3127 }
3128 }
3129
3130 resource_updates
3131}
3132
3133#[allow(unused_variables)]
3142pub fn build_add_image_resource_updates(
3143 renderer_resources: &RendererResources,
3144 id_namespace: IdNamespace,
3145 epoch: Epoch,
3146 document_id: &DocumentId,
3147 images_in_dom: &FastBTreeSet<ImageRef>,
3148 insert_into_active_gl_textures: GlStoreImageFn,
3149) -> Vec<(ImageRefHash, AddImageMsg)> {
3150 images_in_dom
3151 .iter()
3152 .filter_map(|image_ref| {
3153 let image_ref_hash = image_ref.get_hash();
3154
3155 if renderer_resources
3156 .currently_registered_images
3157 .contains_key(&image_ref_hash)
3158 {
3159 return None;
3160 }
3161
3162 match image_ref.get_data() {
3165 DecodedImage::Gl(texture) => {
3166 let descriptor = texture.get_descriptor();
3167 let key = ImageKey::unique(id_namespace);
3168 let external_image_id =
3170 (insert_into_active_gl_textures)(*document_id, epoch, texture.clone());
3171 Some((
3172 image_ref_hash,
3173 AddImageMsg(AddImage {
3174 key,
3175 data: ImageData::External(ExternalImageData {
3176 id: external_image_id,
3177 channel_index: 0,
3178 image_type: ExternalImageType::TextureHandle(
3179 ImageBufferKind::Texture2D,
3180 ),
3181 }),
3182 descriptor,
3183 tiling: None,
3184 }),
3185 ))
3186 }
3187 DecodedImage::Raw((descriptor, data)) => {
3188 let key = ImageKey::unique(id_namespace);
3189 Some((
3190 image_ref_hash,
3191 AddImageMsg(AddImage {
3192 key,
3193 data: data.clone(), descriptor: descriptor.clone(), tiling: None,
3197 }),
3198 ))
3199 }
3200 DecodedImage::NullImage {
3201 width: _,
3202 height: _,
3203 format: _,
3204 tag: _,
3205 } => None,
3206 DecodedImage::Callback(_) => None, }
3209 })
3210 .collect()
3211}
3212
3213fn add_gl_resources(
3214 renderer_resources: &mut RendererResources,
3215 all_resource_updates: &mut Vec<ResourceUpdate>,
3216 add_image_resources: Vec<(ImageRefHash, ImageRefHash, AddImageMsg)>,
3217) {
3218 let add_image_resources = add_image_resources
3219 .into_iter()
3220 .map(|(_, k, v)| (k, v))
3222 .collect::<Vec<_>>();
3223
3224 add_resources(
3225 renderer_resources,
3226 all_resource_updates,
3227 Vec::new(),
3228 add_image_resources,
3229 );
3230}
3231
3232pub fn add_resources(
3237 renderer_resources: &mut RendererResources,
3238 all_resource_updates: &mut Vec<ResourceUpdate>,
3239 add_font_resources: Vec<(StyleFontFamilyHash, AddFontMsg)>,
3240 add_image_resources: Vec<(ImageRefHash, AddImageMsg)>,
3241) {
3242 all_resource_updates.extend(
3243 add_font_resources
3244 .iter()
3245 .map(|(_, f)| f.into_resource_update()),
3246 );
3247 all_resource_updates.extend(
3248 add_image_resources
3249 .iter()
3250 .map(|(_, i)| i.into_resource_update()),
3251 );
3252
3253 for (image_ref_hash, add_image_msg) in add_image_resources.iter() {
3254 renderer_resources.currently_registered_images.insert(
3255 *image_ref_hash,
3256 ResolvedImage {
3257 key: add_image_msg.0.key,
3258 descriptor: add_image_msg.0.descriptor,
3259 },
3260 );
3261 }
3262
3263 for (_, add_font_msg) in add_font_resources {
3264 use self::AddFontMsg::*;
3265 match add_font_msg {
3266 Font(fk, _hash, font_ref) => {
3267 renderer_resources
3268 .currently_registered_fonts
3269 .entry(fk)
3270 .or_insert_with(|| (font_ref, FastHashMap::default()));
3271 }
3272 Instance(fi, size) => {
3273 if let Some((_, instances)) = renderer_resources
3274 .currently_registered_fonts
3275 .get_mut(&fi.font_key)
3276 {
3277 instances.insert(size, fi.key);
3278 }
3279 }
3280 }
3281 }
3282}