mirror of
https://github.com/servo/servo.git
synced 2025-08-04 13:10:20 +01:00
Address some code nits
Signed-off-by: Martin Robinson <mrobinson@igalia.com>
This commit is contained in:
parent
2ab511f19c
commit
cbb2d18bc0
11 changed files with 166 additions and 148 deletions
|
@ -16,8 +16,9 @@ use malloc_size_of::{MallocSizeOf as MallocSizeOfTrait, MallocSizeOfOps};
|
||||||
use malloc_size_of_derive::MallocSizeOf;
|
use malloc_size_of_derive::MallocSizeOf;
|
||||||
use mime::Mime;
|
use mime::Mime;
|
||||||
use net_traits::image_cache::{
|
use net_traits::image_cache::{
|
||||||
Image, ImageCache, ImageCacheMessage, ImageCacheResult, ImageLoadListener,
|
Image, ImageCache, ImageCacheResponseMessage, ImageCacheResult, ImageLoadListener,
|
||||||
ImageOrMetadataAvailable, ImageResponse, PendingImageId, UsePlaceholder, VectorImage,
|
ImageOrMetadataAvailable, ImageResponse, PendingImageId, RasterizationCompleteResponse,
|
||||||
|
UsePlaceholder, VectorImage,
|
||||||
};
|
};
|
||||||
use net_traits::request::CorsSettings;
|
use net_traits::request::CorsSettings;
|
||||||
use net_traits::{FetchMetadata, FetchResponseMsg, FilteredMetadata, NetworkError};
|
use net_traits::{FetchMetadata, FetchResponseMsg, FilteredMetadata, NetworkError};
|
||||||
|
@ -397,41 +398,39 @@ impl PendingLoad {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(MallocSizeOf)]
|
#[derive(Default, MallocSizeOf)]
|
||||||
struct RasterizationTask {
|
struct RasterizationTask {
|
||||||
listeners: Vec<(PipelineId, IpcSender<ImageCacheMessage>)>,
|
listeners: Vec<(PipelineId, IpcSender<ImageCacheResponseMessage>)>,
|
||||||
result: Option<RasterImage>,
|
result: Option<RasterImage>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// ======================================================================
|
/// ## Image cache implementation.
|
||||||
// Image cache implementation.
|
|
||||||
// ======================================================================
|
|
||||||
#[derive(MallocSizeOf)]
|
#[derive(MallocSizeOf)]
|
||||||
struct ImageCacheStore {
|
struct ImageCacheStore {
|
||||||
// Images that are loading over network, or decoding.
|
/// Images that are loading over network, or decoding.
|
||||||
pending_loads: AllPendingLoads,
|
pending_loads: AllPendingLoads,
|
||||||
|
|
||||||
// Images that have finished loading (successful or not)
|
/// Images that have finished loading (successful or not)
|
||||||
completed_loads: HashMap<ImageKey, CompletedLoad>,
|
completed_loads: HashMap<ImageKey, CompletedLoad>,
|
||||||
|
|
||||||
// Vector (e.g. SVG) images that have been sucessfully loaded and parsed
|
/// Vector (e.g. SVG) images that have been sucessfully loaded and parsed
|
||||||
// but are yet to be rasterized. Since the same SVG data can be used for
|
/// but are yet to be rasterized. Since the same SVG data can be used for
|
||||||
// rasterizing at different sizes, we use this hasmap to share the data.
|
/// rasterizing at different sizes, we use this hasmap to share the data.
|
||||||
vector_images: HashMap<PendingImageId, VectorImageData>,
|
vector_images: HashMap<PendingImageId, VectorImageData>,
|
||||||
|
|
||||||
// Vector images for which rasterization at a particular size has started
|
/// Vector images for which rasterization at a particular size has started
|
||||||
// or completed. If completed, the `result` member of `RasterizationTask`
|
/// or completed. If completed, the `result` member of `RasterizationTask`
|
||||||
// contains the rasterized image.
|
/// contains the rasterized image.
|
||||||
rasterized_vector_images: HashMap<(PendingImageId, DeviceIntSize), RasterizationTask>,
|
rasterized_vector_images: HashMap<(PendingImageId, DeviceIntSize), RasterizationTask>,
|
||||||
|
|
||||||
// The placeholder image used when an image fails to load
|
/// The placeholder image used when an image fails to load
|
||||||
#[conditional_malloc_size_of]
|
#[conditional_malloc_size_of]
|
||||||
placeholder_image: Arc<RasterImage>,
|
placeholder_image: Arc<RasterImage>,
|
||||||
|
|
||||||
// The URL used for the placeholder image
|
/// The URL used for the placeholder image
|
||||||
placeholder_url: ServoUrl,
|
placeholder_url: ServoUrl,
|
||||||
|
|
||||||
// Cross-process compositor API instance.
|
/// Cross-process compositor API instance.
|
||||||
#[ignore_malloc_size_of = "Channel from another crate"]
|
#[ignore_malloc_size_of = "Channel from another crate"]
|
||||||
compositor_api: CrossProcessCompositorApi,
|
compositor_api: CrossProcessCompositorApi,
|
||||||
}
|
}
|
||||||
|
@ -683,39 +682,38 @@ impl ImageCache for ImageCacheImpl {
|
||||||
&self,
|
&self,
|
||||||
pipeline_id: PipelineId,
|
pipeline_id: PipelineId,
|
||||||
image_id: PendingImageId,
|
image_id: PendingImageId,
|
||||||
size: DeviceIntSize,
|
requested_size: DeviceIntSize,
|
||||||
sender: IpcSender<ImageCacheMessage>,
|
sender: IpcSender<ImageCacheResponseMessage>,
|
||||||
) {
|
) {
|
||||||
let key = (image_id, size);
|
|
||||||
let completed = {
|
let completed = {
|
||||||
let mut store = self.store.lock().unwrap();
|
let mut store = self.store.lock().unwrap();
|
||||||
|
let key = (image_id, requested_size);
|
||||||
if !store.vector_images.contains_key(&image_id) {
|
if !store.vector_images.contains_key(&image_id) {
|
||||||
warn!("Unknown image requested for rasterization for key {key:?}");
|
warn!("Unknown image requested for rasterization for key {key:?}");
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
match store.rasterized_vector_images.entry(key) {
|
let Some(task) = store.rasterized_vector_images.get_mut(&key) else {
|
||||||
Occupied(mut entry) => {
|
warn!("Image rasterization task not found in the cache for key {key:?}");
|
||||||
let task = entry.get_mut();
|
return;
|
||||||
if task.result.is_some() {
|
};
|
||||||
true
|
|
||||||
} else {
|
match task.result {
|
||||||
task.listeners.push((pipeline_id, sender.clone()));
|
Some(_) => true,
|
||||||
false
|
None => {
|
||||||
}
|
task.listeners.push((pipeline_id, sender.clone()));
|
||||||
},
|
false
|
||||||
Vacant(_) => {
|
|
||||||
warn!("Image rasterization task not found in the cache for key {key:?}");
|
|
||||||
return;
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if completed {
|
if completed {
|
||||||
let _ = sender.send(ImageCacheMessage::VectorImageRasterizationCompleted(
|
let _ = sender.send(ImageCacheResponseMessage::VectorImageRasterizationComplete(
|
||||||
pipeline_id,
|
RasterizationCompleteResponse {
|
||||||
image_id,
|
pipeline_id,
|
||||||
size,
|
image_id,
|
||||||
|
requested_size,
|
||||||
|
},
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -723,7 +721,7 @@ impl ImageCache for ImageCacheImpl {
|
||||||
fn rasterize_vector_image(
|
fn rasterize_vector_image(
|
||||||
&self,
|
&self,
|
||||||
image_id: PendingImageId,
|
image_id: PendingImageId,
|
||||||
size: DeviceIntSize,
|
requested_size: DeviceIntSize,
|
||||||
) -> Option<RasterImage> {
|
) -> Option<RasterImage> {
|
||||||
let mut store = self.store.lock().unwrap();
|
let mut store = self.store.lock().unwrap();
|
||||||
let Some(vector_image) = store.vector_images.get(&image_id).cloned() else {
|
let Some(vector_image) = store.vector_images.get(&image_id).cloned() else {
|
||||||
|
@ -731,44 +729,48 @@ impl ImageCache for ImageCacheImpl {
|
||||||
return None;
|
return None;
|
||||||
};
|
};
|
||||||
|
|
||||||
match store.rasterized_vector_images.entry((image_id, size)) {
|
// This early return relies on the fact that the result of image rasterization cannot
|
||||||
Occupied(occupied_entry) => {
|
// ever be `None`. If that were the case we would need to check whether the entry
|
||||||
return occupied_entry.get().result.clone();
|
// in the `HashMap` was `Occupied` or not.
|
||||||
},
|
let entry = store
|
||||||
Vacant(entry) => entry.insert(RasterizationTask {
|
.rasterized_vector_images
|
||||||
listeners: vec![],
|
.entry((image_id, requested_size))
|
||||||
result: None,
|
.or_default();
|
||||||
}),
|
if let Some(result) = entry.result.as_ref() {
|
||||||
};
|
return Some(result.clone());
|
||||||
|
}
|
||||||
|
|
||||||
let store = self.store.clone();
|
let store = self.store.clone();
|
||||||
self.thread_pool.spawn(move || {
|
self.thread_pool.spawn(move || {
|
||||||
let natural_size = vector_image.svg_tree.size().to_int_size();
|
let natural_size = vector_image.svg_tree.size().to_int_size();
|
||||||
let requested_size = {
|
let tinyskia_requested_size = {
|
||||||
let width = size.width.try_into().unwrap_or(0);
|
let width = requested_size.width.try_into().unwrap_or(0);
|
||||||
let height = size.height.try_into().unwrap_or(0);
|
let height = requested_size.height.try_into().unwrap_or(0);
|
||||||
tiny_skia::IntSize::from_wh(width, height).unwrap_or(natural_size)
|
tiny_skia::IntSize::from_wh(width, height).unwrap_or(natural_size)
|
||||||
};
|
};
|
||||||
let transform = tiny_skia::Transform::from_scale(
|
let transform = tiny_skia::Transform::from_scale(
|
||||||
requested_size.width() as f32 / natural_size.width() as f32,
|
tinyskia_requested_size.width() as f32 / natural_size.width() as f32,
|
||||||
requested_size.height() as f32 / natural_size.height() as f32,
|
tinyskia_requested_size.height() as f32 / natural_size.height() as f32,
|
||||||
);
|
);
|
||||||
let mut pixmap =
|
let mut pixmap = tiny_skia::Pixmap::new(
|
||||||
tiny_skia::Pixmap::new(requested_size.width(), requested_size.height()).unwrap();
|
tinyskia_requested_size.width(),
|
||||||
|
tinyskia_requested_size.height(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
resvg::render(&vector_image.svg_tree, transform, &mut pixmap.as_mut());
|
resvg::render(&vector_image.svg_tree, transform, &mut pixmap.as_mut());
|
||||||
|
|
||||||
let bytes = pixmap.take();
|
let bytes = pixmap.take();
|
||||||
let frame = ImageFrame {
|
let frame = ImageFrame {
|
||||||
delay: None,
|
delay: None,
|
||||||
byte_range: 0..bytes.len(),
|
byte_range: 0..bytes.len(),
|
||||||
width: requested_size.width(),
|
width: tinyskia_requested_size.width(),
|
||||||
height: requested_size.height(),
|
height: tinyskia_requested_size.height(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut rasterized_image = RasterImage {
|
let mut rasterized_image = RasterImage {
|
||||||
metadata: ImageMetadata {
|
metadata: ImageMetadata {
|
||||||
width: requested_size.width(),
|
width: tinyskia_requested_size.width(),
|
||||||
height: requested_size.height(),
|
height: tinyskia_requested_size.height(),
|
||||||
},
|
},
|
||||||
format: PixelFormat::RGBA8,
|
format: PixelFormat::RGBA8,
|
||||||
frames: vec![frame],
|
frames: vec![frame],
|
||||||
|
@ -780,19 +782,23 @@ impl ImageCache for ImageCacheImpl {
|
||||||
let listeners = {
|
let listeners = {
|
||||||
let mut store = store.lock().unwrap();
|
let mut store = store.lock().unwrap();
|
||||||
set_webrender_image_key(&store.compositor_api, &mut rasterized_image);
|
set_webrender_image_key(&store.compositor_api, &mut rasterized_image);
|
||||||
if let Some(task) = store.rasterized_vector_images.get_mut(&(image_id, size)) {
|
store
|
||||||
task.result = Some(rasterized_image);
|
.rasterized_vector_images
|
||||||
std::mem::take(&mut task.listeners)
|
.get_mut(&(image_id, requested_size))
|
||||||
} else {
|
.map(|task| {
|
||||||
Vec::new()
|
task.result = Some(rasterized_image);
|
||||||
}
|
std::mem::take(&mut task.listeners)
|
||||||
|
})
|
||||||
|
.unwrap_or_default()
|
||||||
};
|
};
|
||||||
|
|
||||||
for (pipeline_id, sender) in listeners {
|
for (pipeline_id, sender) in listeners {
|
||||||
let _ = sender.send(ImageCacheMessage::VectorImageRasterizationCompleted(
|
let _ = sender.send(ImageCacheResponseMessage::VectorImageRasterizationComplete(
|
||||||
pipeline_id,
|
RasterizationCompleteResponse {
|
||||||
image_id,
|
pipeline_id,
|
||||||
size,
|
image_id,
|
||||||
|
requested_size,
|
||||||
|
},
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -7,6 +7,7 @@ use std::rc::Rc;
|
||||||
|
|
||||||
use dom_struct::dom_struct;
|
use dom_struct::dom_struct;
|
||||||
use js::rust::{HandleObject, MutableHandleValue};
|
use js::rust::{HandleObject, MutableHandleValue};
|
||||||
|
use net_traits::image_cache::Image;
|
||||||
|
|
||||||
use crate::dom::bindings::cell::DomRefCell;
|
use crate::dom::bindings::cell::DomRefCell;
|
||||||
use crate::dom::bindings::codegen::Bindings::DataTransferBinding::DataTransferMethods;
|
use crate::dom::bindings::codegen::Bindings::DataTransferBinding::DataTransferMethods;
|
||||||
|
@ -155,10 +156,9 @@ impl DataTransferMethods<crate::DomTypeHolder> for DataTransfer {
|
||||||
|
|
||||||
// Step 3
|
// Step 3
|
||||||
if let Some(image) = image.downcast::<HTMLImageElement>() {
|
if let Some(image) = image.downcast::<HTMLImageElement>() {
|
||||||
if let Some(image) = image.image_data().and_then(|image| image.as_raster_image()) {
|
match image.image_data().as_ref().and_then(Image::as_raster_image) {
|
||||||
data_store.set_bitmap(Some(image), x, y);
|
Some(image) => data_store.set_bitmap(Some(image), x, y),
|
||||||
} else {
|
None => warn!("Vector images are not yet supported in setDragImage"),
|
||||||
warn!("Vector images are not yet supported in setDragImage");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -341,14 +341,12 @@ impl HTMLImageElement {
|
||||||
is_placeholder,
|
is_placeholder,
|
||||||
}) => {
|
}) => {
|
||||||
if is_placeholder {
|
if is_placeholder {
|
||||||
let image = image
|
if let Some(raster_image) = image.as_raster_image() {
|
||||||
.as_raster_image()
|
self.process_image_response(
|
||||||
.expect("Only raster images are supported as placeholders currently");
|
ImageResponse::PlaceholderLoaded(raster_image, url),
|
||||||
|
can_gc,
|
||||||
self.process_image_response(
|
)
|
||||||
ImageResponse::PlaceholderLoaded(image, url),
|
}
|
||||||
can_gc,
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
self.process_image_response(ImageResponse::Loaded(image, url), can_gc)
|
self.process_image_response(ImageResponse::Loaded(image, url), can_gc)
|
||||||
}
|
}
|
||||||
|
|
|
@ -262,11 +262,10 @@ impl HTMLVideoElement {
|
||||||
match response {
|
match response {
|
||||||
ImageResponse::Loaded(image, url) => {
|
ImageResponse::Loaded(image, url) => {
|
||||||
debug!("Loaded poster image for video element: {:?}", url);
|
debug!("Loaded poster image for video element: {:?}", url);
|
||||||
if let Some(image) = image.as_raster_image() {
|
match image.as_raster_image() {
|
||||||
self.htmlmediaelement.process_poster_image_loaded(image);
|
Some(image) => self.htmlmediaelement.process_poster_image_loaded(image),
|
||||||
} else {
|
None => warn!("Vector images are not yet supported in video poster"),
|
||||||
warn!("Vector images are not yet supported in video poster");
|
}
|
||||||
};
|
|
||||||
LoadBlocker::terminate(&self.load_blocker, can_gc);
|
LoadBlocker::terminate(&self.load_blocker, can_gc);
|
||||||
},
|
},
|
||||||
ImageResponse::MetadataLoaded(..) => {},
|
ImageResponse::MetadataLoaded(..) => {},
|
||||||
|
|
|
@ -21,8 +21,8 @@ use js::jsval::JSVal;
|
||||||
use js::rust::{HandleObject, MutableHandleValue};
|
use js::rust::{HandleObject, MutableHandleValue};
|
||||||
use net_traits::http_status::HttpStatus;
|
use net_traits::http_status::HttpStatus;
|
||||||
use net_traits::image_cache::{
|
use net_traits::image_cache::{
|
||||||
ImageCache, ImageCacheMessage, ImageCacheResult, ImageLoadListener, ImageOrMetadataAvailable,
|
ImageCache, ImageCacheResponseMessage, ImageCacheResult, ImageLoadListener,
|
||||||
ImageResponse, PendingImageId, UsePlaceholder,
|
ImageOrMetadataAvailable, ImageResponse, PendingImageId, UsePlaceholder,
|
||||||
};
|
};
|
||||||
use net_traits::request::{RequestBuilder, RequestId};
|
use net_traits::request::{RequestBuilder, RequestId};
|
||||||
use net_traits::{
|
use net_traits::{
|
||||||
|
@ -929,7 +929,7 @@ impl Notification {
|
||||||
pending_image_id: PendingImageId,
|
pending_image_id: PendingImageId,
|
||||||
resource_type: ResourceType,
|
resource_type: ResourceType,
|
||||||
) {
|
) {
|
||||||
let (sender, receiver) = ipc::channel::<ImageCacheMessage>().expect("ipc channel failure");
|
let (sender, receiver) = ipc::channel().expect("ipc channel failure");
|
||||||
|
|
||||||
let global: &GlobalScope = &self.global();
|
let global: &GlobalScope = &self.global();
|
||||||
|
|
||||||
|
@ -945,7 +945,7 @@ impl Notification {
|
||||||
task_source.queue(task!(handle_response: move || {
|
task_source.queue(task!(handle_response: move || {
|
||||||
let this = trusted_this.root();
|
let this = trusted_this.root();
|
||||||
if let Ok(response) = response {
|
if let Ok(response) = response {
|
||||||
let ImageCacheMessage::NotifyPendingImageLoadStatus(status) = response else {
|
let ImageCacheResponseMessage::NotifyPendingImageLoadStatus(status) = response else {
|
||||||
warn!("Received unexpected message from image cache: {response:?}");
|
warn!("Received unexpected message from image cache: {response:?}");
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
|
@ -609,23 +609,29 @@ impl WebGLRenderingContext {
|
||||||
};
|
};
|
||||||
let cors_setting = cors_setting_for_element(image.upcast());
|
let cors_setting = cors_setting_for_element(image.upcast());
|
||||||
|
|
||||||
let img =
|
let img = match canvas_utils::request_image_from_cache(
|
||||||
match canvas_utils::request_image_from_cache(&window, img_url, cors_setting) {
|
&window,
|
||||||
ImageResponse::Loaded(image, _) => {
|
img_url,
|
||||||
if let Some(image) = image.as_raster_image() {
|
cors_setting,
|
||||||
image
|
) {
|
||||||
} else {
|
ImageResponse::Loaded(image, _) => {
|
||||||
// Related https://github.com/KhronosGroup/WebGL/issues/1503?
|
match image.as_raster_image() {
|
||||||
|
Some(image) => image,
|
||||||
|
None => {
|
||||||
|
// Vector images are not currently supported here and there are some open questions
|
||||||
|
// in the specification about how to handle them:
|
||||||
|
// See https://github.com/KhronosGroup/WebGL/issues/1503.
|
||||||
warn!(
|
warn!(
|
||||||
"Vector images as are not yet supported as WebGL texture source"
|
"Vector images as are not yet supported as WebGL texture source"
|
||||||
);
|
);
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
},
|
||||||
},
|
}
|
||||||
ImageResponse::PlaceholderLoaded(_, _) |
|
},
|
||||||
ImageResponse::None |
|
ImageResponse::PlaceholderLoaded(_, _) |
|
||||||
ImageResponse::MetadataLoaded(_) => return Ok(None),
|
ImageResponse::None |
|
||||||
};
|
ImageResponse::MetadataLoaded(_) => return Ok(None),
|
||||||
|
};
|
||||||
|
|
||||||
let size = Size2D::new(img.metadata.width, img.metadata.height);
|
let size = Size2D::new(img.metadata.width, img.metadata.height);
|
||||||
|
|
||||||
|
|
|
@ -55,8 +55,8 @@ use malloc_size_of::MallocSizeOf;
|
||||||
use media::WindowGLContext;
|
use media::WindowGLContext;
|
||||||
use net_traits::ResourceThreads;
|
use net_traits::ResourceThreads;
|
||||||
use net_traits::image_cache::{
|
use net_traits::image_cache::{
|
||||||
ImageCache, ImageCacheMessage, ImageLoadListener, ImageResponse, PendingImageId,
|
ImageCache, ImageCacheResponseMessage, ImageLoadListener, ImageResponse, PendingImageId,
|
||||||
PendingImageResponse,
|
PendingImageResponse, RasterizationCompleteResponse,
|
||||||
};
|
};
|
||||||
use net_traits::storage_thread::StorageType;
|
use net_traits::storage_thread::StorageType;
|
||||||
use num_traits::ToPrimitive;
|
use num_traits::ToPrimitive;
|
||||||
|
@ -243,7 +243,7 @@ pub(crate) struct Window {
|
||||||
#[no_trace]
|
#[no_trace]
|
||||||
image_cache: Arc<dyn ImageCache>,
|
image_cache: Arc<dyn ImageCache>,
|
||||||
#[no_trace]
|
#[no_trace]
|
||||||
image_cache_sender: IpcSender<ImageCacheMessage>,
|
image_cache_sender: IpcSender<ImageCacheResponseMessage>,
|
||||||
window_proxy: MutNullableDom<WindowProxy>,
|
window_proxy: MutNullableDom<WindowProxy>,
|
||||||
document: MutNullableDom<Document>,
|
document: MutNullableDom<Document>,
|
||||||
location: MutNullableDom<Location>,
|
location: MutNullableDom<Location>,
|
||||||
|
@ -346,13 +346,13 @@ pub(crate) struct Window {
|
||||||
pending_image_callbacks: DomRefCell<HashMap<PendingImageId, Vec<PendingImageCallback>>>,
|
pending_image_callbacks: DomRefCell<HashMap<PendingImageId, Vec<PendingImageCallback>>>,
|
||||||
|
|
||||||
/// All of the elements that have an outstanding image request that was
|
/// All of the elements that have an outstanding image request that was
|
||||||
/// initiated by layout during a reflow. They are stored in the script thread
|
/// initiated by layout during a reflow. They are stored in the [`ScriptThread`]
|
||||||
/// to ensure that the element can be marked dirty when the image data becomes
|
/// to ensure that the element can be marked dirty when the image data becomes
|
||||||
/// available at some point in the future.
|
/// available at some point in the future.
|
||||||
pending_layout_images: DomRefCell<HashMapTracedValues<PendingImageId, Vec<Dom<Node>>>>,
|
pending_layout_images: DomRefCell<HashMapTracedValues<PendingImageId, Vec<Dom<Node>>>>,
|
||||||
|
|
||||||
/// Vector images for which layout has intiated rasterization at a specific size
|
/// Vector images for which layout has intiated rasterization at a specific size
|
||||||
/// and whose results are not yet available. They are stored in the script thread
|
/// and whose results are not yet available. They are stored in the [`ScriptThread`]
|
||||||
/// so that the element can be marked dirty once the rasterization is completed.
|
/// so that the element can be marked dirty once the rasterization is completed.
|
||||||
pending_images_for_rasterization:
|
pending_images_for_rasterization:
|
||||||
DomRefCell<HashMapTracedValues<PendingImageRasterizationKey, Vec<Dom<Node>>>>,
|
DomRefCell<HashMapTracedValues<PendingImageRasterizationKey, Vec<Dom<Node>>>>,
|
||||||
|
@ -577,7 +577,7 @@ impl Window {
|
||||||
&self,
|
&self,
|
||||||
id: PendingImageId,
|
id: PendingImageId,
|
||||||
callback: impl Fn(PendingImageResponse) + 'static,
|
callback: impl Fn(PendingImageResponse) + 'static,
|
||||||
) -> IpcSender<ImageCacheMessage> {
|
) -> IpcSender<ImageCacheResponseMessage> {
|
||||||
self.pending_image_callbacks
|
self.pending_image_callbacks
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.entry(id)
|
.entry(id)
|
||||||
|
@ -608,11 +608,10 @@ impl Window {
|
||||||
|
|
||||||
pub(crate) fn handle_image_rasterization_complete_notification(
|
pub(crate) fn handle_image_rasterization_complete_notification(
|
||||||
&self,
|
&self,
|
||||||
image_id: PendingImageId,
|
response: RasterizationCompleteResponse,
|
||||||
size: DeviceIntSize,
|
|
||||||
) {
|
) {
|
||||||
let mut images = self.pending_images_for_rasterization.borrow_mut();
|
let mut images = self.pending_images_for_rasterization.borrow_mut();
|
||||||
let nodes = images.entry((image_id, size));
|
let nodes = images.entry((response.image_id, response.requested_size));
|
||||||
let nodes = match nodes {
|
let nodes = match nodes {
|
||||||
Entry::Occupied(nodes) => nodes,
|
Entry::Occupied(nodes) => nodes,
|
||||||
Entry::Vacant(_) => return,
|
Entry::Vacant(_) => return,
|
||||||
|
@ -3054,7 +3053,7 @@ impl Window {
|
||||||
script_chan: Sender<MainThreadScriptMsg>,
|
script_chan: Sender<MainThreadScriptMsg>,
|
||||||
layout: Box<dyn Layout>,
|
layout: Box<dyn Layout>,
|
||||||
font_context: Arc<FontContext>,
|
font_context: Arc<FontContext>,
|
||||||
image_cache_sender: IpcSender<ImageCacheMessage>,
|
image_cache_sender: IpcSender<ImageCacheResponseMessage>,
|
||||||
image_cache: Arc<dyn ImageCache>,
|
image_cache: Arc<dyn ImageCache>,
|
||||||
resource_threads: ResourceThreads,
|
resource_threads: ResourceThreads,
|
||||||
#[cfg(feature = "bluetooth")] bluetooth_thread: IpcSender<BluetoothRequest>,
|
#[cfg(feature = "bluetooth")] bluetooth_thread: IpcSender<BluetoothRequest>,
|
||||||
|
|
|
@ -16,7 +16,7 @@ use crossbeam_channel::{Receiver, SendError, Sender, select};
|
||||||
use devtools_traits::{DevtoolScriptControlMsg, ScriptToDevtoolsControlMsg};
|
use devtools_traits::{DevtoolScriptControlMsg, ScriptToDevtoolsControlMsg};
|
||||||
use ipc_channel::ipc::IpcSender;
|
use ipc_channel::ipc::IpcSender;
|
||||||
use net_traits::FetchResponseMsg;
|
use net_traits::FetchResponseMsg;
|
||||||
use net_traits::image_cache::ImageCacheMessage;
|
use net_traits::image_cache::ImageCacheResponseMessage;
|
||||||
use profile_traits::mem::{self as profile_mem, OpaqueSender, ReportsChan};
|
use profile_traits::mem::{self as profile_mem, OpaqueSender, ReportsChan};
|
||||||
use profile_traits::time::{self as profile_time};
|
use profile_traits::time::{self as profile_time};
|
||||||
use script_traits::{Painter, ScriptThreadMessage};
|
use script_traits::{Painter, ScriptThreadMessage};
|
||||||
|
@ -40,7 +40,7 @@ pub(crate) enum MixedMessage {
|
||||||
FromConstellation(ScriptThreadMessage),
|
FromConstellation(ScriptThreadMessage),
|
||||||
FromScript(MainThreadScriptMsg),
|
FromScript(MainThreadScriptMsg),
|
||||||
FromDevtools(DevtoolScriptControlMsg),
|
FromDevtools(DevtoolScriptControlMsg),
|
||||||
FromImageCache(ImageCacheMessage),
|
FromImageCache(ImageCacheResponseMessage),
|
||||||
#[cfg(feature = "webgpu")]
|
#[cfg(feature = "webgpu")]
|
||||||
FromWebGPUServer(WebGPUMsg),
|
FromWebGPUServer(WebGPUMsg),
|
||||||
TimerFired,
|
TimerFired,
|
||||||
|
@ -105,11 +105,11 @@ impl MixedMessage {
|
||||||
MainThreadScriptMsg::WakeUp => None,
|
MainThreadScriptMsg::WakeUp => None,
|
||||||
},
|
},
|
||||||
MixedMessage::FromImageCache(response) => match response {
|
MixedMessage::FromImageCache(response) => match response {
|
||||||
ImageCacheMessage::NotifyPendingImageLoadStatus(response) => {
|
ImageCacheResponseMessage::NotifyPendingImageLoadStatus(response) => {
|
||||||
Some(response.pipeline_id)
|
Some(response.pipeline_id)
|
||||||
},
|
},
|
||||||
ImageCacheMessage::VectorImageRasterizationCompleted(pipeline_id, ..) => {
|
ImageCacheResponseMessage::VectorImageRasterizationComplete(response) => {
|
||||||
Some(*pipeline_id)
|
Some(response.pipeline_id)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
MixedMessage::FromDevtools(_) | MixedMessage::TimerFired => None,
|
MixedMessage::FromDevtools(_) | MixedMessage::TimerFired => None,
|
||||||
|
@ -333,7 +333,7 @@ pub(crate) struct ScriptThreadSenders {
|
||||||
/// messages on this channel are routed to crossbeam [`Sender`] on the router thread, which
|
/// messages on this channel are routed to crossbeam [`Sender`] on the router thread, which
|
||||||
/// in turn sends messages to [`ScriptThreadReceivers::image_cache_receiver`].
|
/// in turn sends messages to [`ScriptThreadReceivers::image_cache_receiver`].
|
||||||
#[no_trace]
|
#[no_trace]
|
||||||
pub(crate) image_cache_sender: IpcSender<ImageCacheMessage>,
|
pub(crate) image_cache_sender: IpcSender<ImageCacheResponseMessage>,
|
||||||
|
|
||||||
/// For providing contact with the time profiler.
|
/// For providing contact with the time profiler.
|
||||||
#[no_trace]
|
#[no_trace]
|
||||||
|
@ -362,7 +362,7 @@ pub(crate) struct ScriptThreadReceivers {
|
||||||
|
|
||||||
/// The [`Receiver`] which receives incoming messages from the `ImageCache`.
|
/// The [`Receiver`] which receives incoming messages from the `ImageCache`.
|
||||||
#[no_trace]
|
#[no_trace]
|
||||||
pub(crate) image_cache_receiver: Receiver<ImageCacheMessage>,
|
pub(crate) image_cache_receiver: Receiver<ImageCacheResponseMessage>,
|
||||||
|
|
||||||
/// For receiving commands from an optional devtools server. Will be ignored if no such server
|
/// For receiving commands from an optional devtools server. Will be ignored if no such server
|
||||||
/// exists. When devtools are not active this will be [`crossbeam_channel::never()`].
|
/// exists. When devtools are not active this will be [`crossbeam_channel::never()`].
|
||||||
|
|
|
@ -71,7 +71,7 @@ use js::jsval::UndefinedValue;
|
||||||
use js::rust::ParentRuntime;
|
use js::rust::ParentRuntime;
|
||||||
use media::WindowGLContext;
|
use media::WindowGLContext;
|
||||||
use metrics::MAX_TASK_NS;
|
use metrics::MAX_TASK_NS;
|
||||||
use net_traits::image_cache::{ImageCache, ImageCacheMessage};
|
use net_traits::image_cache::{ImageCache, ImageCacheResponseMessage};
|
||||||
use net_traits::request::{Referrer, RequestId};
|
use net_traits::request::{Referrer, RequestId};
|
||||||
use net_traits::response::ResponseInit;
|
use net_traits::response::ResponseInit;
|
||||||
use net_traits::storage_thread::StorageType;
|
use net_traits::storage_thread::StorageType;
|
||||||
|
@ -2095,9 +2095,9 @@ impl ScriptThread {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_msg_from_image_cache(&self, response: ImageCacheMessage) {
|
fn handle_msg_from_image_cache(&self, response: ImageCacheResponseMessage) {
|
||||||
match response {
|
match response {
|
||||||
ImageCacheMessage::NotifyPendingImageLoadStatus(pending_image_response) => {
|
ImageCacheResponseMessage::NotifyPendingImageLoadStatus(pending_image_response) => {
|
||||||
let window = self
|
let window = self
|
||||||
.documents
|
.documents
|
||||||
.borrow()
|
.borrow()
|
||||||
|
@ -2106,10 +2106,10 @@ impl ScriptThread {
|
||||||
window.pending_image_notification(pending_image_response);
|
window.pending_image_notification(pending_image_response);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ImageCacheMessage::VectorImageRasterizationCompleted(pipeline_id, image_id, size) => {
|
ImageCacheResponseMessage::VectorImageRasterizationComplete(response) => {
|
||||||
let window = self.documents.borrow().find_window(pipeline_id);
|
let window = self.documents.borrow().find_window(response.pipeline_id);
|
||||||
if let Some(ref window) = window {
|
if let Some(ref window) = window {
|
||||||
window.handle_image_rasterization_complete_notification(image_id, size);
|
window.handle_image_rasterization_complete_notification(response);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -24,9 +24,10 @@ use crate::request::CorsSettings;
|
||||||
// ======================================================================
|
// ======================================================================
|
||||||
|
|
||||||
pub type VectorImageId = PendingImageId;
|
pub type VectorImageId = PendingImageId;
|
||||||
|
|
||||||
// Represents either a raster image for which the pixel data is available
|
// Represents either a raster image for which the pixel data is available
|
||||||
// or a vector image for which only the natural dimensions are available
|
// or a vector image for which only the natural dimensions are available
|
||||||
// and thus require an further rasterization step.
|
// and thus requires a further rasterization step to render.
|
||||||
#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
|
#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
|
||||||
pub enum Image {
|
pub enum Image {
|
||||||
Raster(#[conditional_malloc_size_of] Arc<RasterImage>),
|
Raster(#[conditional_malloc_size_of] Arc<RasterImage>),
|
||||||
|
@ -82,12 +83,12 @@ pub enum ImageOrMetadataAvailable {
|
||||||
pub struct ImageLoadListener {
|
pub struct ImageLoadListener {
|
||||||
pipeline_id: PipelineId,
|
pipeline_id: PipelineId,
|
||||||
pub id: PendingImageId,
|
pub id: PendingImageId,
|
||||||
sender: IpcSender<ImageCacheMessage>,
|
sender: IpcSender<ImageCacheResponseMessage>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ImageLoadListener {
|
impl ImageLoadListener {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
sender: IpcSender<ImageCacheMessage>,
|
sender: IpcSender<ImageCacheResponseMessage>,
|
||||||
pipeline_id: PipelineId,
|
pipeline_id: PipelineId,
|
||||||
id: PendingImageId,
|
id: PendingImageId,
|
||||||
) -> ImageLoadListener {
|
) -> ImageLoadListener {
|
||||||
|
@ -103,14 +104,15 @@ impl ImageLoadListener {
|
||||||
// This send can fail if thread waiting for this notification has panicked.
|
// This send can fail if thread waiting for this notification has panicked.
|
||||||
// That's not a case that's worth warning about.
|
// That's not a case that's worth warning about.
|
||||||
// TODO(#15501): are there cases in which we should perform cleanup?
|
// TODO(#15501): are there cases in which we should perform cleanup?
|
||||||
let msg = PendingImageResponse {
|
|
||||||
pipeline_id: self.pipeline_id,
|
|
||||||
response,
|
|
||||||
id: self.id,
|
|
||||||
};
|
|
||||||
let _ = self
|
let _ = self
|
||||||
.sender
|
.sender
|
||||||
.send(ImageCacheMessage::NotifyPendingImageLoadStatus(msg));
|
.send(ImageCacheResponseMessage::NotifyPendingImageLoadStatus(
|
||||||
|
PendingImageResponse {
|
||||||
|
pipeline_id: self.pipeline_id,
|
||||||
|
response,
|
||||||
|
id: self.id,
|
||||||
|
},
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,9 +141,16 @@ pub struct PendingImageResponse {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||||
pub enum ImageCacheMessage {
|
pub struct RasterizationCompleteResponse {
|
||||||
|
pub pipeline_id: PipelineId,
|
||||||
|
pub image_id: PendingImageId,
|
||||||
|
pub requested_size: DeviceIntSize,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||||
|
pub enum ImageCacheResponseMessage {
|
||||||
NotifyPendingImageLoadStatus(PendingImageResponse),
|
NotifyPendingImageLoadStatus(PendingImageResponse),
|
||||||
VectorImageRasterizationCompleted(PipelineId, PendingImageId, DeviceIntSize),
|
VectorImageRasterizationComplete(RasterizationCompleteResponse),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
|
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
|
||||||
|
@ -184,26 +193,26 @@ pub trait ImageCache: Sync + Send {
|
||||||
use_placeholder: UsePlaceholder,
|
use_placeholder: UsePlaceholder,
|
||||||
) -> ImageCacheResult;
|
) -> ImageCacheResult;
|
||||||
|
|
||||||
// Returns `Some` if the given `image_id` has already been rasterized at the given `size`.
|
/// Returns `Some` if the given `image_id` has already been rasterized at the given `size`.
|
||||||
// Otherwise, triggers a new job to perform the rasterization. If a notification
|
/// Otherwise, triggers a new job to perform the rasterization. If a notification
|
||||||
// is needed after rasterization is completed, the `add_rasterization_complete_listener`
|
/// is needed after rasterization is completed, the `add_rasterization_complete_listener`
|
||||||
// API below can be used to add a listener.
|
/// API below can be used to add a listener.
|
||||||
fn rasterize_vector_image(
|
fn rasterize_vector_image(
|
||||||
&self,
|
&self,
|
||||||
image_id: VectorImageId,
|
image_id: VectorImageId,
|
||||||
size: DeviceIntSize,
|
size: DeviceIntSize,
|
||||||
) -> Option<RasterImage>;
|
) -> Option<RasterImage>;
|
||||||
|
|
||||||
// Adds a new listener to be notified once the given `image_id` has been rasterized at
|
/// Adds a new listener to be notified once the given `image_id` has been rasterized at
|
||||||
// the given `size`. The listener will receive a `VectorImageRasterizationCompleted`
|
/// the given `size`. The listener will receive a `VectorImageRasterizationComplete`
|
||||||
// message on the given `sender`, even if the listener is called after rasterization
|
/// message on the given `sender`, even if the listener is called after rasterization
|
||||||
// at has already completed.
|
/// at has already completed.
|
||||||
fn add_rasterization_complete_listener(
|
fn add_rasterization_complete_listener(
|
||||||
&self,
|
&self,
|
||||||
pipeline_id: PipelineId,
|
pipeline_id: PipelineId,
|
||||||
image_id: VectorImageId,
|
image_id: VectorImageId,
|
||||||
size: DeviceIntSize,
|
size: DeviceIntSize,
|
||||||
sender: IpcSender<ImageCacheMessage>,
|
sender: IpcSender<ImageCacheResponseMessage>,
|
||||||
);
|
);
|
||||||
|
|
||||||
/// 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,
|
||||||
|
|
|
@ -154,8 +154,9 @@ pub struct PendingImage {
|
||||||
pub origin: ImmutableOrigin,
|
pub origin: ImmutableOrigin,
|
||||||
}
|
}
|
||||||
|
|
||||||
// A vector image that is fully loaded (i.e has a parsed SVG tree) but not yet
|
/// A data structure to tarck vector image that are fully loaded (i.e has a parsed SVG
|
||||||
// rasterized to the size needed by layout.
|
/// tree) but not yet rasterized to the size needed by layout. The rasterization is
|
||||||
|
/// happening in the image cache.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct PendingRasterizationImage {
|
pub struct PendingRasterizationImage {
|
||||||
pub node: UntrustedNodeAddress,
|
pub node: UntrustedNodeAddress,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue