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