Skip to main content

gpui/elements/
surface.rs

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/// A source of a surface's content.
12#[derive(Clone, Debug, PartialEq, Eq)]
13pub enum SurfaceSource {
14    /// A CoreVideo image buffer
15    #[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
26/// A surface element.
27pub struct Surface {
28    source: SurfaceSource,
29    object_fit: ObjectFit,
30    style: StyleRefinement,
31}
32
33/// Create a new surface element.
34#[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    /// Set the object fit for the image.
45    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                // TODO: Add support for corner_radii
114                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}