1use crate::{
2 App, Bounds, Element, ElementId, GlobalElementId, InspectorElementId, IntoElement, LayoutId,
3 ObjectFit, Pixels, Style, StyleRefinement, Styled, Window,
4};
5#[cfg(target_os = "macos")]
6use core_video::pixel_buffer::CVPixelBuffer;
7use refineable::Refineable;
8
9/// A source of a surface's content.
10#[derive(Clone, Debug, PartialEq, Eq)]
11pub enum SurfaceSource {
12 /// A macOS image buffer from CoreVideo
13 #[cfg(target_os = "macos")]
14 Surface(CVPixelBuffer),
15}
16
17#[cfg(target_os = "macos")]
18impl From<CVPixelBuffer> for SurfaceSource {
19 fn from(value: CVPixelBuffer) -> Self {
20 SurfaceSource::Surface(value)
21 }
22}
23
24/// A surface element.
25pub struct Surface {
26 source: SurfaceSource,
27 object_fit: ObjectFit,
28 style: StyleRefinement,
29}
30
31/// Create a new surface element.
32#[cfg(target_os = "macos")]
33pub fn surface(source: impl Into<SurfaceSource>) -> Surface {
34 Surface {
35 source: source.into(),
36 object_fit: ObjectFit::Contain,
37 style: Default::default(),
38 }
39}
40
41impl Surface {
42 /// Set the object fit for the image.
43 pub fn object_fit(mut self, object_fit: ObjectFit) -> Self {
44 self.object_fit = object_fit;
45 self
46 }
47}
48
49impl Element for Surface {
50 type RequestLayoutState = ();
51 type PrepaintState = ();
52
53 fn id(&self) -> Option<ElementId> {
54 None
55 }
56
57 fn source_location(&self) -> Option<&'static core::panic::Location<'static>> {
58 None
59 }
60
61 fn request_layout(
62 &mut self,
63 _global_id: Option<&GlobalElementId>,
64 _inspector_id: Option<&InspectorElementId>,
65 window: &mut Window,
66 cx: &mut App,
67 ) -> (LayoutId, Self::RequestLayoutState) {
68 let mut style = Style::default();
69 style.refine(&self.style);
70 let layout_id = window.request_layout(style, [], cx);
71 (layout_id, ())
72 }
73
74 fn prepaint(
75 &mut self,
76 _global_id: Option<&GlobalElementId>,
77 _inspector_id: Option<&InspectorElementId>,
78 _bounds: Bounds<Pixels>,
79 _request_layout: &mut Self::RequestLayoutState,
80 _window: &mut Window,
81 _cx: &mut App,
82 ) -> Self::PrepaintState {
83 }
84
85 fn paint(
86 &mut self,
87 _global_id: Option<&GlobalElementId>,
88 _inspector_id: Option<&InspectorElementId>,
89 #[cfg_attr(not(target_os = "macos"), allow(unused_variables))] bounds: Bounds<Pixels>,
90 _: &mut Self::RequestLayoutState,
91 _: &mut Self::PrepaintState,
92 #[cfg_attr(not(target_os = "macos"), allow(unused_variables))] window: &mut Window,
93 _: &mut App,
94 ) {
95 match &self.source {
96 #[cfg(target_os = "macos")]
97 SurfaceSource::Surface(surface) => {
98 let size = crate::size(surface.get_width().into(), surface.get_height().into());
99 let new_bounds = self.object_fit.get_bounds(bounds, size);
100 // TODO: Add support for corner_radii
101 window.paint_surface(new_bounds, surface.clone());
102 }
103 #[allow(unreachable_patterns)]
104 _ => {}
105 }
106 }
107}
108
109impl IntoElement for Surface {
110 type Element = Self;
111
112 fn into_element(self) -> Self::Element {
113 self
114 }
115}
116
117impl Styled for Surface {
118 fn style(&mut self) -> &mut StyleRefinement {
119 &mut self.style
120 }
121}