summaryrefslogtreecommitdiff
path: root/libs/nativewindow/rust/src/surface.rs
blob: 25fea807b5e84c3036a5bd224f7b6d970c145447 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
// Copyright (C) 2024 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Rust wrapper for `ANativeWindow` and related types.

use binder::{
    binder_impl::{BorrowedParcel, UnstructuredParcelable},
    impl_deserialize_for_unstructured_parcelable, impl_serialize_for_unstructured_parcelable,
    unstable_api::{status_result, AsNative},
    StatusCode,
};
use nativewindow_bindgen::{
    AHardwareBuffer_Format, ANativeWindow, ANativeWindow_acquire, ANativeWindow_getFormat,
    ANativeWindow_getHeight, ANativeWindow_getWidth, ANativeWindow_readFromParcel,
    ANativeWindow_release, ANativeWindow_writeToParcel,
};
use std::error::Error;
use std::fmt::{self, Debug, Display, Formatter};
use std::ptr::{null_mut, NonNull};

/// Wrapper around an opaque C `ANativeWindow`.
#[derive(PartialEq, Eq)]
pub struct Surface(NonNull<ANativeWindow>);

impl Surface {
    /// Returns the current width in pixels of the window surface.
    pub fn width(&self) -> Result<u32, ErrorCode> {
        // SAFETY: The ANativeWindow pointer we pass is guaranteed to be non-null and valid because
        // it must have been allocated by `ANativeWindow_allocate` or `ANativeWindow_readFromParcel`
        // and we have not yet released it.
        let width = unsafe { ANativeWindow_getWidth(self.0.as_ptr()) };
        width.try_into().map_err(|_| ErrorCode(width))
    }

    /// Returns the current height in pixels of the window surface.
    pub fn height(&self) -> Result<u32, ErrorCode> {
        // SAFETY: The ANativeWindow pointer we pass is guaranteed to be non-null and valid because
        // it must have been allocated by `ANativeWindow_allocate` or `ANativeWindow_readFromParcel`
        // and we have not yet released it.
        let height = unsafe { ANativeWindow_getHeight(self.0.as_ptr()) };
        height.try_into().map_err(|_| ErrorCode(height))
    }

    /// Returns the current pixel format of the window surface.
    pub fn format(&self) -> Result<AHardwareBuffer_Format::Type, ErrorCode> {
        // SAFETY: The ANativeWindow pointer we pass is guaranteed to be non-null and valid because
        // it must have been allocated by `ANativeWindow_allocate` or `ANativeWindow_readFromParcel`
        // and we have not yet released it.
        let format = unsafe { ANativeWindow_getFormat(self.0.as_ptr()) };
        format.try_into().map_err(|_| ErrorCode(format))
    }
}

impl Drop for Surface {
    fn drop(&mut self) {
        // SAFETY: The ANativeWindow pointer we pass is guaranteed to be non-null and valid because
        // it must have been allocated by `ANativeWindow_allocate` or `ANativeWindow_readFromParcel`
        // and we have not yet released it.
        unsafe { ANativeWindow_release(self.0.as_ptr()) }
    }
}

impl Debug for Surface {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        f.debug_struct("Surface")
            .field("width", &self.width())
            .field("height", &self.height())
            .field("format", &self.format())
            .finish()
    }
}

impl Clone for Surface {
    fn clone(&self) -> Self {
        // SAFETY: The ANativeWindow pointer we pass is guaranteed to be non-null and valid because
        // it must have been allocated by `ANativeWindow_allocate` or `ANativeWindow_readFromParcel`
        // and we have not yet released it.
        unsafe { ANativeWindow_acquire(self.0.as_ptr()) };
        Self(self.0)
    }
}

impl UnstructuredParcelable for Surface {
    fn write_to_parcel(&self, parcel: &mut BorrowedParcel) -> Result<(), StatusCode> {
        let status =
        // SAFETY: The ANativeWindow pointer we pass is guaranteed to be non-null and valid because
        // it must have been allocated by `ANativeWindow_allocate` or `ANativeWindow_readFromParcel`
        // and we have not yet released it.
        unsafe { ANativeWindow_writeToParcel(self.0.as_ptr(), parcel.as_native_mut()) };
        status_result(status)
    }

    fn from_parcel(parcel: &BorrowedParcel) -> Result<Self, StatusCode> {
        let mut buffer = null_mut();

        let status =
        // SAFETY: Both pointers must be valid because they are obtained from references.
        // `ANativeWindow_readFromParcel` doesn't store them or do anything else special
        // with them. If it returns success then it will have allocated a new
        // `ANativeWindow` and incremented the reference count, so we can use it until we
        // release it.
            unsafe { ANativeWindow_readFromParcel(parcel.as_native(), &mut buffer) };

        status_result(status)?;

        Ok(Self(
            NonNull::new(buffer)
                .expect("ANativeWindow_readFromParcel returned success but didn't allocate buffer"),
        ))
    }
}

impl_deserialize_for_unstructured_parcelable!(Surface);
impl_serialize_for_unstructured_parcelable!(Surface);

// SAFETY: The underlying *ANativeWindow can be moved between threads.
unsafe impl Send for Surface {}

// SAFETY: The underlying *ANativeWindow can be used from multiple threads concurrently.
unsafe impl Sync for Surface {}

/// An error code returned by methods on [`Surface`].
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct ErrorCode(i32);

impl Error for ErrorCode {}

impl Display for ErrorCode {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "Error {}", self.0)
    }
}