freya_core/elements/
image.rs

1use freya_engine::prelude::*;
2use freya_native_core::real_dom::NodeImmutable;
3
4use super::utils::ElementUtils;
5use crate::{
6    dom::{
7        DioxusNode,
8        ImagesCache,
9    },
10    render::{
11        get_or_create_image,
12        ImageData,
13    },
14    states::ImageState,
15    values::{
16        ImageCover,
17        SamplingMode,
18    },
19};
20
21pub struct ImageElement;
22
23impl ElementUtils for ImageElement {
24    fn render(
25        self,
26        layout_node: &torin::prelude::LayoutNode,
27        node_ref: &DioxusNode,
28        canvas: &Canvas,
29        _font_collection: &mut FontCollection,
30        _font_manager: &FontMgr,
31        _default_fonts: &[String],
32        images_cache: &mut ImagesCache,
33        _scale_factor: f32,
34    ) {
35        let area = layout_node.visible_area();
36
37        let Some(ImageData { image, size }) =
38            get_or_create_image(node_ref, &area.size, images_cache)
39        else {
40            return;
41        };
42
43        let image_state = node_ref.get::<ImageState>().unwrap();
44
45        let mut rect = Rect::new(
46            area.min_x(),
47            area.min_y(),
48            area.min_x() + size.width,
49            area.min_y() + size.height,
50        );
51        let clip_rect = Rect::new(area.min_x(), area.min_y(), area.max_x(), area.max_y());
52
53        if image_state.image_cover == ImageCover::Center {
54            let width_offset = (size.width - area.width()) / 2.;
55            let height_offset = (size.height - area.height()) / 2.;
56
57            rect.left -= width_offset;
58            rect.right -= width_offset;
59            rect.top -= height_offset;
60            rect.bottom -= height_offset;
61        }
62
63        canvas.save();
64        canvas.clip_rect(clip_rect, ClipOp::Intersect, true);
65
66        let mut paint = Paint::default();
67        paint.set_anti_alias(true);
68
69        let sampling = match image_state.image_sampling {
70            SamplingMode::Nearest => SamplingOptions::new(FilterMode::Nearest, MipmapMode::None),
71            SamplingMode::Bilinear => SamplingOptions::new(FilterMode::Linear, MipmapMode::None),
72            SamplingMode::Trilinear => SamplingOptions::new(FilterMode::Linear, MipmapMode::Linear),
73            SamplingMode::Mitchell => SamplingOptions::from(CubicResampler::mitchell()),
74            SamplingMode::CatmullRom => SamplingOptions::from(CubicResampler::catmull_rom()),
75        };
76
77        canvas.draw_image_rect_with_sampling_options(
78            image,
79            None,
80            rect,
81            sampling,
82            &Paint::default(),
83        );
84
85        canvas.restore();
86    }
87    fn clip(
88        &self,
89        layout_node: &torin::prelude::LayoutNode,
90        _node_ref: &DioxusNode,
91        canvas: &Canvas,
92        _scale_factor: f32,
93    ) {
94        canvas.clip_rect(
95            Rect::new(
96                layout_node.area.min_x(),
97                layout_node.area.min_y(),
98                layout_node.area.max_x(),
99                layout_node.area.max_y(),
100            ),
101            ClipOp::Intersect,
102            true,
103        );
104    }
105}