use crate::client::Client;
use crate::object::{ObjectRef, RequestReceiver};
use crate::scenic::{FlatlandInstanceId, FlatlandPtr};
use anyhow::Error;
use fidl_fuchsia_math::Size;
use fidl_fuchsia_ui_composition::{BufferCollectionImportToken, ContentId, ImageProperties};
use std::cell::Cell;
use std::rc::Rc;
use wayland_server_protocol::*;
use zx::{self as zx, HandleBased};
use {
fidl_fuchsia_math as fmath, fidl_fuchsia_ui_composition as composition, fuchsia_trace as ftrace,
};
pub type ImageInstanceId = usize;
pub struct Content {
pub id: ContentId,
flatland: FlatlandPtr,
}
impl Drop for Content {
fn drop(&mut self) {
self.flatland.borrow().proxy().release_image(&self.id).expect("fidl error");
}
}
struct Image {
import_token: Rc<composition::BufferCollectionImportToken>,
size: Size,
id: Cell<Option<(Rc<Content>, ImageInstanceId, FlatlandInstanceId)>>,
}
impl Image {
fn size(&self) -> Size {
self.size
}
pub fn new(import_token: Rc<composition::BufferCollectionImportToken>, size: Size) -> Self {
Self { import_token, size, id: Cell::new(None) }
}
pub fn scenic_content(
&self,
instance_id: ImageInstanceId,
flatland: &FlatlandPtr,
) -> Rc<Content> {
ftrace::duration!(c"wayland", c"Image::scenic_content");
let flatland_id = flatland.borrow().id();
let id = match self.id.take().filter(|id| instance_id == id.1 && flatland_id == id.2) {
Some(id) => id,
None => {
let raw_import_token =
self.import_token.value.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap();
let size =
fmath::SizeU { width: self.size.width as u32, height: self.size.height as u32 };
let image_props = ImageProperties { size: Some(size), ..Default::default() };
let content_id = flatland.borrow_mut().alloc_content_id();
let import_token = BufferCollectionImportToken { value: raw_import_token };
flatland
.borrow()
.proxy()
.create_image(&content_id, import_token, 0, &image_props)
.expect("fidl error");
let content = Content { id: content_id, flatland: flatland.clone() };
(Rc::new(content), instance_id, flatland_id)
}
};
let result = id.0.clone();
self.id.set(Some(id));
result
}
}
#[derive(Clone)]
pub struct Buffer {
image: Rc<Image>,
has_alpha: bool,
}
impl Buffer {
pub fn from_import_token(
import_token: Rc<composition::BufferCollectionImportToken>,
image_size: Size,
has_alpha: bool,
) -> Self {
let image = Image::new(import_token, image_size);
Buffer { image: Rc::new(image), has_alpha }
}
pub fn image_size(&self) -> Size {
self.image.size()
}
pub fn has_alpha(&self) -> bool {
self.has_alpha
}
pub fn image_content(
&self,
instance_id: ImageInstanceId,
flatland: &FlatlandPtr,
) -> Rc<Content> {
ftrace::duration!(c"wayland", c"Buffer::image_content");
self.image.scenic_content(instance_id, flatland)
}
}
impl RequestReceiver<WlBuffer> for Buffer {
fn receive(
this: ObjectRef<Self>,
request: WlBufferRequest,
client: &mut Client,
) -> Result<(), Error> {
let WlBufferRequest::Destroy = request;
client.delete_id(this.id())?;
Ok(())
}
}