diff options
author | Jack Moffitt <jack@metajack.im> | 2014-08-28 09:34:23 -0600 |
---|---|---|
committer | Jack Moffitt <jack@metajack.im> | 2014-09-08 20:21:42 -0600 |
commit | c6ab60dbfc6da7b4f800c9e40893c8b58413960c (patch) | |
tree | d1d74076cf7fa20e4f77ec7cb82cae98b67362cb /components/net/image | |
parent | db2f642c32fc5bed445bb6f2e45b0f6f0b4342cf (diff) | |
download | servo-c6ab60dbfc6da7b4f800c9e40893c8b58413960c.tar.gz servo-c6ab60dbfc6da7b4f800c9e40893c8b58413960c.zip |
Cargoify servo
Diffstat (limited to 'components/net/image')
-rw-r--r-- | components/net/image/base.rs | 67 | ||||
-rw-r--r-- | components/net/image/holder.rs | 109 | ||||
-rw-r--r-- | components/net/image/test.jpeg | bin | 0 -> 4962 bytes |
3 files changed, 176 insertions, 0 deletions
diff --git a/components/net/image/base.rs b/components/net/image/base.rs new file mode 100644 index 00000000000..deda4ee8556 --- /dev/null +++ b/components/net/image/base.rs @@ -0,0 +1,67 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use std::iter::range_step; +use stb_image = stb_image::image; +use png; + +// FIXME: Images must not be copied every frame. Instead we should atomically +// reference count them. +pub type Image = png::Image; + + +static TEST_IMAGE: &'static [u8] = include_bin!("test.jpeg"); + +pub fn test_image_bin() -> Vec<u8> { + TEST_IMAGE.iter().map(|&x| x).collect() +} + +// TODO(pcwalton): Speed up with SIMD, or better yet, find some way to not do this. +fn byte_swap(data: &mut [u8]) { + let length = data.len(); + for i in range_step(0, length, 4) { + let r = data[i + 2]; + data[i + 2] = data[i + 0]; + data[i + 0] = r; + } +} + +pub fn load_from_memory(buffer: &[u8]) -> Option<Image> { + if buffer.len() == 0 { + return None; + } + + if png::is_png(buffer) { + match png::load_png_from_memory(buffer) { + Ok(mut png_image) => { + match png_image.pixels { + png::RGB8(ref mut data) | png::RGBA8(ref mut data) => { + byte_swap(data.as_mut_slice()); + } + _ => {} + } + Some(png_image) + } + Err(_err) => None, + } + } else { + // For non-png images, we use stb_image + // Can't remember why we do this. Maybe it's what cairo wants + static FORCE_DEPTH: uint = 4; + + match stb_image::load_from_memory_with_depth(buffer, FORCE_DEPTH, true) { + stb_image::ImageU8(mut image) => { + assert!(image.depth == 4); + byte_swap(image.data.as_mut_slice()); + Some(png::Image { + width: image.width as u32, + height: image.height as u32, + pixels: png::RGBA8(image.data) + }) + } + stb_image::ImageF32(_image) => fail!("HDR images not implemented"), + stb_image::Error(_) => None + } + } +} diff --git a/components/net/image/holder.rs b/components/net/image/holder.rs new file mode 100644 index 00000000000..11f055aad9d --- /dev/null +++ b/components/net/image/holder.rs @@ -0,0 +1,109 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use image::base::Image; +use image_cache_task::{ImageReady, ImageNotReady, ImageFailed}; +use local_image_cache::LocalImageCache; + +use geom::size::Size2D; +use std::mem; +use sync::{Arc, Mutex}; +use url::Url; + +// FIXME: Nasty coupling here This will be a problem if we want to factor out image handling from +// the network stack. This should probably be factored out into an interface and use dependency +// injection. + +/// A struct to store image data. The image will be loaded once the first time it is requested, +/// and an Arc will be stored. Clones of this Arc are given out on demand. +#[deriving(Clone)] +pub struct ImageHolder { + url: Url, + image: Option<Arc<Box<Image>>>, + cached_size: Size2D<int>, + local_image_cache: Arc<Mutex<LocalImageCache>>, +} + +impl ImageHolder { + pub fn new(url: Url, local_image_cache: Arc<Mutex<LocalImageCache>>) -> ImageHolder { + debug!("ImageHolder::new() {}", url.serialize()); + let holder = ImageHolder { + url: url, + image: None, + cached_size: Size2D(0,0), + local_image_cache: local_image_cache.clone(), + }; + + // Tell the image cache we're going to be interested in this url + // FIXME: These two messages must be sent to prep an image for use + // but they are intended to be spread out in time. Ideally prefetch + // should be done as early as possible and decode only once we + // are sure that the image will be used. + { + let val = holder.local_image_cache.lock(); + let mut local_image_cache = val; + local_image_cache.prefetch(&holder.url); + local_image_cache.decode(&holder.url); + } + + holder + } + + /// This version doesn't perform any computation, but may be stale w.r.t. newly-available image + /// data that determines size. + /// + /// The intent is that the impure version is used during layout when dimensions are used for + /// computing layout. + pub fn size(&self) -> Size2D<int> { + self.cached_size + } + + /// Query and update the current image size. + pub fn get_size(&mut self) -> Option<Size2D<int>> { + debug!("get_size() {}", self.url.serialize()); + self.get_image().map(|img| { + self.cached_size = Size2D(img.width as int, + img.height as int); + self.cached_size.clone() + }) + } + + pub fn get_image_if_present(&self) -> Option<Arc<Box<Image>>> { + debug!("get_image_if_present() {}", self.url.serialize()); + self.image.clone() + } + + pub fn get_image(&mut self) -> Option<Arc<Box<Image>>> { + debug!("get_image() {}", self.url.serialize()); + + // If this is the first time we've called this function, load + // the image and store it for the future + if self.image.is_none() { + let port = { + let val = self.local_image_cache.lock(); + let mut local_image_cache = val; + local_image_cache.get_image(&self.url) + }; + match port.recv() { + ImageReady(image) => { + self.image = Some(image); + } + ImageNotReady => { + debug!("image not ready for {:s}", self.url.serialize()); + } + ImageFailed => { + debug!("image decoding failed for {:s}", self.url.serialize()); + } + } + } + + // Clone isn't pure so we have to swap out the mutable image option + let image = mem::replace(&mut self.image, None); + let result = image.clone(); + mem::replace(&mut self.image, image); + + return result; + } +} + diff --git a/components/net/image/test.jpeg b/components/net/image/test.jpeg Binary files differnew file mode 100644 index 00000000000..1a0bdb7acd1 --- /dev/null +++ b/components/net/image/test.jpeg |