aboutsummaryrefslogtreecommitdiffstats
path: root/components/layout/context.rs
diff options
context:
space:
mode:
authorJosh Matthews <josh@joshmatthews.net>2016-11-21 18:13:40 -0500
committerJosh Matthews <josh@joshmatthews.net>2017-02-22 14:19:35 -0500
commitc890c9143cc1ae82e1116b8fb0c4e9eb478b8a03 (patch)
tree131dcf8dd5a2880562101497d958c02a31903183 /components/layout/context.rs
parent78e8c31a4d1890260dda83f2db85672f693c1e97 (diff)
downloadservo-c890c9143cc1ae82e1116b8fb0c4e9eb478b8a03.tar.gz
servo-c890c9143cc1ae82e1116b8fb0c4e9eb478b8a03.zip
Make script thread initiate requests for images needed by layout.
In support of this goal, the layout thread collects information about CSS images that are missing image data and hands it off to the script thread after layout completes. The script thread stores a list of nodes that will need to be reflowed after the associated network request is complete. The script thread ensures that the nodes are not GCed while a request is ongoing, which the layout thread is incapable of guaranteeing. The image cache's API has also been redesigned in support of this work. No network requests are made by the new image cache, since it does not possess the document-specific information necessary to initiate them. Instead, there is now a single, synchronous query operation that optionally reserves a slot when a cache entry for a URL cannot be found. This reserved slot is then the responsibility of the queryer to populate with the contents of the network response for the URL once it is complete. Any subsequent queries for the same URL will be informed that the response is pending until that occurs. The changes to layout also remove the synchronous image loading code path, which means that reftests now test the same code that non-test binaries execute. The decision to take a screenshot now considers whether there are any outstanding image requests for layout in order to avoid intermittent failures in reftests that use CSS images.
Diffstat (limited to 'components/layout/context.rs')
-rw-r--r--components/layout/context.rs99
1 files changed, 41 insertions, 58 deletions
diff --git a/components/layout/context.rs b/components/layout/context.rs
index e67e7da6fb1..13029dd80bf 100644
--- a/components/layout/context.rs
+++ b/components/layout/context.rs
@@ -5,22 +5,22 @@
//! Data needed by the layout thread.
use fnv::FnvHasher;
-use gfx::display_list::WebRenderImageInfo;
+use gfx::display_list::{WebRenderImageInfo, OpaqueNode};
use gfx::font_cache_thread::FontCacheThread;
use gfx::font_context::FontContext;
use heapsize::HeapSizeOf;
-use ipc_channel::ipc;
-use net_traits::image::base::Image;
-use net_traits::image_cache_thread::{ImageCacheChan, ImageCacheThread, ImageResponse, ImageState};
+use net_traits::image_cache_thread::{ImageCacheThread, ImageState};
use net_traits::image_cache_thread::{ImageOrMetadataAvailable, UsePlaceholder};
+use opaque_node::OpaqueNodeMethods;
use parking_lot::RwLock;
-use servo_config::opts;
+use script_layout_interface::{PendingImage, PendingImageState};
use servo_url::ServoUrl;
use std::borrow::{Borrow, BorrowMut};
use std::cell::{RefCell, RefMut};
use std::collections::HashMap;
use std::hash::BuildHasherDefault;
use std::sync::{Arc, Mutex};
+use std::thread;
use style::context::{SharedStyleContext, ThreadLocalStyleContext};
use style::dom::TElement;
@@ -82,9 +82,6 @@ pub struct LayoutContext {
/// The shared image cache thread.
pub image_cache_thread: Mutex<ImageCacheThread>,
- /// A channel for the image cache to send responses to.
- pub image_cache_sender: Mutex<ImageCacheChan>,
-
/// Interface to the font cache thread.
pub font_cache_thread: Mutex<FontCacheThread>,
@@ -92,6 +89,18 @@ pub struct LayoutContext {
pub webrender_image_cache: Arc<RwLock<HashMap<(ServoUrl, UsePlaceholder),
WebRenderImageInfo,
BuildHasherDefault<FnvHasher>>>>,
+
+ /// 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>>
+}
+
+impl Drop for LayoutContext {
+ fn drop(&mut self) {
+ if !thread::panicking() {
+ assert!(self.pending_images.lock().unwrap().is_empty());
+ }
+ }
}
impl LayoutContext {
@@ -100,49 +109,11 @@ impl LayoutContext {
&self.style_context
}
- fn get_or_request_image_synchronously(&self, url: ServoUrl, use_placeholder: UsePlaceholder)
- -> Option<Arc<Image>> {
- debug_assert!(opts::get().output_file.is_some() || opts::get().exit_after_load);
-
- // See if the image is already available
- let result = self.image_cache_thread.lock().unwrap()
- .find_image(url.clone(), use_placeholder);
-
- match result {
- Ok(image) => return Some(image),
- Err(ImageState::LoadError) => {
- // Image failed to load, so just return nothing
- return None
- }
- Err(_) => {}
- }
-
- // 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 (sync_tx, sync_rx) = ipc::channel().unwrap();
- self.image_cache_thread.lock().unwrap().request_image(url, ImageCacheChan(sync_tx), None);
- loop {
- match sync_rx.recv() {
- Err(_) => return None,
- Ok(response) => {
- match response.image_response {
- ImageResponse::Loaded(image) | ImageResponse::PlaceholderLoaded(image) => {
- return Some(image)
- }
- ImageResponse::None | ImageResponse::MetadataLoaded(_) => {}
- }
- }
- }
- }
- }
-
- pub fn get_or_request_image_or_meta(&self, url: ServoUrl, use_placeholder: UsePlaceholder)
- -> Option<ImageOrMetadataAvailable> {
- // If we are emitting an output file, load the image synchronously.
- if opts::get().output_file.is_some() || opts::get().exit_after_load {
- return self.get_or_request_image_synchronously(url, use_placeholder)
- .map(|img| ImageOrMetadataAvailable::ImageAvailable(img));
- }
+ pub fn get_or_request_image_or_meta(&self,
+ node: OpaqueNode,
+ url: ServoUrl,
+ use_placeholder: UsePlaceholder)
+ -> Option<ImageOrMetadataAvailable> {
// See if the image is already available
let result = self.image_cache_thread.lock().unwrap()
.find_image_or_metadata(url.clone(),
@@ -151,20 +122,32 @@ impl LayoutContext {
Ok(image_or_metadata) => Some(image_or_metadata),
// Image failed to load, so just return nothing
Err(ImageState::LoadError) => None,
- // Not yet requested, async mode - request image or metadata from the cache
- Err(ImageState::NotRequested) => {
- let sender = self.image_cache_sender.lock().unwrap().clone();
- self.image_cache_thread.lock().unwrap()
- .request_image_and_metadata(url, sender, None);
+ // Not yet requested - request image or metadata from the cache
+ Err(ImageState::NotRequested(id)) => {
+ let image = PendingImage {
+ state: PendingImageState::Unrequested(url),
+ node: node.to_untrusted_node_address(),
+ id: id,
+ };
+ self.pending_images.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) => None,
+ 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);
+ None
+ }
}
}
pub fn get_webrender_image_for_url(&self,
+ node: OpaqueNode,
url: ServoUrl,
use_placeholder: UsePlaceholder)
-> Option<WebRenderImageInfo> {
@@ -174,7 +157,7 @@ impl LayoutContext {
return Some((*existing_webrender_image).clone())
}
- match self.get_or_request_image_or_meta(url.clone(), use_placeholder) {
+ match self.get_or_request_image_or_meta(node, url.clone(), use_placeholder) {
Some(ImageOrMetadataAvailable::ImageAvailable(image)) => {
let image_info = WebRenderImageInfo::from_image(&*image);
if image_info.key.is_none() {