aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbors-servo <lbergstrom+bors@mozilla.com>2016-01-31 01:18:41 +0530
committerbors-servo <lbergstrom+bors@mozilla.com>2016-01-31 01:18:41 +0530
commit46b3eb653579a40632f91497a3d48f1d7fbd40cc (patch)
treee45b6e5fcc181c7c8eb9647c1ba8f27f857bd86f
parentf8bdda499ef8c13f65cbc20215bd36dbc42b6439 (diff)
parent167ffa7a95ae0068d2b4f900d2207436a1799675 (diff)
downloadservo-46b3eb653579a40632f91497a3d48f1d7fbd40cc.tar.gz
servo-46b3eb653579a40632f91497a3d48f1d7fbd40cc.zip
Auto merge of #9208 - jmr0:master-img, r=asajeffrey
Use image metadata to lay out images Fixes #7047. cc: @jdm <!-- Reviewable:start --> [<img src="https://reviewable.io/review_button.png" height=40 alt="Review on Reviewable"/>](https://reviewable.io/reviews/servo/servo/9208) <!-- Reviewable:end -->
-rw-r--r--components/layout/context.rs51
-rw-r--r--components/layout/fragment.rs38
-rw-r--r--components/msg/constellation_msg.rs6
-rw-r--r--components/net/Cargo.toml1
-rw-r--r--components/net/image_cache_thread.rs114
-rw-r--r--components/net/lib.rs1
-rw-r--r--components/net_traits/image/base.rs2
-rw-r--r--components/net_traits/image_cache_thread.rs47
-rw-r--r--components/script/dom/bindings/trace.rs4
-rw-r--r--components/script/dom/canvasrenderingcontext2d.rs2
-rw-r--r--components/script/dom/htmlimageelement.rs33
-rw-r--r--components/script/dom/webglrenderingcontext.rs3
-rw-r--r--components/servo/Cargo.lock10
-rw-r--r--ports/cef/Cargo.lock10
-rw-r--r--ports/gonk/Cargo.lock10
15 files changed, 269 insertions, 63 deletions
diff --git a/components/layout/context.rs b/components/layout/context.rs
index 83f2df1412a..53bb036d09c 100644
--- a/components/layout/context.rs
+++ b/components/layout/context.rs
@@ -17,7 +17,7 @@ use gfx_traits::LayerId;
use ipc_channel::ipc::{self, IpcSender};
use net_traits::image::base::Image;
use net_traits::image_cache_thread::{ImageCacheChan, ImageCacheThread, ImageResponse, ImageState};
-use net_traits::image_cache_thread::{UsePlaceholder};
+use net_traits::image_cache_thread::{ImageOrMetadataAvailable, UsePlaceholder};
use std::cell::{RefCell, RefMut};
use std::collections::HashMap;
use std::collections::hash_state::DefaultState;
@@ -155,7 +155,7 @@ impl<'a> LayoutContext<'a> {
match sync_rx.recv().unwrap().image_response {
ImageResponse::Loaded(image) |
ImageResponse::PlaceholderLoaded(image) => Some(image),
- ImageResponse::None => None,
+ ImageResponse::None | ImageResponse::MetadataLoaded(_) => None,
}
}
// Not yet requested, async mode - request image from the cache
@@ -172,4 +172,51 @@ impl<'a> LayoutContext<'a> {
}
}
}
+
+ pub fn get_or_request_image_or_meta(&self, url: Url, use_placeholder: UsePlaceholder)
+ -> Option<ImageOrMetadataAvailable> {
+ // See if the image is already available
+ let result = self.shared.image_cache_thread.find_image_or_metadata(url.clone(),
+ use_placeholder);
+
+ match result {
+ Ok(image_or_metadata) => Some(image_or_metadata),
+ Err(state) => {
+ // If we are emitting an output file, then we need to block on
+ // image load or we risk emitting an output file missing the image.
+ let is_sync = opts::get().output_file.is_some() ||
+ opts::get().exit_after_load;
+
+ match (state, is_sync) {
+ // Image failed to load, so just return nothing
+ (ImageState::LoadError, _) => None,
+ // Not loaded, test mode - load the image synchronously
+ (_, true) => {
+ let (sync_tx, sync_rx) = ipc::channel().unwrap();
+ self.shared.image_cache_thread.request_image(url,
+ ImageCacheChan(sync_tx),
+ None);
+ match sync_rx.recv().unwrap().image_response {
+ ImageResponse::Loaded(image) |
+ ImageResponse::PlaceholderLoaded(image) =>
+ Some(ImageOrMetadataAvailable::ImageAvailable(image)),
+ ImageResponse::None | ImageResponse::MetadataLoaded(_) =>
+ None,
+ }
+ }
+ // Not yet requested, async mode - request image or metadata from the cache
+ (ImageState::NotRequested, false) => {
+ let sender = self.shared.image_cache_sender.lock().unwrap().clone();
+ self.shared.image_cache_thread.request_image_and_metadata(url, sender, None);
+ None
+ }
+ // Image has been requested, is still pending. Return no image
+ // for this paint loop. When the image loads it will trigger
+ // a reflow and/or repaint.
+ (ImageState::Pending, false) => None,
+ }
+ }
+ }
+ }
+
}
diff --git a/components/layout/fragment.rs b/components/layout/fragment.rs
index 9fa563ce20d..45ffac1c659 100644
--- a/components/layout/fragment.rs
+++ b/components/layout/fragment.rs
@@ -25,8 +25,8 @@ use ipc_channel::ipc::IpcSender;
use layout_debug;
use model::{self, IntrinsicISizes, IntrinsicISizesContribution, MaybeAuto, specified};
use msg::constellation_msg::PipelineId;
-use net_traits::image::base::Image;
-use net_traits::image_cache_thread::UsePlaceholder;
+use net_traits::image::base::{Image, ImageMetadata};
+use net_traits::image_cache_thread::{ImageOrMetadataAvailable, UsePlaceholder};
use rustc_serialize::{Encodable, Encoder};
use script::dom::htmlcanvaselement::HTMLCanvasData;
use std::borrow::ToOwned;
@@ -344,6 +344,7 @@ pub struct ImageFragmentInfo {
/// The image held within this fragment.
pub replaced_image_fragment_info: ReplacedImageFragmentInfo,
pub image: Option<Arc<Image>>,
+ pub metadata: Option<ImageMetadata>,
}
impl ImageFragmentInfo {
@@ -361,26 +362,39 @@ impl ImageFragmentInfo {
.map(Au::from_px)
}
- let image = url.and_then(|url| {
- layout_context.get_or_request_image(url, UsePlaceholder::Yes)
+ let image_or_metadata = url.and_then(|url| {
+ layout_context.get_or_request_image_or_meta(url, UsePlaceholder::Yes)
});
+ let (image, metadata) = match image_or_metadata {
+ Some(ImageOrMetadataAvailable::ImageAvailable(i)) => {
+ (Some(i.clone()), Some(ImageMetadata { height: i.height, width: i.width } ))
+ }
+ Some(ImageOrMetadataAvailable::MetadataAvailable(m)) => {
+ (None, Some(m))
+ }
+ None => {
+ (None, None)
+ }
+ };
+
ImageFragmentInfo {
replaced_image_fragment_info: ReplacedImageFragmentInfo::new(node,
convert_length(node, &atom!("width")),
convert_length(node, &atom!("height"))),
image: image,
+ metadata: metadata,
}
}
/// Returns the original inline-size of the image.
pub fn image_inline_size(&mut self) -> Au {
- match self.image {
- Some(ref image) => {
+ match self.metadata {
+ Some(ref metadata) => {
Au::from_px(if self.replaced_image_fragment_info.writing_mode_is_vertical {
- image.height
+ metadata.height
} else {
- image.width
+ metadata.width
} as i32)
}
None => Au(0)
@@ -389,12 +403,12 @@ impl ImageFragmentInfo {
/// Returns the original block-size of the image.
pub fn image_block_size(&mut self) -> Au {
- match self.image {
- Some(ref image) => {
+ match self.metadata {
+ Some(ref metadata) => {
Au::from_px(if self.replaced_image_fragment_info.writing_mode_is_vertical {
- image.width
+ metadata.width
} else {
- image.height
+ metadata.height
} as i32)
}
None => Au(0)
diff --git a/components/msg/constellation_msg.rs b/components/msg/constellation_msg.rs
index ba971992a93..2ce14039a15 100644
--- a/components/msg/constellation_msg.rs
+++ b/components/msg/constellation_msg.rs
@@ -216,6 +216,12 @@ pub enum PixelFormat {
RGBA8, // RGB + alpha, 8 bits per channel
}
+#[derive(Clone, Deserialize, Eq, PartialEq, Serialize, HeapSizeOf)]
+pub struct ImageMetadata {
+ pub width: u32,
+ pub height: u32,
+}
+
#[derive(Deserialize, Serialize, HeapSizeOf)]
pub struct Image {
pub width: u32,
diff --git a/components/net/Cargo.toml b/components/net/Cargo.toml
index 3381bc2a131..608cbee0791 100644
--- a/components/net/Cargo.toml
+++ b/components/net/Cargo.toml
@@ -40,3 +40,4 @@ flate2 = "0.2.0"
uuid = "0.1.16"
url = "0.5.2"
websocket = "0.14.0"
+immeta = "0.2"
diff --git a/components/net/image_cache_thread.rs b/components/net/image_cache_thread.rs
index 98075ab3443..e7d960068e0 100644
--- a/components/net/image_cache_thread.rs
+++ b/components/net/image_cache_thread.rs
@@ -2,12 +2,13 @@
* 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 immeta::load_from_buf;
use ipc_channel::ipc::{self, IpcSender};
use ipc_channel::router::ROUTER;
-use net_traits::image::base::{Image, load_from_memory};
+use net_traits::image::base::{Image, ImageMetadata, load_from_memory};
use net_traits::image_cache_thread::ImageResponder;
use net_traits::image_cache_thread::{ImageCacheChan, ImageCacheCommand, ImageCacheThread, ImageState};
-use net_traits::image_cache_thread::{ImageCacheResult, ImageResponse, UsePlaceholder};
+use net_traits::image_cache_thread::{ImageCacheResult, ImageOrMetadataAvailable, ImageResponse, UsePlaceholder};
use net_traits::{AsyncResponseTarget, ControlMsg, LoadConsumer, LoadData, ResourceThread};
use net_traits::{ResponseAction, LoadContext};
use std::borrow::ToOwned;
@@ -38,6 +39,9 @@ struct PendingLoad {
// is complete and the buffer has been transmitted to the decoder.
bytes: Vec<u8>,
+ // Image metadata, if available.
+ metadata: Option<ImageMetadata>,
+
// Once loading is complete, the result of the operation.
result: Option<Result<(), String>>,
listeners: Vec<ImageListener>,
@@ -51,6 +55,7 @@ impl PendingLoad {
fn new(url: Arc<Url>) -> PendingLoad {
PendingLoad {
bytes: vec!(),
+ metadata: None,
result: None,
listeners: vec!(),
url: url,
@@ -165,6 +170,7 @@ impl CompletedLoad {
struct ImageListener {
sender: ImageCacheChan,
responder: Option<ImageResponder>,
+ send_metadata_msg: bool,
}
// A key used to communicate during loading.
@@ -188,17 +194,24 @@ impl LoadKeyGenerator {
}
impl ImageListener {
- fn new(sender: ImageCacheChan, responder: Option<ImageResponder>) -> ImageListener {
+ fn new(sender: ImageCacheChan, responder: Option<ImageResponder>, send_metadata_msg: bool) -> ImageListener {
ImageListener {
sender: sender,
responder: responder,
+ send_metadata_msg: send_metadata_msg,
}
}
- fn notify(self, image_response: ImageResponse) {
+ fn notify(&self, image_response: ImageResponse) {
+ if !self.send_metadata_msg {
+ if let ImageResponse::MetadataLoaded(_) = image_response {
+ return;
+ }
+ }
+
let ImageCacheChan(ref sender) = self.sender;
let msg = ImageCacheResult {
- responder: self.responder,
+ responder: self.responder.clone(),
image_response: image_response,
};
sender.send(msg).ok();
@@ -310,27 +323,17 @@ impl ImageCache {
return Some(sender);
}
ImageCacheCommand::RequestImage(url, result_chan, responder) => {
- self.request_image(url, result_chan, responder);
+ self.request_image(url, result_chan, responder, false);
+ }
+ ImageCacheCommand::RequestImageAndMetadata(url, result_chan, responder) => {
+ self.request_image(url, result_chan, responder, true);
}
ImageCacheCommand::GetImageIfAvailable(url, use_placeholder, consumer) => {
- let result = match self.completed_loads.get(&url) {
- Some(completed_load) => {
- match (completed_load.image_response.clone(), use_placeholder) {
- (ImageResponse::Loaded(image), _) |
- (ImageResponse::PlaceholderLoaded(image), UsePlaceholder::Yes) => {
- Ok(image)
- }
- (ImageResponse::PlaceholderLoaded(_), UsePlaceholder::No) |
- (ImageResponse::None, _) => {
- Err(ImageState::LoadError)
- }
- }
- }
- None => {
- self.pending_loads.get_by_url(&url).
- map_or(Err(ImageState::NotRequested), |_| Err(ImageState::Pending))
- }
- };
+ let result = self.get_image_if_available(url, use_placeholder);
+ consumer.send(result).unwrap();
+ }
+ ImageCacheCommand::GetImageOrMetadataIfAvailable(url, use_placeholder, consumer) => {
+ let result = self.get_image_or_meta_if_available(url, use_placeholder);
consumer.send(result).unwrap();
}
};
@@ -345,13 +348,24 @@ impl ImageCache {
(ResponseAction::DataAvailable(data), _) => {
let pending_load = self.pending_loads.get_by_key_mut(&msg.key).unwrap();
pending_load.bytes.extend_from_slice(&data);
+ //jmr0 TODO: possibly move to another task?
+ if let None = pending_load.metadata {
+ if let Ok(metadata) = load_from_buf(&pending_load.bytes) {
+ let dimensions = metadata.dimensions();
+ let img_metadata = ImageMetadata { width: dimensions.width,
+ height: dimensions.height };
+ pending_load.metadata = Some(img_metadata.clone());
+ for listener in &pending_load.listeners {
+ listener.notify(ImageResponse::MetadataLoaded(img_metadata.clone()).clone());
+ }
+ }
+ }
}
(ResponseAction::ResponseComplete(result), key) => {
match result {
Ok(()) => {
let pending_load = self.pending_loads.get_by_key_mut(&msg.key).unwrap();
pending_load.result = Some(result);
-
let bytes = mem::replace(&mut pending_load.bytes, vec!());
let sender = self.decoder_sender.clone();
@@ -401,12 +415,15 @@ impl ImageCache {
// Request an image from the cache. If the image hasn't been
// loaded/decoded yet, it will be loaded/decoded in the
- // background.
+ // background. If send_metadata_msg is set, the channel will be notified
+ // that image metadata is available, possibly before the image has finished
+ // loading.
fn request_image(&mut self,
url: Url,
result_chan: ImageCacheChan,
- responder: Option<ImageResponder>) {
- let image_listener = ImageListener::new(result_chan, responder);
+ responder: Option<ImageResponder>,
+ send_metadata_msg: bool) {
+ let image_listener = ImageListener::new(result_chan, responder, send_metadata_msg);
// Let's avoid copying url everywhere.
let ref_url = Arc::new(url);
@@ -449,6 +466,47 @@ impl ImageCache {
}
}
}
+
+ fn get_image_if_available(&mut self,
+ url: Url,
+ placeholder: UsePlaceholder, )
+ -> Result<Arc<Image>, ImageState> {
+ let img_or_metadata = self.get_image_or_meta_if_available(url, placeholder);
+ match img_or_metadata {
+ Ok(ImageOrMetadataAvailable::ImageAvailable(image)) => Ok(image),
+ Ok(ImageOrMetadataAvailable::MetadataAvailable(_)) => Err(ImageState::Pending),
+ Err(err) => Err(err),
+ }
+ }
+
+ fn get_image_or_meta_if_available(&mut self,
+ url: Url,
+ placeholder: UsePlaceholder)
+ -> Result<ImageOrMetadataAvailable, ImageState> {
+ match self.completed_loads.get(&url) {
+ Some(completed_load) => {
+ match (completed_load.image_response.clone(), placeholder) {
+ (ImageResponse::Loaded(image), _) |
+ (ImageResponse::PlaceholderLoaded(image), UsePlaceholder::Yes) => {
+ Ok(ImageOrMetadataAvailable::ImageAvailable(image))
+ }
+ (ImageResponse::PlaceholderLoaded(_), UsePlaceholder::No) |
+ (ImageResponse::None, _) |
+ (ImageResponse::MetadataLoaded(_), _) => {
+ Err(ImageState::LoadError)
+ }
+ }
+ }
+ None => {
+ self.pending_loads.get_by_url(&url).as_ref().
+ map_or(Err(ImageState::NotRequested), |pl| pl.metadata.as_ref().
+ map_or(Err(ImageState::Pending), |meta|
+ Ok(ImageOrMetadataAvailable::MetadataAvailable(meta.clone()))
+ )
+ )
+ }
+ }
+ }
}
/// Create a new image cache.
diff --git a/components/net/lib.rs b/components/net/lib.rs
index 0c434475177..143672962cb 100644
--- a/components/net/lib.rs
+++ b/components/net/lib.rs
@@ -14,6 +14,7 @@ extern crate cookie as cookie_rs;
extern crate devtools_traits;
extern crate flate2;
extern crate hyper;
+extern crate immeta;
extern crate ipc_channel;
#[macro_use]
extern crate log;
diff --git a/components/net_traits/image/base.rs b/components/net_traits/image/base.rs
index 65fc9eeaa15..7faf439e34b 100644
--- a/components/net_traits/image/base.rs
+++ b/components/net_traits/image/base.rs
@@ -7,7 +7,7 @@ use piston_image::{self, DynamicImage, GenericImage, ImageFormat};
use stb_image::image as stb_image2;
use util::vec::byte_swap;
-pub use msg::constellation_msg::{Image, PixelFormat};
+pub use msg::constellation_msg::{Image, ImageMetadata, PixelFormat};
// FIXME: Images must not be copied every frame. Instead we should atomically
// reference count them.
diff --git a/components/net_traits/image_cache_thread.rs b/components/net_traits/image_cache_thread.rs
index 85ef01be4f6..2381efbb997 100644
--- a/components/net_traits/image_cache_thread.rs
+++ b/components/net_traits/image_cache_thread.rs
@@ -3,7 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use ipc_channel::ipc::{self, IpcSender};
-use msg::constellation_msg::Image;
+use msg::constellation_msg::{Image, ImageMetadata};
use std::sync::Arc;
use url::Url;
use util::mem::HeapSizeOf;
@@ -12,7 +12,7 @@ use util::mem::HeapSizeOf;
/// and image, and returned to the specified event loop when the
/// image load completes. It is typically used to trigger a reflow
/// and/or repaint.
-#[derive(Deserialize, Serialize)]
+#[derive(Clone, Deserialize, Serialize)]
pub struct ImageResponder {
sender: IpcSender<ImageResponse>,
}
@@ -42,13 +42,22 @@ pub enum ImageState {
pub enum ImageResponse {
/// The requested image was loaded.
Loaded(Arc<Image>),
+ /// The request image metadata was loaded.
+ MetadataLoaded(ImageMetadata),
/// The requested image failed to load, so a placeholder was loaded instead.
PlaceholderLoaded(Arc<Image>),
/// Neither the requested image nor the placeholder could be loaded.
None
}
-/// Channel for sending commands to the image cache.
+/// Indicating either entire image or just metadata availability
+#[derive(Clone, Deserialize, Serialize, HeapSizeOf)]
+pub enum ImageOrMetadataAvailable {
+ ImageAvailable(Arc<Image>),
+ MetadataAvailable(ImageMetadata),
+}
+
+/// Channel used by the image cache to send results.
#[derive(Clone, Deserialize, Serialize)]
pub struct ImageCacheChan(pub IpcSender<ImageCacheResult>);
@@ -68,12 +77,22 @@ pub enum ImageCacheCommand {
/// that is passed to the result channel.
RequestImage(Url, ImageCacheChan, Option<ImageResponder>),
+ /// Requests an image and a "metadata-ready" notification message asynchronously from the
+ /// cache. The cache will make an effort to send metadata before the image is completely
+ /// loaded. Supply a channel to receive the results, and optionally an image responder
+ /// that is passed to the result channel.
+ RequestImageAndMetadata(Url, ImageCacheChan, Option<ImageResponder>),
+
/// Synchronously check the state of an image in the cache.
/// TODO(gw): Profile this on some real world sites and see
/// if it's worth caching the results of this locally in each
/// layout / paint thread.
GetImageIfAvailable(Url, UsePlaceholder, IpcSender<Result<Arc<Image>, ImageState>>),
+ /// Synchronously check the state of an image in the cache. If the image is in a loading
+ /// state and but its metadata has been made available, it will be sent as a response.
+ GetImageOrMetadataIfAvailable(Url, UsePlaceholder, IpcSender<Result<ImageOrMetadataAvailable, ImageState>>),
+
/// Clients must wait for a response before shutting down the ResourceThread
Exit(IpcSender<()>),
}
@@ -101,7 +120,7 @@ impl ImageCacheThread {
}
}
- /// Asynchronously request and image. See ImageCacheCommand::RequestImage.
+ /// Asynchronously request an image. See ImageCacheCommand::RequestImage.
pub fn request_image(&self,
url: Url,
result_chan: ImageCacheChan,
@@ -110,6 +129,16 @@ impl ImageCacheThread {
self.chan.send(msg).unwrap();
}
+ /// Asynchronously request an image and metadata.
+ /// See ImageCacheCommand::RequestImageAndMetadata
+ pub fn request_image_and_metadata(&self,
+ url: Url,
+ result_chan: ImageCacheChan,
+ responder: Option<ImageResponder>) {
+ let msg = ImageCacheCommand::RequestImageAndMetadata(url, result_chan, responder);
+ self.chan.send(msg).unwrap();
+ }
+
/// Get the current state of an image. See ImageCacheCommand::GetImageIfAvailable.
pub fn find_image(&self, url: Url, use_placeholder: UsePlaceholder)
-> Result<Arc<Image>, ImageState> {
@@ -119,6 +148,16 @@ impl ImageCacheThread {
receiver.recv().unwrap()
}
+ /// Get the current state of an image, returning its metadata if available.
+ /// See ImageCacheCommand::GetImageOrMetadataIfAvailable.
+ pub fn find_image_or_metadata(&self, url: Url, use_placeholder: UsePlaceholder)
+ -> Result<ImageOrMetadataAvailable, ImageState> {
+ let (sender, receiver) = ipc::channel().unwrap();
+ let msg = ImageCacheCommand::GetImageOrMetadataIfAvailable(url, use_placeholder, sender);
+ self.chan.send(msg).unwrap();
+ receiver.recv().unwrap()
+ }
+
/// Shutdown the image cache thread.
pub fn exit(&self) {
let (response_chan, response_port) = ipc::channel().unwrap();
diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs
index 31dcc99daaa..dec38c26565 100644
--- a/components/script/dom/bindings/trace.rs
+++ b/components/script/dom/bindings/trace.rs
@@ -58,7 +58,7 @@ use libc;
use msg::constellation_msg::ConstellationChan;
use msg::constellation_msg::{PipelineId, SubpageId, WindowSizeData};
use net_traits::Metadata;
-use net_traits::image::base::Image;
+use net_traits::image::base::{Image, ImageMetadata};
use net_traits::image_cache_thread::{ImageCacheChan, ImageCacheThread};
use net_traits::storage_thread::StorageType;
use profile_traits::mem::ProfilerChan as MemProfilerChan;
@@ -265,7 +265,7 @@ no_jsmanaged_fields!(Receiver<T>);
no_jsmanaged_fields!(Rect<T>);
no_jsmanaged_fields!(Size2D<T>);
no_jsmanaged_fields!(Arc<T>);
-no_jsmanaged_fields!(Image, ImageCacheChan, ImageCacheThread);
+no_jsmanaged_fields!(Image, ImageMetadata, ImageCacheChan, ImageCacheThread);
no_jsmanaged_fields!(Metadata);
no_jsmanaged_fields!(Atom, Namespace, QualName);
no_jsmanaged_fields!(Trusted<T: Reflectable>);
diff --git a/components/script/dom/canvasrenderingcontext2d.rs b/components/script/dom/canvasrenderingcontext2d.rs
index 346ecb9680d..f4f1e2c51a7 100644
--- a/components/script/dom/canvasrenderingcontext2d.rs
+++ b/components/script/dom/canvasrenderingcontext2d.rs
@@ -444,7 +444,7 @@ impl CanvasRenderingContext2D {
let img = match self.request_image_from_cache(url) {
ImageResponse::Loaded(img) => img,
- ImageResponse::PlaceholderLoaded(_) | ImageResponse::None => {
+ ImageResponse::PlaceholderLoaded(_) | ImageResponse::None | ImageResponse::MetadataLoaded(_) => {
return None;
}
};
diff --git a/components/script/dom/htmlimageelement.rs b/components/script/dom/htmlimageelement.rs
index 6474d360a75..a6b124939f0 100644
--- a/components/script/dom/htmlimageelement.rs
+++ b/components/script/dom/htmlimageelement.rs
@@ -21,7 +21,7 @@ use dom::node::{Node, NodeDamage, document_from_node, window_from_node};
use dom::virtualmethods::VirtualMethods;
use ipc_channel::ipc;
use ipc_channel::router::ROUTER;
-use net_traits::image::base::Image;
+use net_traits::image::base::{Image, ImageMetadata};
use net_traits::image_cache_thread::{ImageResponder, ImageResponse};
use script_thread::ScriptThreadEventCategory::UpdateReplacedElement;
use script_thread::{CommonScriptMsg, Runnable, ScriptChan};
@@ -35,6 +35,7 @@ pub struct HTMLImageElement {
htmlelement: HTMLElement,
url: DOMRefCell<Option<Url>>,
image: DOMRefCell<Option<Arc<Image>>>,
+ metadata: DOMRefCell<Option<ImageMetadata>>,
}
impl HTMLImageElement {
@@ -64,12 +65,17 @@ impl Runnable for ImageResponseHandlerRunnable {
// Update the image field
let element = self.element.root();
let element_ref = element.r();
- *element_ref.image.borrow_mut() = match self.image {
+ let (image, metadata, trigger_image_load) = match self.image {
ImageResponse::Loaded(image) | ImageResponse::PlaceholderLoaded(image) => {
- Some(image)
+ (Some(image.clone()), Some(ImageMetadata { height: image.height, width: image.width } ), true)
}
- ImageResponse::None => None,
+ ImageResponse::MetadataLoaded(meta) => {
+ (None, Some(meta), false)
+ }
+ ImageResponse::None => (None, None, true)
};
+ *element_ref.image.borrow_mut() = image;
+ *element_ref.metadata.borrow_mut() = metadata;
// Mark the node dirty
let document = document_from_node(&*element);
@@ -77,7 +83,9 @@ impl Runnable for ImageResponseHandlerRunnable {
// Fire image.onload
let window = window_from_node(document.r());
- element.upcast::<EventTarget>().fire_simple_event("load", GlobalRef::Window(window.r()));
+ if trigger_image_load {
+ element.upcast::<EventTarget>().fire_simple_event("load", GlobalRef::Window(window.r()));
+ }
// Trigger reflow
window.add_pending_reflow();
}
@@ -116,7 +124,7 @@ impl HTMLImageElement {
UpdateReplacedElement, runnable));
});
- image_cache.request_image(img_url,
+ image_cache.request_image_and_metadata(img_url,
window.image_cache_chan(),
Some(ImageResponder::new(responder_sender)));
}
@@ -128,6 +136,7 @@ impl HTMLImageElement {
htmlelement: HTMLElement::new_inherited(localName, prefix, document),
url: DOMRefCell::new(None),
image: DOMRefCell::new(None),
+ metadata: DOMRefCell::new(None),
}
}
@@ -218,20 +227,20 @@ impl HTMLImageElementMethods for HTMLImageElement {
// https://html.spec.whatwg.org/multipage/#dom-img-naturalwidth
fn NaturalWidth(&self) -> u32 {
- let image = self.image.borrow();
+ let metadata = self.metadata.borrow();
- match *image {
- Some(ref image) => image.width,
+ match *metadata {
+ Some(ref metadata) => metadata.width,
None => 0,
}
}
// https://html.spec.whatwg.org/multipage/#dom-img-naturalheight
fn NaturalHeight(&self) -> u32 {
- let image = self.image.borrow();
+ let metadata = self.metadata.borrow();
- match *image {
- Some(ref image) => image.height,
+ match *metadata {
+ Some(ref metadata) => metadata.height,
None => 0,
}
}
diff --git a/components/script/dom/webglrenderingcontext.rs b/components/script/dom/webglrenderingcontext.rs
index 5d6199664b7..51d9f3a12c8 100644
--- a/components/script/dom/webglrenderingcontext.rs
+++ b/components/script/dom/webglrenderingcontext.rs
@@ -1138,7 +1138,8 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
let img = match canvas_utils::request_image_from_cache(window.r(), img_url) {
ImageResponse::Loaded(img) => img,
- ImageResponse::PlaceholderLoaded(_) | ImageResponse::None
+ ImageResponse::PlaceholderLoaded(_) | ImageResponse::None |
+ ImageResponse::MetadataLoaded(_)
=> return,
};
diff --git a/components/servo/Cargo.lock b/components/servo/Cargo.lock
index c4f1d112d71..57069e9b9ea 100644
--- a/components/servo/Cargo.lock
+++ b/components/servo/Cargo.lock
@@ -854,6 +854,15 @@ dependencies = [
]
[[package]]
+name = "immeta"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "byteorder 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "inflate"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1151,6 +1160,7 @@ dependencies = [
"devtools_traits 0.0.1",
"flate2 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"hyper 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "immeta 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
"ipc-channel 0.2.0 (git+https://github.com/servo/ipc-channel)",
"log 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"mime_guess 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
diff --git a/ports/cef/Cargo.lock b/ports/cef/Cargo.lock
index 49fa2d65ec1..6e3ab36d065 100644
--- a/ports/cef/Cargo.lock
+++ b/ports/cef/Cargo.lock
@@ -813,6 +813,15 @@ dependencies = [
]
[[package]]
+name = "immeta"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "byteorder 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "inflate"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1110,6 +1119,7 @@ dependencies = [
"devtools_traits 0.0.1",
"flate2 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"hyper 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "immeta 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
"ipc-channel 0.2.0 (git+https://github.com/servo/ipc-channel)",
"log 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"mime_guess 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
diff --git a/ports/gonk/Cargo.lock b/ports/gonk/Cargo.lock
index 19df79d24a7..927004350de 100644
--- a/ports/gonk/Cargo.lock
+++ b/ports/gonk/Cargo.lock
@@ -784,6 +784,15 @@ dependencies = [
]
[[package]]
+name = "immeta"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "byteorder 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "inflate"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1081,6 +1090,7 @@ dependencies = [
"devtools_traits 0.0.1",
"flate2 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"hyper 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "immeta 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
"ipc-channel 0.2.0 (git+https://github.com/servo/ipc-channel)",
"log 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"mime_guess 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",