mirror of
https://github.com/servo/servo.git
synced 2025-08-05 13:40:08 +01:00
Copy image-fetching code from Layout 2013
This commit is contained in:
parent
cbcf83fc65
commit
c8cbc57b76
6 changed files with 178 additions and 6 deletions
4
Cargo.lock
generated
4
Cargo.lock
generated
|
@ -2744,12 +2744,14 @@ dependencies = [
|
|||
"cssparser",
|
||||
"embedder_traits",
|
||||
"euclid",
|
||||
"fnv",
|
||||
"gfx",
|
||||
"gfx_traits",
|
||||
"ipc-channel",
|
||||
"libc",
|
||||
"msg",
|
||||
"net_traits",
|
||||
"parking_lot",
|
||||
"range",
|
||||
"rayon",
|
||||
"rayon_croissant",
|
||||
|
@ -2758,6 +2760,7 @@ dependencies = [
|
|||
"serde",
|
||||
"servo_arc",
|
||||
"servo_geometry",
|
||||
"servo_url",
|
||||
"style",
|
||||
"style_traits",
|
||||
"unicode-script",
|
||||
|
@ -2834,6 +2837,7 @@ dependencies = [
|
|||
"metrics",
|
||||
"msg",
|
||||
"net_traits",
|
||||
"parking_lot",
|
||||
"profile_traits",
|
||||
"range",
|
||||
"script",
|
||||
|
|
|
@ -18,12 +18,14 @@ atomic_refcell = "0.1"
|
|||
cssparser = "0.27"
|
||||
embedder_traits = {path = "../embedder_traits"}
|
||||
euclid = "0.20"
|
||||
fnv = "1.0"
|
||||
gfx = {path = "../gfx"}
|
||||
gfx_traits = {path = "../gfx_traits"}
|
||||
ipc-channel = "0.12"
|
||||
libc = "0.2"
|
||||
msg = {path = "../msg"}
|
||||
net_traits = {path = "../net_traits"}
|
||||
parking_lot = "0.9"
|
||||
range = {path = "../range"}
|
||||
rayon = "1"
|
||||
rayon_croissant = "0.2.0"
|
||||
|
@ -32,6 +34,7 @@ script_traits = {path = "../script_traits"}
|
|||
serde = "1.0"
|
||||
servo_arc = { path = "../servo_arc" }
|
||||
servo_geometry = {path = "../geometry"}
|
||||
servo_url = {path = "../url"}
|
||||
style = {path = "../style", features = ["servo", "servo-layout-2020"]}
|
||||
style_traits = {path = "../style_traits"}
|
||||
unicode-script = {version = "0.3", features = ["harfbuzz"]}
|
||||
|
|
|
@ -2,18 +2,51 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use crate::display_list::WebRenderImageInfo;
|
||||
use fnv::FnvHashMap;
|
||||
use gfx::font_cache_thread::FontCacheThread;
|
||||
use gfx::font_context::FontContext;
|
||||
use msg::constellation_msg::PipelineId;
|
||||
use net_traits::image_cache::{CanRequestImages, ImageCache, ImageState};
|
||||
use net_traits::image_cache::{ImageOrMetadataAvailable, UsePlaceholder};
|
||||
use parking_lot::RwLock;
|
||||
use script_layout_interface::{PendingImage, PendingImageState};
|
||||
use servo_url::{ImmutableOrigin, ServoUrl};
|
||||
use std::cell::RefCell;
|
||||
use std::sync::Mutex;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use style::context::SharedStyleContext;
|
||||
use style::dom::OpaqueNode;
|
||||
|
||||
pub struct LayoutContext<'a> {
|
||||
pub id: PipelineId,
|
||||
pub use_rayon: bool,
|
||||
pub origin: ImmutableOrigin,
|
||||
|
||||
/// Bits shared by the layout and style system.
|
||||
pub style_context: SharedStyleContext<'a>,
|
||||
|
||||
/// Interface to the font cache thread.
|
||||
pub font_cache_thread: Mutex<FontCacheThread>,
|
||||
|
||||
/// Reference to the script thread image cache.
|
||||
pub image_cache: Arc<dyn ImageCache>,
|
||||
|
||||
/// 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: Option<Mutex<Vec<PendingImage>>>,
|
||||
|
||||
pub webrender_image_cache:
|
||||
Arc<RwLock<FnvHashMap<(ServoUrl, UsePlaceholder), WebRenderImageInfo>>>,
|
||||
}
|
||||
|
||||
impl<'a> Drop for LayoutContext<'a> {
|
||||
fn drop(&mut self) {
|
||||
if !std::thread::panicking() {
|
||||
if let Some(ref pending_images) = self.pending_images {
|
||||
assert!(pending_images.lock().unwrap().is_empty());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> LayoutContext<'a> {
|
||||
|
@ -21,6 +54,100 @@ impl<'a> LayoutContext<'a> {
|
|||
pub fn shared_context(&self) -> &SharedStyleContext {
|
||||
&self.style_context
|
||||
}
|
||||
|
||||
pub fn get_or_request_image_or_meta(
|
||||
&self,
|
||||
node: OpaqueNode,
|
||||
url: ServoUrl,
|
||||
use_placeholder: UsePlaceholder,
|
||||
) -> Option<ImageOrMetadataAvailable> {
|
||||
//XXXjdm For cases where we do not request an image, we still need to
|
||||
// ensure the node gets another script-initiated reflow or it
|
||||
// won't be requested at all.
|
||||
let can_request = if self.pending_images.is_some() {
|
||||
CanRequestImages::Yes
|
||||
} else {
|
||||
CanRequestImages::No
|
||||
};
|
||||
|
||||
// See if the image is already available
|
||||
let result = self.image_cache.find_image_or_metadata(
|
||||
url.clone(),
|
||||
self.origin.clone(),
|
||||
None,
|
||||
use_placeholder,
|
||||
can_request,
|
||||
);
|
||||
match result {
|
||||
Ok(image_or_metadata) => Some(image_or_metadata),
|
||||
// Image failed to load, so just return nothing
|
||||
Err(ImageState::LoadError) => None,
|
||||
// Not yet requested - request image or metadata from the cache
|
||||
Err(ImageState::NotRequested(id)) => {
|
||||
let image = PendingImage {
|
||||
state: PendingImageState::Unrequested(url),
|
||||
node: node.into(),
|
||||
id: id,
|
||||
};
|
||||
self.pending_images
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.lock()
|
||||
.unwrap()
|
||||
.push(image);
|
||||
None
|
||||
},
|
||||
// Image has been requested, is still pending. Return no image for this paint loop.
|
||||
// When the image loads it will trigger a reflow and/or repaint.
|
||||
Err(ImageState::Pending(id)) => {
|
||||
//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,
|
||||
};
|
||||
pending_images.lock().unwrap().push(image);
|
||||
}
|
||||
None
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_webrender_image_for_url(
|
||||
&self,
|
||||
node: OpaqueNode,
|
||||
url: ServoUrl,
|
||||
use_placeholder: UsePlaceholder,
|
||||
) -> Option<WebRenderImageInfo> {
|
||||
if let Some(existing_webrender_image) = self
|
||||
.webrender_image_cache
|
||||
.read()
|
||||
.get(&(url.clone(), use_placeholder))
|
||||
{
|
||||
return Some((*existing_webrender_image).clone());
|
||||
}
|
||||
|
||||
match self.get_or_request_image_or_meta(node, url.clone(), use_placeholder) {
|
||||
Some(ImageOrMetadataAvailable::ImageAvailable(image, _)) => {
|
||||
let image_info = WebRenderImageInfo {
|
||||
width: image.width,
|
||||
height: image.height,
|
||||
key: image.id,
|
||||
};
|
||||
if image_info.key.is_none() {
|
||||
Some(image_info)
|
||||
} else {
|
||||
let mut webrender_image_cache = self.webrender_image_cache.write();
|
||||
webrender_image_cache.insert((url, use_placeholder), image_info);
|
||||
Some(image_info)
|
||||
}
|
||||
},
|
||||
None | Some(ImageOrMetadataAvailable::MetadataAvailable(_)) => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) type LayoutFontContext = FontContext<FontCacheThread>;
|
||||
|
|
|
@ -14,6 +14,13 @@ use style::values::computed::{BorderStyle, Length, LengthPercentage};
|
|||
use style::values::specified::ui::CursorKind;
|
||||
use webrender_api::{self as wr, units};
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct WebRenderImageInfo {
|
||||
pub width: u32,
|
||||
pub height: u32,
|
||||
pub key: Option<wr::ImageKey>,
|
||||
}
|
||||
|
||||
// `webrender_api::display_item::ItemTag` is private
|
||||
type ItemTag = (u64, u16);
|
||||
type HitInfo = Option<ItemTag>;
|
||||
|
|
|
@ -32,6 +32,7 @@ malloc_size_of = { path = "../malloc_size_of" }
|
|||
metrics = {path = "../metrics"}
|
||||
msg = {path = "../msg"}
|
||||
net_traits = {path = "../net_traits"}
|
||||
parking_lot = { version = "0.9", features = ["nightly"] }
|
||||
profile_traits = {path = "../profile_traits"}
|
||||
range = {path = "../range"}
|
||||
script = {path = "../script"}
|
||||
|
|
|
@ -35,7 +35,7 @@ use gfx_traits::{node_id_from_scroll_id, Epoch};
|
|||
use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
|
||||
use ipc_channel::router::ROUTER;
|
||||
use layout::context::LayoutContext;
|
||||
use layout::display_list::DisplayListBuilder;
|
||||
use layout::display_list::{DisplayListBuilder, WebRenderImageInfo};
|
||||
use layout::query::{
|
||||
process_content_box_request, process_content_boxes_request, LayoutRPCImpl, LayoutThreadData,
|
||||
};
|
||||
|
@ -56,7 +56,8 @@ use msg::constellation_msg::{
|
|||
};
|
||||
use msg::constellation_msg::{LayoutHangAnnotation, MonitoredComponentType, PipelineId};
|
||||
use msg::constellation_msg::{MonitoredComponentId, TopLevelBrowsingContextId};
|
||||
use net_traits::image_cache::ImageCache;
|
||||
use net_traits::image_cache::{ImageCache, UsePlaceholder};
|
||||
use parking_lot::RwLock;
|
||||
use profile_traits::mem::{self as profile_mem, Report, ReportKind, ReportsChan};
|
||||
use profile_traits::time::{self as profile_time, profile, TimerMetadata};
|
||||
use profile_traits::time::{TimerMetadataFrameType, TimerMetadataReflowType};
|
||||
|
@ -147,6 +148,9 @@ pub struct LayoutThread {
|
|||
/// The channel on which messages can be sent to the memory profiler.
|
||||
mem_profiler_chan: profile_mem::ProfilerChan,
|
||||
|
||||
/// Reference to the script thread image cache.
|
||||
image_cache: Arc<dyn ImageCache>,
|
||||
|
||||
/// Public interface to the font cache thread.
|
||||
font_cache_thread: FontCacheThread,
|
||||
|
||||
|
@ -189,6 +193,8 @@ pub struct LayoutThread {
|
|||
/// All the other elements of this struct are read-only.
|
||||
rw_data: Arc<Mutex<LayoutThreadData>>,
|
||||
|
||||
webrender_image_cache: Arc<RwLock<FnvHashMap<(ServoUrl, UsePlaceholder), WebRenderImageInfo>>>,
|
||||
|
||||
/// The executors for paint worklets.
|
||||
registered_painters: RegisteredPaintersImpl,
|
||||
|
||||
|
@ -232,7 +238,7 @@ impl LayoutThreadFactory for LayoutThread {
|
|||
background_hang_monitor_register: Box<dyn BackgroundHangMonitorRegister>,
|
||||
constellation_chan: IpcSender<ConstellationMsg>,
|
||||
script_chan: IpcSender<ConstellationControlMsg>,
|
||||
_image_cache: Arc<dyn ImageCache>,
|
||||
image_cache: Arc<dyn ImageCache>,
|
||||
font_cache_thread: FontCacheThread,
|
||||
time_profiler_chan: profile_time::ProfilerChan,
|
||||
mem_profiler_chan: profile_mem::ProfilerChan,
|
||||
|
@ -280,6 +286,7 @@ impl LayoutThreadFactory for LayoutThread {
|
|||
background_hang_monitor,
|
||||
constellation_chan,
|
||||
script_chan,
|
||||
image_cache,
|
||||
font_cache_thread,
|
||||
time_profiler_chan,
|
||||
mem_profiler_chan.clone(),
|
||||
|
@ -443,6 +450,7 @@ impl LayoutThread {
|
|||
background_hang_monitor: Box<dyn BackgroundHangMonitor>,
|
||||
constellation_chan: IpcSender<ConstellationMsg>,
|
||||
script_chan: IpcSender<ConstellationControlMsg>,
|
||||
image_cache: Arc<dyn ImageCache>,
|
||||
font_cache_thread: FontCacheThread,
|
||||
time_profiler_chan: profile_time::ProfilerChan,
|
||||
mem_profiler_chan: profile_mem::ProfilerChan,
|
||||
|
@ -489,6 +497,7 @@ impl LayoutThread {
|
|||
time_profiler_chan: time_profiler_chan,
|
||||
mem_profiler_chan: mem_profiler_chan,
|
||||
registered_painters: RegisteredPaintersImpl(Default::default()),
|
||||
image_cache,
|
||||
font_cache_thread: font_cache_thread,
|
||||
first_reflow: Cell::new(true),
|
||||
font_cache_receiver: font_cache_receiver,
|
||||
|
@ -523,6 +532,7 @@ impl LayoutThread {
|
|||
element_inner_text_response: String::new(),
|
||||
inner_window_dimensions_response: None,
|
||||
})),
|
||||
webrender_image_cache: Default::default(),
|
||||
timer: if pref!(layout.animations.test.enabled) {
|
||||
Timer::test_mode()
|
||||
} else {
|
||||
|
@ -553,6 +563,7 @@ impl LayoutThread {
|
|||
fn build_layout_context<'a>(
|
||||
&'a self,
|
||||
guards: StylesheetGuards<'a>,
|
||||
script_initiated_layout: bool,
|
||||
snapshot_map: &'a SnapshotMap,
|
||||
) -> LayoutContext<'a> {
|
||||
let thread_local_style_context_creation_data =
|
||||
|
@ -560,6 +571,7 @@ impl LayoutThread {
|
|||
|
||||
LayoutContext {
|
||||
id: self.id,
|
||||
origin: self.url.origin(),
|
||||
style_context: SharedStyleContext {
|
||||
stylist: &self.stylist,
|
||||
options: GLOBAL_STYLE_DATA.options.clone(),
|
||||
|
@ -573,7 +585,14 @@ impl LayoutThread {
|
|||
traversal_flags: TraversalFlags::empty(),
|
||||
snapshot_map: snapshot_map,
|
||||
},
|
||||
image_cache: self.image_cache.clone(),
|
||||
font_cache_thread: Mutex::new(self.font_cache_thread.clone()),
|
||||
webrender_image_cache: self.webrender_image_cache.clone(),
|
||||
pending_images: if script_initiated_layout {
|
||||
Some(Mutex::new(Vec::new()))
|
||||
} else {
|
||||
None
|
||||
},
|
||||
use_rayon: STYLE_THREAD_POOL.pool().is_some(),
|
||||
}
|
||||
}
|
||||
|
@ -1074,7 +1093,7 @@ impl LayoutThread {
|
|||
self.stylist.flush(&guards, Some(element), Some(&map));
|
||||
|
||||
// Create a layout context for use throughout the following passes.
|
||||
let mut layout_context = self.build_layout_context(guards.clone(), &map);
|
||||
let mut layout_context = self.build_layout_context(guards.clone(), true, &map);
|
||||
|
||||
let traversal = RecalcStyle::new(layout_context);
|
||||
let token = {
|
||||
|
@ -1132,7 +1151,12 @@ impl LayoutThread {
|
|||
}
|
||||
|
||||
self.first_reflow.set(false);
|
||||
self.respond_to_query_if_necessary(&data.reflow_goal, &mut *rw_data, &mut layout_context);
|
||||
self.respond_to_query_if_necessary(
|
||||
&data.reflow_goal,
|
||||
&mut *rw_data,
|
||||
&mut layout_context,
|
||||
data.result.borrow_mut().as_mut().unwrap(),
|
||||
);
|
||||
}
|
||||
|
||||
fn respond_to_query_if_necessary(
|
||||
|
@ -1140,7 +1164,13 @@ impl LayoutThread {
|
|||
reflow_goal: &ReflowGoal,
|
||||
rw_data: &mut LayoutThreadData,
|
||||
context: &mut LayoutContext,
|
||||
reflow_result: &mut ReflowComplete,
|
||||
) {
|
||||
let pending_images = match &context.pending_images {
|
||||
Some(pending) => std::mem::take(&mut *pending.lock().unwrap()),
|
||||
None => Vec::new(),
|
||||
};
|
||||
reflow_result.pending_images = pending_images;
|
||||
match *reflow_goal {
|
||||
ReflowGoal::LayoutQuery(ref querymsg, _) => match querymsg {
|
||||
&QueryMsg::ContentBoxQuery(node) => {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue