1use crate::{
2 Bounds, Element, ElementId, GlobalElementId, IntoElement, LayoutId, ObjectFit, Pixels, Style,
3 StyleRefinement, Styled, WindowContext,
4};
5#[cfg(target_os = "macos")]
6use media::core_video::CVImageBuffer;
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(CVImageBuffer),
15}
16
17#[cfg(target_os = "macos")]
18impl From<CVImageBuffer> for SurfaceSource {
19 fn from(value: CVImageBuffer) -> 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.
32pub fn surface(source: impl Into<SurfaceSource>) -> Surface {
33 Surface {
34 source: source.into(),
35 object_fit: ObjectFit::Contain,
36 style: Default::default(),
37 }
38}
39
40impl Surface {
41 /// Set the object fit for the image.
42 pub fn object_fit(mut self, object_fit: ObjectFit) -> Self {
43 self.object_fit = object_fit;
44 self
45 }
46}
47
48impl Element for Surface {
49 type RequestLayoutState = ();
50 type PrepaintState = ();
51
52 fn id(&self) -> Option<ElementId> {
53 None
54 }
55
56 fn request_layout(
57 &mut self,
58 _global_id: Option<&GlobalElementId>,
59 cx: &mut WindowContext,
60 ) -> (LayoutId, Self::RequestLayoutState) {
61 let mut style = Style::default();
62 style.refine(&self.style);
63 let layout_id = cx.request_layout(style, []);
64 (layout_id, ())
65 }
66
67 fn prepaint(
68 &mut self,
69 _global_id: Option<&GlobalElementId>,
70 _bounds: Bounds<Pixels>,
71 _request_layout: &mut Self::RequestLayoutState,
72 _cx: &mut WindowContext,
73 ) -> Self::PrepaintState {
74 }
75
76 fn paint(
77 &mut self,
78 _global_id: Option<&GlobalElementId>,
79 #[cfg_attr(not(target_os = "macos"), allow(unused_variables))] bounds: Bounds<Pixels>,
80 _: &mut Self::RequestLayoutState,
81 _: &mut Self::PrepaintState,
82 #[cfg_attr(not(target_os = "macos"), allow(unused_variables))] cx: &mut WindowContext,
83 ) {
84 match &self.source {
85 #[cfg(target_os = "macos")]
86 SurfaceSource::Surface(surface) => {
87 let size = crate::size(surface.width().into(), surface.height().into());
88 let new_bounds = self.object_fit.get_bounds(bounds, size);
89 // TODO: Add support for corner_radii
90 cx.paint_surface(new_bounds, surface.clone());
91 }
92 #[allow(unreachable_patterns)]
93 _ => {}
94 }
95 }
96}
97
98impl IntoElement for Surface {
99 type Element = Self;
100
101 fn into_element(self) -> Self::Element {
102 self
103 }
104}
105
106impl Styled for Surface {
107 fn style(&mut self) -> &mut StyleRefinement {
108 &mut self.style
109 }
110}