|
Packit |
f0b94e |
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
Packit |
f0b94e |
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
Packit |
f0b94e |
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
Packit |
f0b94e |
|
|
Packit |
f0b94e |
// A very basic BlobImageRenderer that can only render a checkerboard pattern.
|
|
Packit |
f0b94e |
|
|
Packit |
f0b94e |
use std::collections::HashMap;
|
|
Packit |
f0b94e |
use std::sync::Arc;
|
|
Packit |
f0b94e |
use std::sync::Mutex;
|
|
Packit |
f0b94e |
use webrender::api::*;
|
|
Packit |
f0b94e |
|
|
Packit |
f0b94e |
// Serialize/deserialze the blob.
|
|
Packit |
f0b94e |
|
|
Packit |
f0b94e |
pub fn serialize_blob(color: ColorU) -> Vec<u8> {
|
|
Packit |
f0b94e |
vec![color.r, color.g, color.b, color.a]
|
|
Packit |
f0b94e |
}
|
|
Packit |
f0b94e |
|
|
Packit |
f0b94e |
fn deserialize_blob(blob: &[u8]) -> Result<ColorU, ()> {
|
|
Packit |
f0b94e |
let mut iter = blob.iter();
|
|
Packit |
f0b94e |
return match (iter.next(), iter.next(), iter.next(), iter.next()) {
|
|
Packit |
f0b94e |
(Some(&r), Some(&g), Some(&b), Some(&a)) => Ok(ColorU::new(r, g, b, a)),
|
|
Packit |
f0b94e |
(Some(&a), None, None, None) => Ok(ColorU::new(a, a, a, a)),
|
|
Packit |
f0b94e |
_ => Err(()),
|
|
Packit |
f0b94e |
};
|
|
Packit |
f0b94e |
}
|
|
Packit |
f0b94e |
|
|
Packit |
f0b94e |
// This is the function that applies the deserialized drawing commands and generates
|
|
Packit |
f0b94e |
// actual image data.
|
|
Packit |
f0b94e |
fn render_blob(
|
|
Packit |
f0b94e |
color: ColorU,
|
|
Packit |
f0b94e |
descriptor: &BlobImageDescriptor,
|
|
Packit |
f0b94e |
tile: Option<TileOffset>,
|
|
Packit |
f0b94e |
) -> BlobImageResult {
|
|
Packit |
f0b94e |
// Allocate storage for the result. Right now the resource cache expects the
|
|
Packit |
f0b94e |
// tiles to have have no stride or offset.
|
|
Packit |
f0b94e |
let mut texels = Vec::with_capacity((descriptor.width * descriptor.height * 4) as usize);
|
|
Packit |
f0b94e |
|
|
Packit |
f0b94e |
// Generate a per-tile pattern to see it in the demo. For a real use case it would not
|
|
Packit |
f0b94e |
// make sense for the rendered content to depend on its tile.
|
|
Packit |
f0b94e |
let tile_checker = match tile {
|
|
Packit |
f0b94e |
Some(tile) => (tile.x % 2 == 0) != (tile.y % 2 == 0),
|
|
Packit |
f0b94e |
None => true,
|
|
Packit |
f0b94e |
};
|
|
Packit |
f0b94e |
|
|
Packit |
f0b94e |
for y in 0 .. descriptor.height {
|
|
Packit |
f0b94e |
for x in 0 .. descriptor.width {
|
|
Packit |
f0b94e |
// Apply the tile's offset. This is important: all drawing commands should be
|
|
Packit |
f0b94e |
// translated by this offset to give correct results with tiled blob images.
|
|
Packit |
f0b94e |
let x2 = x + descriptor.offset.x as u32;
|
|
Packit |
f0b94e |
let y2 = y + descriptor.offset.y as u32;
|
|
Packit |
f0b94e |
|
|
Packit |
f0b94e |
// Render a simple checkerboard pattern
|
|
Packit |
f0b94e |
let checker = if (x2 % 20 >= 10) != (y2 % 20 >= 10) {
|
|
Packit |
f0b94e |
1
|
|
Packit |
f0b94e |
} else {
|
|
Packit |
f0b94e |
0
|
|
Packit |
f0b94e |
};
|
|
Packit |
f0b94e |
// ..nested in the per-tile cherkerboard pattern
|
|
Packit |
f0b94e |
let tc = if tile_checker { 0 } else { (1 - checker) * 40 };
|
|
Packit |
f0b94e |
|
|
Packit |
f0b94e |
match descriptor.format {
|
|
Packit |
f0b94e |
ImageFormat::BGRA8 => {
|
|
Packit |
f0b94e |
texels.push(color.b * checker + tc);
|
|
Packit |
f0b94e |
texels.push(color.g * checker + tc);
|
|
Packit |
f0b94e |
texels.push(color.r * checker + tc);
|
|
Packit |
f0b94e |
texels.push(color.a * checker + tc);
|
|
Packit |
f0b94e |
}
|
|
Packit |
f0b94e |
ImageFormat::R8 => {
|
|
Packit |
f0b94e |
texels.push(color.a * checker + tc);
|
|
Packit |
f0b94e |
}
|
|
Packit |
f0b94e |
_ => {
|
|
Packit |
f0b94e |
return Err(BlobImageError::Other(
|
|
Packit |
f0b94e |
format!("Usupported image format {:?}", descriptor.format),
|
|
Packit |
f0b94e |
));
|
|
Packit |
f0b94e |
}
|
|
Packit |
f0b94e |
}
|
|
Packit |
f0b94e |
}
|
|
Packit |
f0b94e |
}
|
|
Packit |
f0b94e |
|
|
Packit |
f0b94e |
Ok(RasterizedBlobImage {
|
|
Packit |
f0b94e |
data: texels,
|
|
Packit |
f0b94e |
width: descriptor.width,
|
|
Packit |
f0b94e |
height: descriptor.height,
|
|
Packit |
f0b94e |
})
|
|
Packit |
f0b94e |
}
|
|
Packit |
f0b94e |
|
|
Packit |
f0b94e |
pub struct BlobCallbacks {
|
|
Packit |
f0b94e |
pub request: Box<Fn(&BlobImageRequest) + Send + 'static>,
|
|
Packit |
f0b94e |
pub resolve: Box<Fn() + Send + 'static>,
|
|
Packit |
f0b94e |
}
|
|
Packit |
f0b94e |
|
|
Packit |
f0b94e |
impl BlobCallbacks {
|
|
Packit |
f0b94e |
pub fn new() -> Self {
|
|
Packit |
f0b94e |
BlobCallbacks { request: Box::new(|_|()), resolve: Box::new(|| (())) }
|
|
Packit |
f0b94e |
}
|
|
Packit |
f0b94e |
}
|
|
Packit |
f0b94e |
|
|
Packit |
f0b94e |
pub struct CheckerboardRenderer {
|
|
Packit |
f0b94e |
image_cmds: HashMap<ImageKey, ColorU>,
|
|
Packit |
f0b94e |
callbacks: Arc<Mutex<BlobCallbacks>>,
|
|
Packit |
f0b94e |
|
|
Packit |
f0b94e |
// The images rendered in the current frame (not kept here between frames).
|
|
Packit |
f0b94e |
rendered_images: HashMap<BlobImageRequest, BlobImageResult>,
|
|
Packit |
f0b94e |
}
|
|
Packit |
f0b94e |
|
|
Packit |
f0b94e |
impl CheckerboardRenderer {
|
|
Packit |
f0b94e |
pub fn new(callbacks: Arc<Mutex<BlobCallbacks>>) -> Self {
|
|
Packit |
f0b94e |
CheckerboardRenderer {
|
|
Packit |
f0b94e |
callbacks,
|
|
Packit |
f0b94e |
image_cmds: HashMap::new(),
|
|
Packit |
f0b94e |
rendered_images: HashMap::new(),
|
|
Packit |
f0b94e |
}
|
|
Packit |
f0b94e |
}
|
|
Packit |
f0b94e |
}
|
|
Packit |
f0b94e |
|
|
Packit |
f0b94e |
impl BlobImageRenderer for CheckerboardRenderer {
|
|
Packit |
f0b94e |
fn add(&mut self, key: ImageKey, cmds: BlobImageData, _: Option<TileSize>) {
|
|
Packit |
f0b94e |
self.image_cmds
|
|
Packit |
f0b94e |
.insert(key, deserialize_blob(&cmds[..]).unwrap());
|
|
Packit |
f0b94e |
}
|
|
Packit |
f0b94e |
|
|
Packit |
f0b94e |
fn update(&mut self, key: ImageKey, cmds: BlobImageData, _dirty_rect: Option<DeviceUintRect>) {
|
|
Packit |
f0b94e |
// Here, updating is just replacing the current version of the commands with
|
|
Packit |
f0b94e |
// the new one (no incremental updates).
|
|
Packit |
f0b94e |
self.image_cmds
|
|
Packit |
f0b94e |
.insert(key, deserialize_blob(&cmds[..]).unwrap());
|
|
Packit |
f0b94e |
}
|
|
Packit |
f0b94e |
|
|
Packit |
f0b94e |
fn delete(&mut self, key: ImageKey) {
|
|
Packit |
f0b94e |
self.image_cmds.remove(&key);
|
|
Packit |
f0b94e |
}
|
|
Packit |
f0b94e |
|
|
Packit |
f0b94e |
fn request(
|
|
Packit |
f0b94e |
&mut self,
|
|
Packit |
f0b94e |
_resources: &BlobImageResources,
|
|
Packit |
f0b94e |
request: BlobImageRequest,
|
|
Packit |
f0b94e |
descriptor: &BlobImageDescriptor,
|
|
Packit |
f0b94e |
_dirty_rect: Option<DeviceUintRect>,
|
|
Packit |
f0b94e |
) {
|
|
Packit |
f0b94e |
(self.callbacks.lock().unwrap().request)(&request);
|
|
Packit |
f0b94e |
assert!(!self.rendered_images.contains_key(&request));
|
|
Packit |
f0b94e |
// This method is where we kick off our rendering jobs.
|
|
Packit |
f0b94e |
// It should avoid doing work on the calling thread as much as possible.
|
|
Packit |
f0b94e |
// In this example we will use the thread pool to render individual tiles.
|
|
Packit |
f0b94e |
|
|
Packit |
f0b94e |
// Gather the input data to send to a worker thread.
|
|
Packit |
f0b94e |
let cmds = self.image_cmds.get(&request.key).unwrap();
|
|
Packit |
f0b94e |
|
|
Packit |
f0b94e |
let result = render_blob(*cmds, descriptor, request.tile);
|
|
Packit |
f0b94e |
|
|
Packit |
f0b94e |
self.rendered_images.insert(request, result);
|
|
Packit |
f0b94e |
}
|
|
Packit |
f0b94e |
|
|
Packit |
f0b94e |
fn resolve(&mut self, request: BlobImageRequest) -> BlobImageResult {
|
|
Packit |
f0b94e |
(self.callbacks.lock().unwrap().resolve)();
|
|
Packit |
f0b94e |
self.rendered_images.remove(&request).unwrap()
|
|
Packit |
f0b94e |
}
|
|
Packit |
f0b94e |
|
|
Packit |
f0b94e |
fn delete_font(&mut self, _key: FontKey) {}
|
|
Packit |
f0b94e |
|
|
Packit |
f0b94e |
fn delete_font_instance(&mut self, _key: FontInstanceKey) {}
|
|
Packit |
f0b94e |
}
|