1#[cfg(target_os = "windows")]
2use crate::WindowsScreenCaptureFrame;
3use crate::{
4 App, Bounds, DevicePixels, Element, ElementId, GlobalElementId, InspectorElementId,
5 IntoElement, LayoutId, ObjectFit, Pixels, Size, Style, StyleRefinement, Styled, Window,
6};
7#[cfg(any(target_os = "macos", target_os = "ios"))]
8use objc2_core_foundation::CFRetained;
9#[cfg(any(target_os = "macos", target_os = "ios"))]
10use objc2_core_video::{CVPixelBuffer, CVPixelBufferGetHeight, CVPixelBufferGetWidth};
11use refineable::Refineable;
12
13#[derive(Clone)]
19pub enum SurfaceSource {
20 #[cfg(any(target_os = "macos", target_os = "ios"))]
22 Surface(CFRetained<CVPixelBuffer>),
23 #[cfg(any(
25 target_os = "linux",
26 target_os = "freebsd",
27 all(target_os = "macos", feature = "custom-gpu"),
28 all(target_family = "wasm", feature = "custom-gpu")
29 ))]
30 Texture {
31 #[cfg(not(target_family = "wasm"))]
33 texture: std::sync::Arc<dyn std::any::Any + Send + Sync>,
34 #[cfg(target_family = "wasm")]
38 texture: std::sync::Arc<dyn std::any::Any>,
39 size: Size<DevicePixels>,
41 },
42 #[cfg(target_os = "windows")]
44 WindowsCapture(WindowsScreenCaptureFrame),
45 #[doc(hidden)]
47 Unsupported(Size<DevicePixels>),
48}
49
50impl std::fmt::Debug for SurfaceSource {
51 fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
52 match *self {
53 #[cfg(any(target_os = "macos", target_os = "ios"))]
54 SurfaceSource::Surface(ref buf) => _f.debug_tuple("Surface").field(buf).finish(),
55 #[cfg(any(
56 target_os = "linux",
57 target_os = "freebsd",
58 all(target_os = "macos", feature = "custom-gpu"),
59 all(target_family = "wasm", feature = "custom-gpu")
60 ))]
61 SurfaceSource::Texture { size, .. } => _f
62 .debug_struct("Texture")
63 .field("size", &size)
64 .finish_non_exhaustive(),
65 #[cfg(target_os = "windows")]
66 SurfaceSource::WindowsCapture(ref frame) => frame.fmt(_f),
67 SurfaceSource::Unsupported(size) => _f.debug_tuple("Unsupported").field(&size).finish(),
68 }
69 }
70}
71
72impl SurfaceSource {
73 fn size(&self) -> Size<DevicePixels> {
74 match self {
75 #[cfg(any(target_os = "macos", target_os = "ios"))]
76 SurfaceSource::Surface(buffer) => crate::size(
77 CVPixelBufferGetWidth(buffer).into(),
78 CVPixelBufferGetHeight(buffer).into(),
79 ),
80 #[cfg(any(
81 target_os = "linux",
82 target_os = "freebsd",
83 all(target_os = "macos", feature = "custom-gpu"),
84 all(target_family = "wasm", feature = "custom-gpu")
85 ))]
86 SurfaceSource::Texture { size, .. } => *size,
87 #[cfg(target_os = "windows")]
88 SurfaceSource::WindowsCapture(frame) => frame.size(),
89 SurfaceSource::Unsupported(size) => *size,
90 }
91 }
92}
93
94#[cfg(any(target_os = "macos", target_os = "ios"))]
95impl From<CFRetained<CVPixelBuffer>> for SurfaceSource {
96 fn from(value: CFRetained<CVPixelBuffer>) -> Self {
97 SurfaceSource::Surface(value)
98 }
99}
100
101#[cfg(target_os = "windows")]
102impl From<WindowsScreenCaptureFrame> for SurfaceSource {
103 fn from(value: WindowsScreenCaptureFrame) -> Self {
104 SurfaceSource::WindowsCapture(value)
105 }
106}
107
108#[cfg(all(target_os = "windows", feature = "screen-capture"))]
109impl From<crate::ScreenCaptureFrame> for SurfaceSource {
110 fn from(value: crate::ScreenCaptureFrame) -> Self {
111 SurfaceSource::WindowsCapture(value.0)
112 }
113}
114
115pub struct Surface {
120 source: SurfaceSource,
121 object_fit: ObjectFit,
122 style: StyleRefinement,
123}
124
125pub fn surface(source: impl Into<SurfaceSource>) -> Surface {
131 Surface {
132 source: source.into(),
133 object_fit: ObjectFit::Contain,
134 style: Default::default(),
135 }
136}
137
138impl Surface {
139 pub fn object_fit(mut self, object_fit: ObjectFit) -> Self {
141 self.object_fit = object_fit;
142 self
143 }
144}
145
146impl Element for Surface {
147 type RequestLayoutState = ();
148 type PrepaintState = ();
149
150 fn id(&self) -> Option<ElementId> {
151 None
152 }
153
154 fn source_location(&self) -> Option<&'static core::panic::Location<'static>> {
155 None
156 }
157
158 fn request_layout(
159 &mut self,
160 _global_id: Option<&GlobalElementId>,
161 _inspector_id: Option<&InspectorElementId>,
162 window: &mut Window,
163 cx: &mut App,
164 ) -> (LayoutId, Self::RequestLayoutState) {
165 let mut style = Style::default();
166 style.refine(&self.style);
167 let layout_id = window.request_layout(style, [], cx);
168 (layout_id, ())
169 }
170
171 fn prepaint(
172 &mut self,
173 _global_id: Option<&GlobalElementId>,
174 _inspector_id: Option<&InspectorElementId>,
175 _bounds: Bounds<Pixels>,
176 _request_layout: &mut Self::RequestLayoutState,
177 _window: &mut Window,
178 _cx: &mut App,
179 ) -> Self::PrepaintState {
180 }
181
182 fn paint(
183 &mut self,
184 _global_id: Option<&GlobalElementId>,
185 _inspector_id: Option<&InspectorElementId>,
186 #[cfg_attr(
187 not(any(target_os = "macos", target_os = "ios")),
188 allow(unused_variables)
189 )]
190 _bounds: Bounds<Pixels>,
191 _: &mut Self::RequestLayoutState,
192 _: &mut Self::PrepaintState,
193 _window: &mut Window,
194 _: &mut App,
195 ) {
196 let new_bounds = self.object_fit.get_bounds(_bounds, self.source.size());
197 let mut style = Style::default();
199 style.refine(&self.style);
200 _window.with_element_opacity(style.opacity, |window| {
201 window.paint_surface(new_bounds, self.source.clone());
202 });
203 }
204}
205
206impl IntoElement for Surface {
207 type Element = Self;
208
209 fn into_element(self) -> Self::Element {
210 self
211 }
212}
213
214impl Styled for Surface {
215 fn style(&mut self) -> &mut StyleRefinement {
216 &mut self.style
217 }
218}