1use crate::{
2 App, Bounds, Element, ElementId, GlobalElementId, InspectorElementId, IntoElement, LayoutId,
3 ObjectFit, Pixels, Style, StyleRefinement, Styled, Window,
4};
5#[cfg(any(target_os = "linux", target_os = "freebsd"))]
6use crate::{DevicePixels, Size};
7#[cfg(target_os = "macos")]
8use core_video::pixel_buffer::CVPixelBuffer;
9use refineable::Refineable;
10#[cfg(any(target_os = "linux", target_os = "freebsd"))]
11use std::sync::Arc;
12
13pub enum SurfaceSource {
15 #[cfg(target_os = "macos")]
17 Surface(CVPixelBuffer),
18 #[cfg(any(target_os = "linux", target_os = "freebsd"))]
20 Texture {
21 texture: Arc<dyn std::any::Any + Send + Sync>,
23 size: Size<DevicePixels>,
25 },
26}
27
28impl Clone for SurfaceSource {
29 fn clone(&self) -> Self {
30 match *self {
31 #[cfg(target_os = "macos")]
32 SurfaceSource::Surface(ref buf) => SurfaceSource::Surface(buf.clone()),
33 #[cfg(any(target_os = "linux", target_os = "freebsd"))]
34 SurfaceSource::Texture { ref texture, size } => SurfaceSource::Texture {
35 texture: Arc::clone(texture),
36 size,
37 },
38 }
39 }
40}
41
42impl std::fmt::Debug for SurfaceSource {
43 fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
44 match *self {
45 #[cfg(target_os = "macos")]
46 SurfaceSource::Surface(ref buf) => _f.debug_tuple("Surface").field(buf).finish(),
47 #[cfg(any(target_os = "linux", target_os = "freebsd"))]
48 SurfaceSource::Texture { size, .. } => _f
49 .debug_struct("Texture")
50 .field("size", &size)
51 .finish_non_exhaustive(),
52 }
53 }
54}
55
56#[cfg(target_os = "macos")]
57impl From<CVPixelBuffer> for SurfaceSource {
58 fn from(value: CVPixelBuffer) -> Self {
59 SurfaceSource::Surface(value)
60 }
61}
62
63pub struct Surface {
65 source: SurfaceSource,
66 object_fit: ObjectFit,
67 style: StyleRefinement,
68}
69
70pub fn surface(source: impl Into<SurfaceSource>) -> Surface {
72 Surface {
73 source: source.into(),
74 object_fit: ObjectFit::Contain,
75 style: Default::default(),
76 }
77}
78
79impl Surface {
80 pub fn object_fit(mut self, object_fit: ObjectFit) -> Self {
82 self.object_fit = object_fit;
83 self
84 }
85}
86
87impl Element for Surface {
88 type RequestLayoutState = ();
89 type PrepaintState = ();
90
91 fn id(&self) -> Option<ElementId> {
92 None
93 }
94
95 fn source_location(&self) -> Option<&'static core::panic::Location<'static>> {
96 None
97 }
98
99 fn request_layout(
100 &mut self,
101 _global_id: Option<&GlobalElementId>,
102 _inspector_id: Option<&InspectorElementId>,
103 window: &mut Window,
104 cx: &mut App,
105 ) -> (LayoutId, Self::RequestLayoutState) {
106 let mut style = Style::default();
107 style.refine(&self.style);
108 let layout_id = window.request_layout(style, [], cx);
109 (layout_id, ())
110 }
111
112 fn prepaint(
113 &mut self,
114 _global_id: Option<&GlobalElementId>,
115 _inspector_id: Option<&InspectorElementId>,
116 _bounds: Bounds<Pixels>,
117 _request_layout: &mut Self::RequestLayoutState,
118 _window: &mut Window,
119 _cx: &mut App,
120 ) -> Self::PrepaintState {
121 }
122
123 fn paint(
124 &mut self,
125 _global_id: Option<&GlobalElementId>,
126 _inspector_id: Option<&InspectorElementId>,
127 _bounds: Bounds<Pixels>,
128 _: &mut Self::RequestLayoutState,
129 _: &mut Self::PrepaintState,
130 _window: &mut Window,
131 _: &mut App,
132 ) {
133 match self.source {
134 #[cfg(target_os = "macos")]
135 SurfaceSource::Surface(ref surface) => {
136 let size = crate::size(surface.get_width().into(), surface.get_height().into());
137 let new_bounds = self.object_fit.get_bounds(_bounds, size);
138 _window.paint_surface(new_bounds, surface.clone());
140 }
141 #[cfg(any(target_os = "linux", target_os = "freebsd"))]
142 SurfaceSource::Texture {
143 ref texture,
144 ref size,
145 } => {
146 let new_bounds = self.object_fit.get_bounds(_bounds, *size);
147 _window.paint_surface(new_bounds, Arc::clone(texture), *size);
148 }
149 }
150 }
151}
152
153impl IntoElement for Surface {
154 type Element = Self;
155
156 fn into_element(self) -> Self::Element {
157 self
158 }
159}
160
161impl Styled for Surface {
162 fn style(&mut self) -> &mut StyleRefinement {
163 &mut self.style
164 }
165}