Avoid dropping image requests on the ground from non-script-initiated reflow.

This commit is contained in:
Josh Matthews 2016-12-29 14:07:57 -05:00
parent 541ecbfe21
commit 980eb5ac33
6 changed files with 96 additions and 47 deletions

View file

@ -9,7 +9,7 @@ use gfx::display_list::{WebRenderImageInfo, OpaqueNode};
use gfx::font_cache_thread::FontCacheThread;
use gfx::font_context::FontContext;
use heapsize::HeapSizeOf;
use net_traits::image_cache_thread::{ImageCacheThread, ImageState};
use net_traits::image_cache_thread::{ImageCacheThread, ImageState, CanRequestImages};
use net_traits::image_cache_thread::{ImageOrMetadataAvailable, UsePlaceholder};
use opaque_node::OpaqueNodeMethods;
use parking_lot::RwLock;
@ -92,13 +92,15 @@ pub struct LayoutContext {
/// A list of in-progress image loads to be shared with the script thread.
/// A None value means that this layout was not initiated by the script thread.
pub pending_images: Mutex<Vec<PendingImage>>
pub pending_images: Option<Mutex<Vec<PendingImage>>>
}
impl Drop for LayoutContext {
fn drop(&mut self) {
if !thread::panicking() {
assert!(self.pending_images.lock().unwrap().is_empty());
if let Some(ref pending_images) = self.pending_images {
assert!(pending_images.lock().unwrap().is_empty());
}
}
}
}
@ -114,10 +116,20 @@ impl LayoutContext {
url: ServoUrl,
use_placeholder: UsePlaceholder)
-> Option<ImageOrMetadataAvailable> {
//XXXjdm For cases where we do not request an image, we still need to
// ensure the node gets another script-initiated reflow or it
// won't be requested at all.
let can_request = if self.pending_images.is_some() {
CanRequestImages::Yes
} else {
CanRequestImages::No
};
// See if the image is already available
let result = self.image_cache_thread.lock().unwrap()
.find_image_or_metadata(url.clone(),
use_placeholder);
use_placeholder,
can_request);
match result {
Ok(image_or_metadata) => Some(image_or_metadata),
// Image failed to load, so just return nothing
@ -129,18 +141,23 @@ impl LayoutContext {
node: node.to_untrusted_node_address(),
id: id,
};
self.pending_images.lock().unwrap().push(image);
self.pending_images.as_ref().unwrap().lock().unwrap().push(image);
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.
Err(ImageState::Pending(id)) => {
let image = PendingImage {
state: PendingImageState::PendingResponse,
node: node.to_untrusted_node_address(),
id: id,
};
self.pending_images.lock().unwrap().push(image);
//XXXjdm if self.pending_images is not available, we should make sure that
// this node gets marked dirty again so it gets a script-initiated
// reflow that deals with this properly.
if let Some(ref pending_images) = self.pending_images {
let image = PendingImage {
state: PendingImageState::PendingResponse,
node: node.to_untrusted_node_address(),
id: id,
};
pending_images.lock().unwrap().push(image);
}
None
}
}