mirror of
https://github.com/servo/servo.git
synced 2025-06-08 00:23:30 +00:00
Auto merge of #23661 - julientregoat:i-21289, r=jdm
Refactor ImageCache::find_image_or_metadata -> ImageCache::{get_image, track_image} <!-- Please describe your changes on the following line: --> Updated the `ImageCache` trait to replace `find_image_or_metadata` with two new functions `track_image` and `get_image`, as well as a new enum (`ImageCacheResult`). As a result, I was able to refactor the functions that previously called `find_image_or_metadata` pretty cleanly. For a list of these functions, please see the commit information. --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `___` with appropriate data: --> - [x] `./mach build -d` does not report any errors - [x] `./mach test-tidy` does not report any errors - [x] These changes fix #21289 (GitHub issue number if applicable) <!-- Either: --> - [ ] There are tests for these changes OR - [x] These changes do not require tests because tests already exist for these components. I ran `cargo test` in `net`, `net_traits`, `layout`, and `script` successfully. <!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.--> <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/23661) <!-- Reviewable:end -->
This commit is contained in:
commit
c9480c8e07
9 changed files with 282 additions and 242 deletions
|
@ -11,7 +11,7 @@ use gfx::font_cache_thread::FontCacheThread;
|
||||||
use gfx::font_context::FontContext;
|
use gfx::font_context::FontContext;
|
||||||
use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
|
use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
|
||||||
use msg::constellation_msg::PipelineId;
|
use msg::constellation_msg::PipelineId;
|
||||||
use net_traits::image_cache::{CanRequestImages, ImageCache, ImageState};
|
use net_traits::image_cache::{CanRequestImages, ImageCache, ImageCacheResult};
|
||||||
use net_traits::image_cache::{ImageOrMetadataAvailable, UsePlaceholder};
|
use net_traits::image_cache::{ImageOrMetadataAvailable, UsePlaceholder};
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
use script_layout_interface::{PendingImage, PendingImageState};
|
use script_layout_interface::{PendingImage, PendingImageState};
|
||||||
|
@ -122,24 +122,40 @@ impl<'a> LayoutContext<'a> {
|
||||||
CanRequestImages::No
|
CanRequestImages::No
|
||||||
};
|
};
|
||||||
|
|
||||||
// See if the image is already available
|
// Check for available image or start tracking.
|
||||||
let result = self.image_cache.find_image_or_metadata(
|
let cache_result = self.image_cache.get_cached_image_status(
|
||||||
url.clone(),
|
url.clone(),
|
||||||
self.origin.clone(),
|
self.origin.clone(),
|
||||||
None,
|
None,
|
||||||
use_placeholder,
|
use_placeholder,
|
||||||
can_request,
|
can_request,
|
||||||
);
|
);
|
||||||
match result {
|
|
||||||
Ok(image_or_metadata) => Some(image_or_metadata),
|
match cache_result {
|
||||||
// Image failed to load, so just return nothing
|
ImageCacheResult::Available(img_or_meta) => Some(img_or_meta),
|
||||||
Err(ImageState::LoadError) => 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.
|
||||||
|
ImageCacheResult::Pending(id) => {
|
||||||
|
//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,
|
||||||
|
origin: self.origin.clone(),
|
||||||
|
};
|
||||||
|
pending_images.lock().unwrap().push(image);
|
||||||
|
}
|
||||||
|
None
|
||||||
|
},
|
||||||
// Not yet requested - request image or metadata from the cache
|
// Not yet requested - request image or metadata from the cache
|
||||||
Err(ImageState::NotRequested(id)) => {
|
ImageCacheResult::ReadyForRequest(id) => {
|
||||||
let image = PendingImage {
|
let image = PendingImage {
|
||||||
state: PendingImageState::Unrequested(url),
|
state: PendingImageState::Unrequested(url),
|
||||||
node: node.to_untrusted_node_address(),
|
node: node.to_untrusted_node_address(),
|
||||||
id: id,
|
id,
|
||||||
origin: self.origin.clone(),
|
origin: self.origin.clone(),
|
||||||
};
|
};
|
||||||
self.pending_images
|
self.pending_images
|
||||||
|
@ -150,23 +166,8 @@ impl<'a> LayoutContext<'a> {
|
||||||
.push(image);
|
.push(image);
|
||||||
None
|
None
|
||||||
},
|
},
|
||||||
// Image has been requested, is still pending. Return no image for this paint loop.
|
// Image failed to load, so just return nothing
|
||||||
// When the image loads it will trigger a reflow and/or repaint.
|
ImageCacheResult::LoadError => None,
|
||||||
Err(ImageState::Pending(id)) => {
|
|
||||||
//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,
|
|
||||||
origin: self.origin.clone(),
|
|
||||||
};
|
|
||||||
pending_images.lock().unwrap().push(image);
|
|
||||||
}
|
|
||||||
None
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,11 +3,12 @@
|
||||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use crate::display_list::WebRenderImageInfo;
|
use crate::display_list::WebRenderImageInfo;
|
||||||
|
use crate::opaque_node::OpaqueNodeMethods;
|
||||||
use fnv::FnvHashMap;
|
use fnv::FnvHashMap;
|
||||||
use gfx::font_cache_thread::FontCacheThread;
|
use gfx::font_cache_thread::FontCacheThread;
|
||||||
use gfx::font_context::FontContext;
|
use gfx::font_context::FontContext;
|
||||||
use msg::constellation_msg::PipelineId;
|
use msg::constellation_msg::PipelineId;
|
||||||
use net_traits::image_cache::{CanRequestImages, ImageCache, ImageState};
|
use net_traits::image_cache::{CanRequestImages, ImageCache, ImageCacheResult};
|
||||||
use net_traits::image_cache::{ImageOrMetadataAvailable, UsePlaceholder};
|
use net_traits::image_cache::{ImageOrMetadataAvailable, UsePlaceholder};
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
use script_layout_interface::{PendingImage, PendingImageState};
|
use script_layout_interface::{PendingImage, PendingImageState};
|
||||||
|
@ -70,24 +71,40 @@ impl<'a> LayoutContext<'a> {
|
||||||
CanRequestImages::No
|
CanRequestImages::No
|
||||||
};
|
};
|
||||||
|
|
||||||
// See if the image is already available
|
// Check for available image or start tracking.
|
||||||
let result = self.image_cache.find_image_or_metadata(
|
let cache_result = self.image_cache.get_cached_image_status(
|
||||||
url.clone(),
|
url.clone(),
|
||||||
self.origin.clone(),
|
self.origin.clone(),
|
||||||
None,
|
None,
|
||||||
use_placeholder,
|
use_placeholder,
|
||||||
can_request,
|
can_request,
|
||||||
);
|
);
|
||||||
match result {
|
|
||||||
Ok(image_or_metadata) => Some(image_or_metadata),
|
match cache_result {
|
||||||
// Image failed to load, so just return nothing
|
ImageCacheResult::Available(img_or_meta) => Some(img_or_meta),
|
||||||
Err(ImageState::LoadError) => 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.
|
||||||
|
ImageCacheResult::Pending(id) => {
|
||||||
|
//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,
|
||||||
|
origin: self.origin.clone(),
|
||||||
|
};
|
||||||
|
pending_images.lock().unwrap().push(image);
|
||||||
|
}
|
||||||
|
None
|
||||||
|
},
|
||||||
// Not yet requested - request image or metadata from the cache
|
// Not yet requested - request image or metadata from the cache
|
||||||
Err(ImageState::NotRequested(id)) => {
|
ImageCacheResult::ReadyForRequest(id) => {
|
||||||
let image = PendingImage {
|
let image = PendingImage {
|
||||||
state: PendingImageState::Unrequested(url),
|
state: PendingImageState::Unrequested(url),
|
||||||
node: node.into(),
|
node: node.to_untrusted_node_address(),
|
||||||
id: id,
|
id,
|
||||||
origin: self.origin.clone(),
|
origin: self.origin.clone(),
|
||||||
};
|
};
|
||||||
self.pending_images
|
self.pending_images
|
||||||
|
@ -98,23 +115,8 @@ impl<'a> LayoutContext<'a> {
|
||||||
.push(image);
|
.push(image);
|
||||||
None
|
None
|
||||||
},
|
},
|
||||||
// Image has been requested, is still pending. Return no image for this paint loop.
|
// Image failed to load, so just return nothing
|
||||||
// When the image loads it will trigger a reflow and/or repaint.
|
ImageCacheResult::LoadError => None,
|
||||||
Err(ImageState::Pending(id)) => {
|
|
||||||
//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.into(),
|
|
||||||
id: id,
|
|
||||||
origin: self.origin.clone(),
|
|
||||||
};
|
|
||||||
pending_images.lock().unwrap().push(image);
|
|
||||||
}
|
|
||||||
None
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,9 +4,13 @@
|
||||||
|
|
||||||
use embedder_traits::resources::{self, Resource};
|
use embedder_traits::resources::{self, Resource};
|
||||||
use immeta::load_from_buf;
|
use immeta::load_from_buf;
|
||||||
|
use ipc_channel::ipc::IpcSender;
|
||||||
use net_traits::image::base::{load_from_memory, Image, ImageMetadata};
|
use net_traits::image::base::{load_from_memory, Image, ImageMetadata};
|
||||||
use net_traits::image_cache::{CanRequestImages, CorsStatus, ImageCache, ImageResponder};
|
use net_traits::image_cache::{
|
||||||
use net_traits::image_cache::{ImageOrMetadataAvailable, ImageResponse, ImageState};
|
CanRequestImages, CorsStatus, ImageCache, ImageCacheResult, ImageResponder,
|
||||||
|
PendingImageResponse,
|
||||||
|
};
|
||||||
|
use net_traits::image_cache::{ImageOrMetadataAvailable, ImageResponse};
|
||||||
use net_traits::image_cache::{PendingImageId, UsePlaceholder};
|
use net_traits::image_cache::{PendingImageId, UsePlaceholder};
|
||||||
use net_traits::request::CorsSettings;
|
use net_traits::request::CorsSettings;
|
||||||
use net_traits::{
|
use net_traits::{
|
||||||
|
@ -16,7 +20,6 @@ use pixels::PixelFormat;
|
||||||
use servo_url::{ImmutableOrigin, ServoUrl};
|
use servo_url::{ImmutableOrigin, ServoUrl};
|
||||||
use std::collections::hash_map::Entry::{Occupied, Vacant};
|
use std::collections::hash_map::Entry::{Occupied, Vacant};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::io;
|
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use std::thread;
|
use std::thread;
|
||||||
|
@ -45,13 +48,10 @@ fn decode_bytes_sync(key: LoadKey, bytes: &[u8], cors: CorsStatus) -> DecoderMsg
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_placeholder_image(
|
fn get_placeholder_image(webrender_api: &WebrenderIpcSender, data: &[u8]) -> Arc<Image> {
|
||||||
webrender_api: &WebrenderIpcSender,
|
|
||||||
data: &[u8],
|
|
||||||
) -> io::Result<Arc<Image>> {
|
|
||||||
let mut image = load_from_memory(&data, CorsStatus::Unsafe).unwrap();
|
let mut image = load_from_memory(&data, CorsStatus::Unsafe).unwrap();
|
||||||
set_webrender_image_key(webrender_api, &mut image);
|
set_webrender_image_key(webrender_api, &mut image);
|
||||||
Ok(Arc::new(image))
|
Arc::new(image)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_webrender_image_key(webrender_api: &WebrenderIpcSender, image: &mut Image) {
|
fn set_webrender_image_key(webrender_api: &WebrenderIpcSender, image: &mut Image) {
|
||||||
|
@ -335,7 +335,7 @@ struct ImageCacheStore {
|
||||||
completed_loads: HashMap<ImageKey, CompletedLoad>,
|
completed_loads: HashMap<ImageKey, CompletedLoad>,
|
||||||
|
|
||||||
// The placeholder image used when an image fails to load
|
// The placeholder image used when an image fails to load
|
||||||
placeholder_image: Option<Arc<Image>>,
|
placeholder_image: Arc<Image>,
|
||||||
|
|
||||||
// The URL used for the placeholder image
|
// The URL used for the placeholder image
|
||||||
placeholder_url: ServoUrl,
|
placeholder_url: ServoUrl,
|
||||||
|
@ -391,7 +391,7 @@ impl ImageCacheStore {
|
||||||
origin: ImmutableOrigin,
|
origin: ImmutableOrigin,
|
||||||
cors_setting: Option<CorsSettings>,
|
cors_setting: Option<CorsSettings>,
|
||||||
placeholder: UsePlaceholder,
|
placeholder: UsePlaceholder,
|
||||||
) -> Option<Result<ImageOrMetadataAvailable, ImageState>> {
|
) -> Option<Result<(Arc<Image>, ServoUrl), ()>> {
|
||||||
self.completed_loads
|
self.completed_loads
|
||||||
.get(&(url, origin, cors_setting))
|
.get(&(url, origin, cors_setting))
|
||||||
.map(
|
.map(
|
||||||
|
@ -400,13 +400,10 @@ impl ImageCacheStore {
|
||||||
(
|
(
|
||||||
&ImageResponse::PlaceholderLoaded(ref image, ref url),
|
&ImageResponse::PlaceholderLoaded(ref image, ref url),
|
||||||
UsePlaceholder::Yes,
|
UsePlaceholder::Yes,
|
||||||
) => Ok(ImageOrMetadataAvailable::ImageAvailable(
|
) => Ok((image.clone(), url.clone())),
|
||||||
image.clone(),
|
|
||||||
url.clone(),
|
|
||||||
)),
|
|
||||||
(&ImageResponse::PlaceholderLoaded(_, _), UsePlaceholder::No) |
|
(&ImageResponse::PlaceholderLoaded(_, _), UsePlaceholder::No) |
|
||||||
(&ImageResponse::None, _) |
|
(&ImageResponse::None, _) |
|
||||||
(&ImageResponse::MetadataLoaded(_), _) => Err(ImageState::LoadError),
|
(&ImageResponse::MetadataLoaded(_), _) => Err(()),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -436,25 +433,36 @@ impl ImageCache for ImageCacheImpl {
|
||||||
store: Arc::new(Mutex::new(ImageCacheStore {
|
store: Arc::new(Mutex::new(ImageCacheStore {
|
||||||
pending_loads: AllPendingLoads::new(),
|
pending_loads: AllPendingLoads::new(),
|
||||||
completed_loads: HashMap::new(),
|
completed_loads: HashMap::new(),
|
||||||
placeholder_image: get_placeholder_image(&webrender_api, &rippy_data).ok(),
|
placeholder_image: get_placeholder_image(&webrender_api, &rippy_data),
|
||||||
placeholder_url: ServoUrl::parse("chrome://resources/rippy.png").unwrap(),
|
placeholder_url: ServoUrl::parse("chrome://resources/rippy.png").unwrap(),
|
||||||
webrender_api: webrender_api,
|
webrender_api: webrender_api,
|
||||||
})),
|
})),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return any available metadata or image for the given URL,
|
fn get_image(
|
||||||
/// or an indication that the image is not yet available if it is in progress,
|
&self,
|
||||||
/// or else reserve a slot in the cache for the URL if the consumer can request images.
|
url: ServoUrl,
|
||||||
fn find_image_or_metadata(
|
origin: ImmutableOrigin,
|
||||||
|
cors_setting: Option<CorsSettings>,
|
||||||
|
) -> Option<Arc<Image>> {
|
||||||
|
let store = self.store.lock().unwrap();
|
||||||
|
let result =
|
||||||
|
store.get_completed_image_if_available(url, origin, cors_setting, UsePlaceholder::No);
|
||||||
|
match result {
|
||||||
|
Some(Ok((img, _))) => Some(img),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_cached_image_status(
|
||||||
&self,
|
&self,
|
||||||
url: ServoUrl,
|
url: ServoUrl,
|
||||||
origin: ImmutableOrigin,
|
origin: ImmutableOrigin,
|
||||||
cors_setting: Option<CorsSettings>,
|
cors_setting: Option<CorsSettings>,
|
||||||
use_placeholder: UsePlaceholder,
|
use_placeholder: UsePlaceholder,
|
||||||
can_request: CanRequestImages,
|
can_request: CanRequestImages,
|
||||||
) -> Result<ImageOrMetadataAvailable, ImageState> {
|
) -> ImageCacheResult {
|
||||||
debug!("Find image or metadata for {} ({:?})", url, origin);
|
|
||||||
let mut store = self.store.lock().unwrap();
|
let mut store = self.store.lock().unwrap();
|
||||||
if let Some(result) = store.get_completed_image_if_available(
|
if let Some(result) = store.get_completed_image_if_available(
|
||||||
url.clone(),
|
url.clone(),
|
||||||
|
@ -462,8 +470,18 @@ impl ImageCache for ImageCacheImpl {
|
||||||
cors_setting,
|
cors_setting,
|
||||||
use_placeholder,
|
use_placeholder,
|
||||||
) {
|
) {
|
||||||
debug!("{} is available", url);
|
match result {
|
||||||
return result;
|
Ok((image, image_url)) => {
|
||||||
|
debug!("{} is available", url);
|
||||||
|
return ImageCacheResult::Available(ImageOrMetadataAvailable::ImageAvailable(
|
||||||
|
image, image_url,
|
||||||
|
));
|
||||||
|
},
|
||||||
|
Err(()) => {
|
||||||
|
debug!("{} is not available", url);
|
||||||
|
return ImageCacheResult::LoadError;
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let decoded = {
|
let decoded = {
|
||||||
|
@ -481,20 +499,22 @@ impl ImageCache for ImageCacheImpl {
|
||||||
},
|
},
|
||||||
(&None, &Some(ref meta)) => {
|
(&None, &Some(ref meta)) => {
|
||||||
debug!("Metadata available for {} ({:?})", url, key);
|
debug!("Metadata available for {} ({:?})", url, key);
|
||||||
return Ok(ImageOrMetadataAvailable::MetadataAvailable(meta.clone()));
|
return ImageCacheResult::Available(
|
||||||
|
ImageOrMetadataAvailable::MetadataAvailable(meta.clone()),
|
||||||
|
);
|
||||||
},
|
},
|
||||||
(&Some(Err(_)), _) | (&None, &None) => {
|
(&Some(Err(_)), _) | (&None, &None) => {
|
||||||
debug!("{} ({:?}) is still pending", url, key);
|
debug!("{} ({:?}) is still pending", url, key);
|
||||||
return Err(ImageState::Pending(key));
|
return ImageCacheResult::Pending(key);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
CacheResult::Miss(Some((key, _pl))) => {
|
CacheResult::Miss(Some((key, _pl))) => {
|
||||||
debug!("Should be requesting {} ({:?})", url, key);
|
debug!("Should be requesting {} ({:?})", url, key);
|
||||||
return Err(ImageState::NotRequested(key));
|
return ImageCacheResult::ReadyForRequest(key);
|
||||||
},
|
},
|
||||||
CacheResult::Miss(None) => {
|
CacheResult::Miss(None) => {
|
||||||
debug!("Couldn't find an entry for {}", url);
|
debug!("Couldn't find an entry for {}", url);
|
||||||
return Err(ImageState::LoadError);
|
return ImageCacheResult::LoadError;
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -505,11 +525,50 @@ impl ImageCache for ImageCacheImpl {
|
||||||
// TODO: make this behaviour configurable according to the caller's needs.
|
// TODO: make this behaviour configurable according to the caller's needs.
|
||||||
store.handle_decoder(decoded);
|
store.handle_decoder(decoded);
|
||||||
match store.get_completed_image_if_available(url, origin, cors_setting, use_placeholder) {
|
match store.get_completed_image_if_available(url, origin, cors_setting, use_placeholder) {
|
||||||
Some(result) => result,
|
Some(Ok((image, image_url))) => ImageCacheResult::Available(
|
||||||
None => Err(ImageState::LoadError),
|
ImageOrMetadataAvailable::ImageAvailable(image, image_url),
|
||||||
|
),
|
||||||
|
_ => ImageCacheResult::LoadError,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn track_image(
|
||||||
|
&self,
|
||||||
|
url: ServoUrl,
|
||||||
|
origin: ImmutableOrigin,
|
||||||
|
cors_setting: Option<CorsSettings>,
|
||||||
|
sender: IpcSender<PendingImageResponse>,
|
||||||
|
use_placeholder: UsePlaceholder,
|
||||||
|
can_request: CanRequestImages,
|
||||||
|
) -> ImageCacheResult {
|
||||||
|
debug!("Track image for {} ({:?})", url, origin);
|
||||||
|
let cache_result = self.get_cached_image_status(
|
||||||
|
url.clone(),
|
||||||
|
origin.clone(),
|
||||||
|
cors_setting,
|
||||||
|
use_placeholder,
|
||||||
|
can_request,
|
||||||
|
);
|
||||||
|
|
||||||
|
match cache_result {
|
||||||
|
ImageCacheResult::Available(ImageOrMetadataAvailable::MetadataAvailable(_)) => {
|
||||||
|
let store = self.store.lock().unwrap();
|
||||||
|
let id = store
|
||||||
|
.pending_loads
|
||||||
|
.url_to_load_key
|
||||||
|
.get(&(url, origin, cors_setting))
|
||||||
|
.unwrap();
|
||||||
|
self.add_listener(*id, ImageResponder::new(sender, *id));
|
||||||
|
},
|
||||||
|
ImageCacheResult::Pending(id) | ImageCacheResult::ReadyForRequest(id) => {
|
||||||
|
self.add_listener(id, ImageResponder::new(sender, id));
|
||||||
|
},
|
||||||
|
_ => {},
|
||||||
|
}
|
||||||
|
|
||||||
|
cache_result
|
||||||
|
}
|
||||||
|
|
||||||
/// Add a new listener for the given pending image id. If the image is already present,
|
/// Add a new listener for the given pending image id. If the image is already present,
|
||||||
/// the responder will still receive the expected response.
|
/// the responder will still receive the expected response.
|
||||||
fn add_listener(&self, id: PendingImageId, listener: ImageResponder) {
|
fn add_listener(&self, id: PendingImageId, listener: ImageResponder) {
|
||||||
|
@ -600,13 +659,8 @@ impl ImageCache for ImageCacheImpl {
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
debug!("Processing error for {:?}", key);
|
debug!("Processing error for {:?}", key);
|
||||||
let mut store = self.store.lock().unwrap();
|
let mut store = self.store.lock().unwrap();
|
||||||
match store.placeholder_image.clone() {
|
let placeholder_image = store.placeholder_image.clone();
|
||||||
Some(placeholder_image) => store.complete_load(
|
store.complete_load(id, LoadResult::PlaceholderLoaded(placeholder_image))
|
||||||
id,
|
|
||||||
LoadResult::PlaceholderLoaded(placeholder_image),
|
|
||||||
),
|
|
||||||
None => store.complete_load(id, LoadResult::None),
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -73,14 +73,6 @@ pub enum ImageResponse {
|
||||||
None,
|
None,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The current state of an image in the cache.
|
|
||||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
|
|
||||||
pub enum ImageState {
|
|
||||||
Pending(PendingImageId),
|
|
||||||
LoadError,
|
|
||||||
NotRequested(PendingImageId),
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The unique id for an image that has previously been requested.
|
/// The unique id for an image that has previously been requested.
|
||||||
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)]
|
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)]
|
||||||
pub struct PendingImageId(pub u64);
|
pub struct PendingImageId(pub u64);
|
||||||
|
@ -101,22 +93,50 @@ pub enum UsePlaceholder {
|
||||||
// ImageCache public API.
|
// ImageCache public API.
|
||||||
// ======================================================================
|
// ======================================================================
|
||||||
|
|
||||||
|
pub enum ImageCacheResult {
|
||||||
|
Available(ImageOrMetadataAvailable),
|
||||||
|
LoadError,
|
||||||
|
Pending(PendingImageId),
|
||||||
|
ReadyForRequest(PendingImageId),
|
||||||
|
}
|
||||||
|
|
||||||
pub trait ImageCache: Sync + Send {
|
pub trait ImageCache: Sync + Send {
|
||||||
fn new(webrender_api: WebrenderIpcSender) -> Self
|
fn new(webrender_api: WebrenderIpcSender) -> Self
|
||||||
where
|
where
|
||||||
Self: Sized;
|
Self: Sized;
|
||||||
|
|
||||||
/// Return any available metadata or image for the given URL,
|
/// Definitively check whether there is a cached, fully loaded image available.
|
||||||
/// or an indication that the image is not yet available if it is in progress,
|
fn get_image(
|
||||||
/// or else reserve a slot in the cache for the URL if the consumer can request images.
|
&self,
|
||||||
fn find_image_or_metadata(
|
url: ServoUrl,
|
||||||
|
origin: ImmutableOrigin,
|
||||||
|
cors_setting: Option<CorsSettings>,
|
||||||
|
) -> Option<Arc<Image>>;
|
||||||
|
|
||||||
|
fn get_cached_image_status(
|
||||||
&self,
|
&self,
|
||||||
url: ServoUrl,
|
url: ServoUrl,
|
||||||
origin: ImmutableOrigin,
|
origin: ImmutableOrigin,
|
||||||
cors_setting: Option<CorsSettings>,
|
cors_setting: Option<CorsSettings>,
|
||||||
use_placeholder: UsePlaceholder,
|
use_placeholder: UsePlaceholder,
|
||||||
can_request: CanRequestImages,
|
can_request: CanRequestImages,
|
||||||
) -> Result<ImageOrMetadataAvailable, ImageState>;
|
) -> ImageCacheResult;
|
||||||
|
|
||||||
|
/// Add a listener for the provided pending image id, eventually called by
|
||||||
|
/// ImageCacheStore::complete_load.
|
||||||
|
/// If only metadata is available, Available(ImageOrMetadataAvailable) will
|
||||||
|
/// be returned.
|
||||||
|
/// If Available(ImageOrMetadataAvailable::Image) or LoadError is the final value,
|
||||||
|
/// the provided listener will be dropped (consumed & not added to PendingLoad).
|
||||||
|
fn track_image(
|
||||||
|
&self,
|
||||||
|
url: ServoUrl,
|
||||||
|
origin: ImmutableOrigin,
|
||||||
|
cors_setting: Option<CorsSettings>,
|
||||||
|
sender: IpcSender<PendingImageResponse>,
|
||||||
|
use_placeholder: UsePlaceholder,
|
||||||
|
can_request: CanRequestImages,
|
||||||
|
) -> ImageCacheResult;
|
||||||
|
|
||||||
/// Add a new listener for the given pending image id. If the image is already present,
|
/// Add a new listener for the given pending image id. If the image is already present,
|
||||||
/// the responder will still receive the expected response.
|
/// the responder will still receive the expected response.
|
||||||
|
|
|
@ -38,12 +38,7 @@ use euclid::{
|
||||||
vec2,
|
vec2,
|
||||||
};
|
};
|
||||||
use ipc_channel::ipc::{self, IpcSender};
|
use ipc_channel::ipc::{self, IpcSender};
|
||||||
use net_traits::image_cache::CanRequestImages;
|
use net_traits::image_cache::{ImageCache, ImageResponse};
|
||||||
use net_traits::image_cache::ImageCache;
|
|
||||||
use net_traits::image_cache::ImageOrMetadataAvailable;
|
|
||||||
use net_traits::image_cache::ImageResponse;
|
|
||||||
use net_traits::image_cache::ImageState;
|
|
||||||
use net_traits::image_cache::UsePlaceholder;
|
|
||||||
use net_traits::request::CorsSettings;
|
use net_traits::request::CorsSettings;
|
||||||
use pixels::PixelFormat;
|
use pixels::PixelFormat;
|
||||||
use profile_traits::ipc as profiled_ipc;
|
use profile_traits::ipc as profiled_ipc;
|
||||||
|
@ -261,19 +256,12 @@ impl CanvasState {
|
||||||
url: ServoUrl,
|
url: ServoUrl,
|
||||||
cors_setting: Option<CorsSettings>,
|
cors_setting: Option<CorsSettings>,
|
||||||
) -> ImageResponse {
|
) -> ImageResponse {
|
||||||
let response = self.image_cache.find_image_or_metadata(
|
match self
|
||||||
url.clone(),
|
.image_cache
|
||||||
self.origin.clone(),
|
.get_image(url.clone(), self.origin.clone(), cors_setting)
|
||||||
cors_setting,
|
{
|
||||||
UsePlaceholder::No,
|
Some(image) => ImageResponse::Loaded(image, url),
|
||||||
CanRequestImages::No,
|
None => {
|
||||||
);
|
|
||||||
match response {
|
|
||||||
Ok(ImageOrMetadataAvailable::ImageAvailable(image, url)) => {
|
|
||||||
ImageResponse::Loaded(image, url)
|
|
||||||
},
|
|
||||||
Err(ImageState::Pending(_)) => ImageResponse::None,
|
|
||||||
_ => {
|
|
||||||
// Rather annoyingly, we get the same response back from
|
// Rather annoyingly, we get the same response back from
|
||||||
// A load which really failed and from a load which hasn't started yet.
|
// A load which really failed and from a load which hasn't started yet.
|
||||||
self.missing_image_urls.borrow_mut().push(url);
|
self.missing_image_urls.borrow_mut().push(url);
|
||||||
|
|
|
@ -432,8 +432,7 @@ impl<'a> From<&'a WebGLContextAttributes> for GLContextAttributes {
|
||||||
|
|
||||||
pub mod utils {
|
pub mod utils {
|
||||||
use crate::dom::window::Window;
|
use crate::dom::window::Window;
|
||||||
use net_traits::image_cache::CanRequestImages;
|
use net_traits::image_cache::ImageResponse;
|
||||||
use net_traits::image_cache::{ImageOrMetadataAvailable, ImageResponse, UsePlaceholder};
|
|
||||||
use net_traits::request::CorsSettings;
|
use net_traits::request::CorsSettings;
|
||||||
use servo_url::ServoUrl;
|
use servo_url::ServoUrl;
|
||||||
|
|
||||||
|
@ -443,18 +442,15 @@ pub mod utils {
|
||||||
cors_setting: Option<CorsSettings>,
|
cors_setting: Option<CorsSettings>,
|
||||||
) -> ImageResponse {
|
) -> ImageResponse {
|
||||||
let image_cache = window.image_cache();
|
let image_cache = window.image_cache();
|
||||||
let response = image_cache.find_image_or_metadata(
|
let result = image_cache.get_image(
|
||||||
url.into(),
|
url.clone(),
|
||||||
window.origin().immutable().clone(),
|
window.origin().immutable().clone(),
|
||||||
cors_setting,
|
cors_setting,
|
||||||
UsePlaceholder::No,
|
|
||||||
CanRequestImages::No,
|
|
||||||
);
|
);
|
||||||
match response {
|
|
||||||
Ok(ImageOrMetadataAvailable::ImageAvailable(image, url)) => {
|
match result {
|
||||||
ImageResponse::Loaded(image, url)
|
Some(image) => ImageResponse::Loaded(image, url),
|
||||||
},
|
None => ImageResponse::None,
|
||||||
_ => ImageResponse::None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,7 +43,7 @@ use crate::dom::values::UNSIGNED_LONG_MAX;
|
||||||
use crate::dom::virtualmethods::VirtualMethods;
|
use crate::dom::virtualmethods::VirtualMethods;
|
||||||
use crate::dom::window::Window;
|
use crate::dom::window::Window;
|
||||||
use crate::fetch::create_a_potential_cors_request;
|
use crate::fetch::create_a_potential_cors_request;
|
||||||
use crate::image_listener::{add_cache_listener_for_element, ImageCacheListener};
|
use crate::image_listener::{generate_cache_listener_for_element, ImageCacheListener};
|
||||||
use crate::microtask::{Microtask, MicrotaskRunnable};
|
use crate::microtask::{Microtask, MicrotaskRunnable};
|
||||||
use crate::network_listener::{self, NetworkListener, PreInvoke, ResourceTimingListener};
|
use crate::network_listener::{self, NetworkListener, PreInvoke, ResourceTimingListener};
|
||||||
use crate::script_thread::ScriptThread;
|
use crate::script_thread::ScriptThread;
|
||||||
|
@ -54,13 +54,15 @@ use dom_struct::dom_struct;
|
||||||
use euclid::Point2D;
|
use euclid::Point2D;
|
||||||
use html5ever::{LocalName, Prefix, QualName};
|
use html5ever::{LocalName, Prefix, QualName};
|
||||||
use ipc_channel::ipc;
|
use ipc_channel::ipc;
|
||||||
|
use ipc_channel::ipc::IpcSender;
|
||||||
use ipc_channel::router::ROUTER;
|
use ipc_channel::router::ROUTER;
|
||||||
use mime::{self, Mime};
|
use mime::{self, Mime};
|
||||||
use msg::constellation_msg::PipelineId;
|
use msg::constellation_msg::PipelineId;
|
||||||
use net_traits::image::base::{Image, ImageMetadata};
|
use net_traits::image::base::{Image, ImageMetadata};
|
||||||
use net_traits::image_cache::UsePlaceholder;
|
use net_traits::image_cache::{
|
||||||
use net_traits::image_cache::{CanRequestImages, CorsStatus, ImageCache, ImageOrMetadataAvailable};
|
CanRequestImages, CorsStatus, ImageCache, ImageCacheResult, ImageOrMetadataAvailable,
|
||||||
use net_traits::image_cache::{ImageResponder, ImageResponse, ImageState, PendingImageId};
|
ImageResponse, PendingImageId, PendingImageResponse, UsePlaceholder,
|
||||||
|
};
|
||||||
use net_traits::request::{CorsSettings, Destination, Initiator, RequestBuilder};
|
use net_traits::request::{CorsSettings, Destination, Initiator, RequestBuilder};
|
||||||
use net_traits::{FetchMetadata, FetchResponseListener, FetchResponseMsg, NetworkError};
|
use net_traits::{FetchMetadata, FetchResponseListener, FetchResponseMsg, NetworkError};
|
||||||
use net_traits::{ReferrerPolicy, ResourceFetchTiming, ResourceTimingType};
|
use net_traits::{ReferrerPolicy, ResourceFetchTiming, ResourceTimingType};
|
||||||
|
@ -317,35 +319,27 @@ impl HTMLImageElement {
|
||||||
fn fetch_image(&self, img_url: &ServoUrl) {
|
fn fetch_image(&self, img_url: &ServoUrl) {
|
||||||
let window = window_from_node(self);
|
let window = window_from_node(self);
|
||||||
let image_cache = window.image_cache();
|
let image_cache = window.image_cache();
|
||||||
let response = image_cache.find_image_or_metadata(
|
let sender = generate_cache_listener_for_element(self);
|
||||||
img_url.clone().into(),
|
let cache_result = image_cache.track_image(
|
||||||
|
img_url.clone(),
|
||||||
window.origin().immutable().clone(),
|
window.origin().immutable().clone(),
|
||||||
cors_setting_for_element(self.upcast()),
|
cors_setting_for_element(self.upcast()),
|
||||||
|
sender,
|
||||||
UsePlaceholder::Yes,
|
UsePlaceholder::Yes,
|
||||||
CanRequestImages::Yes,
|
CanRequestImages::Yes,
|
||||||
);
|
);
|
||||||
match response {
|
|
||||||
Ok(ImageOrMetadataAvailable::ImageAvailable(image, url)) => {
|
|
||||||
self.process_image_response(ImageResponse::Loaded(image, url));
|
|
||||||
},
|
|
||||||
|
|
||||||
Ok(ImageOrMetadataAvailable::MetadataAvailable(m)) => {
|
match cache_result {
|
||||||
self.process_image_response(ImageResponse::MetadataLoaded(m));
|
ImageCacheResult::Available(ImageOrMetadataAvailable::ImageAvailable(image, url)) => {
|
||||||
|
self.process_image_response(ImageResponse::Loaded(image, url))
|
||||||
},
|
},
|
||||||
|
ImageCacheResult::Available(ImageOrMetadataAvailable::MetadataAvailable(m)) => {
|
||||||
Err(ImageState::Pending(id)) => {
|
self.process_image_response(ImageResponse::MetadataLoaded(m))
|
||||||
add_cache_listener_for_element(image_cache, id, self);
|
|
||||||
},
|
},
|
||||||
|
ImageCacheResult::Pending(_) => (),
|
||||||
Err(ImageState::LoadError) => {
|
ImageCacheResult::ReadyForRequest(id) => self.fetch_request(img_url, id),
|
||||||
self.process_image_response(ImageResponse::None);
|
ImageCacheResult::LoadError => self.process_image_response(ImageResponse::None),
|
||||||
},
|
};
|
||||||
|
|
||||||
Err(ImageState::NotRequested(id)) => {
|
|
||||||
add_cache_listener_for_element(image_cache, id, self);
|
|
||||||
self.fetch_request(img_url, id);
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fetch_request(&self, img_url: &ServoUrl, id: PendingImageId) {
|
fn fetch_request(&self, img_url: &ServoUrl, id: PendingImageId) {
|
||||||
|
@ -943,14 +937,13 @@ impl HTMLImageElement {
|
||||||
if let Some(src) = selected_source {
|
if let Some(src) = selected_source {
|
||||||
if let Ok(img_url) = base_url.join(&src) {
|
if let Ok(img_url) = base_url.join(&src) {
|
||||||
let image_cache = window.image_cache();
|
let image_cache = window.image_cache();
|
||||||
let response = image_cache.find_image_or_metadata(
|
let response = image_cache.get_image(
|
||||||
img_url.clone().into(),
|
img_url.clone(),
|
||||||
window.origin().immutable().clone(),
|
window.origin().immutable().clone(),
|
||||||
cors_setting_for_element(self.upcast()),
|
cors_setting_for_element(self.upcast()),
|
||||||
UsePlaceholder::No,
|
|
||||||
CanRequestImages::No,
|
|
||||||
);
|
);
|
||||||
if let Ok(ImageOrMetadataAvailable::ImageAvailable(image, url)) = response {
|
|
||||||
|
if let Some(image) = response {
|
||||||
// Cancel any outstanding tasks that were queued before the src was
|
// Cancel any outstanding tasks that were queued before the src was
|
||||||
// set on this element.
|
// set on this element.
|
||||||
self.generation.set(self.generation.get() + 1);
|
self.generation.set(self.generation.get() + 1);
|
||||||
|
@ -963,7 +956,7 @@ impl HTMLImageElement {
|
||||||
self.abort_request(State::CompletelyAvailable, ImageRequestPhase::Current);
|
self.abort_request(State::CompletelyAvailable, ImageRequestPhase::Current);
|
||||||
self.abort_request(State::Unavailable, ImageRequestPhase::Pending);
|
self.abort_request(State::Unavailable, ImageRequestPhase::Pending);
|
||||||
let mut current_request = self.current_request.borrow_mut();
|
let mut current_request = self.current_request.borrow_mut();
|
||||||
current_request.final_url = Some(url);
|
current_request.final_url = Some(img_url.clone());
|
||||||
current_request.image = Some(image.clone());
|
current_request.image = Some(image.clone());
|
||||||
current_request.metadata = Some(metadata);
|
current_request.metadata = Some(metadata);
|
||||||
// Step 6.3.6
|
// Step 6.3.6
|
||||||
|
@ -1010,13 +1003,12 @@ impl HTMLImageElement {
|
||||||
/// Step 2-12 of https://html.spec.whatwg.org/multipage/#img-environment-changes
|
/// Step 2-12 of https://html.spec.whatwg.org/multipage/#img-environment-changes
|
||||||
fn react_to_environment_changes_sync_steps(&self, generation: u32) {
|
fn react_to_environment_changes_sync_steps(&self, generation: u32) {
|
||||||
// TODO reduce duplicacy of this code
|
// TODO reduce duplicacy of this code
|
||||||
fn add_cache_listener_for_element(
|
|
||||||
image_cache: Arc<dyn ImageCache>,
|
fn generate_cache_listener_for_element(
|
||||||
id: PendingImageId,
|
|
||||||
elem: &HTMLImageElement,
|
elem: &HTMLImageElement,
|
||||||
selected_source: String,
|
selected_source: String,
|
||||||
selected_pixel_density: f64,
|
selected_pixel_density: f64,
|
||||||
) {
|
) -> IpcSender<PendingImageResponse> {
|
||||||
let trusted_node = Trusted::new(elem);
|
let trusted_node = Trusted::new(elem);
|
||||||
let (responder_sender, responder_receiver) = ipc::channel().unwrap();
|
let (responder_sender, responder_receiver) = ipc::channel().unwrap();
|
||||||
|
|
||||||
|
@ -1025,27 +1017,30 @@ impl HTMLImageElement {
|
||||||
.task_manager()
|
.task_manager()
|
||||||
.networking_task_source_with_canceller();
|
.networking_task_source_with_canceller();
|
||||||
let generation = elem.generation.get();
|
let generation = elem.generation.get();
|
||||||
ROUTER.add_route(responder_receiver.to_opaque(), Box::new(move |message| {
|
ROUTER.add_route(
|
||||||
debug!("Got image {:?}", message);
|
responder_receiver.to_opaque(),
|
||||||
// Return the image via a message to the script thread, which marks
|
Box::new(move |message| {
|
||||||
// the element as dirty and triggers a reflow.
|
debug!("Got image {:?}", message);
|
||||||
let element = trusted_node.clone();
|
// Return the image via a message to the script thread, which marks
|
||||||
let image = message.to().unwrap();
|
// the element as dirty and triggers a reflow.
|
||||||
let selected_source_clone = selected_source.clone();
|
let element = trusted_node.clone();
|
||||||
let _ = task_source.queue_with_canceller(
|
let image = message.to().unwrap();
|
||||||
task!(process_image_response_for_environment_change: move || {
|
let selected_source_clone = selected_source.clone();
|
||||||
let element = element.root();
|
let _ = task_source.queue_with_canceller(
|
||||||
// Ignore any image response for a previous request that has been discarded.
|
task!(process_image_response_for_environment_change: move || {
|
||||||
if generation == element.generation.get() {
|
let element = element.root();
|
||||||
element.process_image_response_for_environment_change(image,
|
// Ignore any image response for a previous request that has been discarded.
|
||||||
USVString::from(selected_source_clone), generation, selected_pixel_density);
|
if generation == element.generation.get() {
|
||||||
}
|
element.process_image_response_for_environment_change(image,
|
||||||
}),
|
USVString::from(selected_source_clone), generation, selected_pixel_density);
|
||||||
&canceller,
|
}
|
||||||
);
|
}),
|
||||||
}));
|
&canceller,
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
image_cache.add_listener(id, ImageResponder::new(responder_sender, id));
|
responder_sender
|
||||||
}
|
}
|
||||||
|
|
||||||
let elem = self.upcast::<Element>();
|
let elem = self.upcast::<Element>();
|
||||||
|
@ -1099,25 +1094,32 @@ impl HTMLImageElement {
|
||||||
|
|
||||||
let window = window_from_node(self);
|
let window = window_from_node(self);
|
||||||
let image_cache = window.image_cache();
|
let image_cache = window.image_cache();
|
||||||
|
|
||||||
// Step 14
|
// Step 14
|
||||||
let response = image_cache.find_image_or_metadata(
|
let sender = generate_cache_listener_for_element(
|
||||||
img_url.clone().into(),
|
self,
|
||||||
|
selected_source.0.clone(),
|
||||||
|
selected_pixel_density,
|
||||||
|
);
|
||||||
|
let cache_result = image_cache.track_image(
|
||||||
|
img_url.clone(),
|
||||||
window.origin().immutable().clone(),
|
window.origin().immutable().clone(),
|
||||||
cors_setting_for_element(self.upcast()),
|
cors_setting_for_element(self.upcast()),
|
||||||
|
sender,
|
||||||
UsePlaceholder::No,
|
UsePlaceholder::No,
|
||||||
CanRequestImages::Yes,
|
CanRequestImages::Yes,
|
||||||
);
|
);
|
||||||
match response {
|
|
||||||
Ok(ImageOrMetadataAvailable::ImageAvailable(_image, _url)) => {
|
match cache_result {
|
||||||
|
ImageCacheResult::Available(ImageOrMetadataAvailable::ImageAvailable(_image, _url)) => {
|
||||||
// Step 15
|
// Step 15
|
||||||
self.finish_reacting_to_environment_change(
|
self.finish_reacting_to_environment_change(
|
||||||
selected_source,
|
selected_source,
|
||||||
generation,
|
generation,
|
||||||
selected_pixel_density,
|
selected_pixel_density,
|
||||||
);
|
)
|
||||||
},
|
},
|
||||||
|
ImageCacheResult::Available(ImageOrMetadataAvailable::MetadataAvailable(m)) => {
|
||||||
Ok(ImageOrMetadataAvailable::MetadataAvailable(m)) => {
|
|
||||||
self.process_image_response_for_environment_change(
|
self.process_image_response_for_environment_change(
|
||||||
ImageResponse::MetadataLoaded(m),
|
ImageResponse::MetadataLoaded(m),
|
||||||
selected_source,
|
selected_source,
|
||||||
|
@ -1125,18 +1127,7 @@ impl HTMLImageElement {
|
||||||
selected_pixel_density,
|
selected_pixel_density,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
ImageCacheResult::LoadError => {
|
||||||
Err(ImageState::Pending(id)) => {
|
|
||||||
add_cache_listener_for_element(
|
|
||||||
image_cache.clone(),
|
|
||||||
id,
|
|
||||||
self,
|
|
||||||
selected_source.0,
|
|
||||||
selected_pixel_density,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
Err(ImageState::LoadError) => {
|
|
||||||
self.process_image_response_for_environment_change(
|
self.process_image_response_for_environment_change(
|
||||||
ImageResponse::None,
|
ImageResponse::None,
|
||||||
selected_source,
|
selected_source,
|
||||||
|
@ -1144,17 +1135,8 @@ impl HTMLImageElement {
|
||||||
selected_pixel_density,
|
selected_pixel_density,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
ImageCacheResult::ReadyForRequest(id) => self.fetch_request(&img_url, id),
|
||||||
Err(ImageState::NotRequested(id)) => {
|
ImageCacheResult::Pending(_) => (),
|
||||||
add_cache_listener_for_element(
|
|
||||||
image_cache,
|
|
||||||
id,
|
|
||||||
self,
|
|
||||||
selected_source.0,
|
|
||||||
selected_pixel_density,
|
|
||||||
);
|
|
||||||
self.fetch_request(&img_url, id);
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,16 +19,17 @@ use crate::dom::node::{document_from_node, window_from_node, Node};
|
||||||
use crate::dom::performanceresourcetiming::InitiatorType;
|
use crate::dom::performanceresourcetiming::InitiatorType;
|
||||||
use crate::dom::virtualmethods::VirtualMethods;
|
use crate::dom::virtualmethods::VirtualMethods;
|
||||||
use crate::fetch::FetchCanceller;
|
use crate::fetch::FetchCanceller;
|
||||||
use crate::image_listener::{add_cache_listener_for_element, ImageCacheListener};
|
use crate::image_listener::{generate_cache_listener_for_element, ImageCacheListener};
|
||||||
use crate::network_listener::{self, NetworkListener, PreInvoke, ResourceTimingListener};
|
use crate::network_listener::{self, NetworkListener, PreInvoke, ResourceTimingListener};
|
||||||
use dom_struct::dom_struct;
|
use dom_struct::dom_struct;
|
||||||
use euclid::default::Size2D;
|
use euclid::default::Size2D;
|
||||||
use html5ever::{LocalName, Prefix};
|
use html5ever::{LocalName, Prefix};
|
||||||
use ipc_channel::ipc;
|
use ipc_channel::ipc;
|
||||||
use ipc_channel::router::ROUTER;
|
use ipc_channel::router::ROUTER;
|
||||||
use net_traits::image_cache::UsePlaceholder;
|
use net_traits::image_cache::{
|
||||||
use net_traits::image_cache::{CanRequestImages, ImageCache, ImageOrMetadataAvailable};
|
CanRequestImages, ImageCache, ImageCacheResult, ImageOrMetadataAvailable, ImageResponse,
|
||||||
use net_traits::image_cache::{ImageResponse, ImageState, PendingImageId};
|
PendingImageId, UsePlaceholder,
|
||||||
|
};
|
||||||
use net_traits::request::{CredentialsMode, Destination, RequestBuilder};
|
use net_traits::request::{CredentialsMode, Destination, RequestBuilder};
|
||||||
use net_traits::{
|
use net_traits::{
|
||||||
CoreResourceMsg, FetchChannels, FetchMetadata, FetchResponseListener, FetchResponseMsg,
|
CoreResourceMsg, FetchChannels, FetchMetadata, FetchResponseListener, FetchResponseMsg,
|
||||||
|
@ -155,27 +156,23 @@ impl HTMLVideoElement {
|
||||||
// network activity as possible.
|
// network activity as possible.
|
||||||
let window = window_from_node(self);
|
let window = window_from_node(self);
|
||||||
let image_cache = window.image_cache();
|
let image_cache = window.image_cache();
|
||||||
let response = image_cache.find_image_or_metadata(
|
let sender = generate_cache_listener_for_element(self);
|
||||||
poster_url.clone().into(),
|
let cache_result = image_cache.track_image(
|
||||||
|
poster_url.clone(),
|
||||||
window.origin().immutable().clone(),
|
window.origin().immutable().clone(),
|
||||||
None,
|
None,
|
||||||
|
sender,
|
||||||
UsePlaceholder::No,
|
UsePlaceholder::No,
|
||||||
CanRequestImages::Yes,
|
CanRequestImages::Yes,
|
||||||
);
|
);
|
||||||
match response {
|
|
||||||
Ok(ImageOrMetadataAvailable::ImageAvailable(image, url)) => {
|
|
||||||
self.process_image_response(ImageResponse::Loaded(image, url));
|
|
||||||
},
|
|
||||||
|
|
||||||
Err(ImageState::Pending(id)) => {
|
match cache_result {
|
||||||
add_cache_listener_for_element(image_cache, id, self);
|
ImageCacheResult::Available(ImageOrMetadataAvailable::ImageAvailable(img, url)) => {
|
||||||
|
self.process_image_response(ImageResponse::Loaded(img, url));
|
||||||
},
|
},
|
||||||
|
ImageCacheResult::ReadyForRequest(id) => {
|
||||||
Err(ImageState::NotRequested(id)) => {
|
self.do_fetch_poster_frame(poster_url, id, cancel_receiver)
|
||||||
add_cache_listener_for_element(image_cache, id, self);
|
|
||||||
self.do_fetch_poster_frame(poster_url, id, cancel_receiver);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,20 +8,20 @@ use crate::dom::bindings::reflector::DomObject;
|
||||||
use crate::dom::node::{window_from_node, Node};
|
use crate::dom::node::{window_from_node, Node};
|
||||||
use crate::task_source::TaskSource;
|
use crate::task_source::TaskSource;
|
||||||
use ipc_channel::ipc;
|
use ipc_channel::ipc;
|
||||||
|
use ipc_channel::ipc::IpcSender;
|
||||||
use ipc_channel::router::ROUTER;
|
use ipc_channel::router::ROUTER;
|
||||||
use net_traits::image_cache::{ImageCache, ImageResponder, ImageResponse, PendingImageId};
|
use net_traits::image_cache::{ImageResponse, PendingImageResponse};
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
pub trait ImageCacheListener {
|
pub trait ImageCacheListener {
|
||||||
fn generation_id(&self) -> u32;
|
fn generation_id(&self) -> u32;
|
||||||
fn process_image_response(&self, response: ImageResponse);
|
fn process_image_response(&self, response: ImageResponse);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_cache_listener_for_element<T: ImageCacheListener + DerivedFrom<Node> + DomObject>(
|
pub fn generate_cache_listener_for_element<
|
||||||
image_cache: Arc<dyn ImageCache>,
|
T: ImageCacheListener + DerivedFrom<Node> + DomObject,
|
||||||
id: PendingImageId,
|
>(
|
||||||
elem: &T,
|
elem: &T,
|
||||||
) {
|
) -> IpcSender<PendingImageResponse> {
|
||||||
let trusted_node = Trusted::new(elem);
|
let trusted_node = Trusted::new(elem);
|
||||||
let (responder_sender, responder_receiver) = ipc::channel().unwrap();
|
let (responder_sender, responder_receiver) = ipc::channel().unwrap();
|
||||||
|
|
||||||
|
@ -49,5 +49,5 @@ pub fn add_cache_listener_for_element<T: ImageCacheListener + DerivedFrom<Node>
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
image_cache.add_listener(id, ImageResponder::new(responder_sender, id));
|
responder_sender
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue