Refactored image cache task - details below.

* Simpler image cache API for clients to use.
 * Significantly fewer threads.
   * One thread for image cache task (multiplexes commands, decoder threads and async resource requests).
   * 4 threads for decoder worker tasks.
 * Removed ReflowEvent hacks in script and layout tasks.
   * Image elements pass a Trusted<T> to image cache, which is used to dirty nodes via script task. Previous use of Untrusted addresses was unsafe.
   * Image requests such as background-image on layout / paint threads trigger repaint only rather than full reflow.
 * Add reflow batching for when multiple images load quickly.
   * Reduces the number of paints loading wikipedia from ~95 to ~35.
 * Reasonably simple to add proper prefetch support in a follow up PR.
 * Async loaded images always construct Image fragments now, instead of generic.
   * Image fragments support the image not being present.
 * Simpler implementation of synchronous image loading for reftests.
 * Removed image holder.
 * image.onload support.
 * image NaturalWidth and NaturalHeight support.
 * Updated WPT expectations.
This commit is contained in:
Glenn Watson 2015-04-20 13:34:26 +10:00
parent e278e5b9a2
commit d8aef7208e
33 changed files with 2785 additions and 1679 deletions

View file

@ -250,24 +250,6 @@ impl<'a> FlowConstructor<'a> {
node.set_flow_construction_result(result);
}
/// Builds the `ImageFragmentInfo` for the given image. This is out of line to guide inlining.
fn build_fragment_info_for_image(&mut self, node: &ThreadSafeLayoutNode, url: Option<Url>)
-> SpecificFragmentInfo {
match url {
None => SpecificFragmentInfo::Generic,
Some(url) => {
// FIXME(pcwalton): The fact that image fragments store the cache within them makes
// little sense to me.
SpecificFragmentInfo::Image(box ImageFragmentInfo::new(node,
url,
self.layout_context
.shared
.image_cache
.clone()))
}
}
}
/// Builds the fragment for the given block or subclass thereof.
fn build_fragment_for_block(&mut self, node: &ThreadSafeLayoutNode) -> Fragment {
let specific_fragment_info = match node.type_id() {
@ -277,12 +259,17 @@ impl<'a> FlowConstructor<'a> {
}
Some(NodeTypeId::Element(ElementTypeId::HTMLElement(
HTMLElementTypeId::HTMLImageElement))) => {
self.build_fragment_info_for_image(node, node.image_url())
let image_info = box ImageFragmentInfo::new(node,
node.image_url(),
&self.layout_context);
SpecificFragmentInfo::Image(image_info)
}
Some(NodeTypeId::Element(ElementTypeId::HTMLElement(
HTMLElementTypeId::HTMLObjectElement))) => {
let data = node.get_object_data();
self.build_fragment_info_for_image(node, data)
let image_info = box ImageFragmentInfo::new(node,
node.get_object_data(),
&self.layout_context);
SpecificFragmentInfo::Image(image_info)
}
Some(NodeTypeId::Element(ElementTypeId::HTMLElement(
HTMLElementTypeId::HTMLTableElement))) => {
@ -1031,8 +1018,10 @@ impl<'a> FlowConstructor<'a> {
};
let marker_fragment = match node.style().get_list().list_style_image {
Some(ref url) => {
Some(Fragment::new(node,
self.build_fragment_info_for_image(node, Some((*url).clone()))))
let image_info = box ImageFragmentInfo::new(node,
Some((*url).clone()),
&self.layout_context);
Some(Fragment::new(node, SpecificFragmentInfo::Image(image_info)))
}
None => {
match ListStyleTypeContent::from_list_style_type(node.style()

View file

@ -13,17 +13,18 @@ use gfx::display_list::OpaqueNode;
use gfx::font_cache_task::FontCacheTask;
use gfx::font_context::FontContext;
use msg::constellation_msg::ConstellationChan;
use net_traits::image::base::Image;
use net_traits::image_cache_task::{ImageCacheChan, ImageCacheTask, ImageState};
use script::layout_interface::{Animation, LayoutChan};
use script_traits::UntrustedNodeAddress;
use net_traits::local_image_cache::LocalImageCache;
use std::boxed;
use std::cell::Cell;
use std::ptr;
use std::sync::mpsc::Sender;
use std::sync::{Arc, Mutex};
use std::sync::Arc;
use std::sync::mpsc::{channel, Sender};
use style::selector_matching::Stylist;
use url::Url;
use util::geometry::Au;
use util::opts;
struct LocalLayoutContext {
font_context: FontContext,
@ -55,8 +56,11 @@ fn create_or_get_local_context(shared_layout_context: &SharedLayoutContext)
/// Layout information shared among all workers. This must be thread-safe.
pub struct SharedLayoutContext {
/// The local image cache.
pub image_cache: Arc<Mutex<LocalImageCache<UntrustedNodeAddress>>>,
/// The shared image cache task.
pub image_cache_task: ImageCacheTask,
/// A channel for the image cache to send responses to.
pub image_cache_sender: ImageCacheChan,
/// The current screen size.
pub screen_size: Size2D<Au>,
@ -139,4 +143,42 @@ impl<'a> LayoutContext<'a> {
&mut cached_context.style_sharing_candidate_cache
}
}
pub fn get_or_request_image(&self, url: Url) -> Option<Arc<Image>> {
// See if the image is already available
let result = self.shared.image_cache_task.get_image_if_available(url.clone());
match result {
Ok(image) => Some(image),
Err(state) => {
// If we are emitting an output file, then we need to block on
// image load or we risk emitting an output file missing the image.
let is_sync = opts::get().output_file.is_some();
match (state, is_sync) {
// Image failed to load, so just return nothing
(ImageState::LoadError, _) => None,
// Not loaded, test mode - load the image synchronously
(_, true) => {
let (sync_tx, sync_rx) = channel();
self.shared.image_cache_task.request_image(url,
ImageCacheChan(sync_tx),
None);
sync_rx.recv().unwrap().image
}
// Not yet requested, async mode - request image from the cache
(ImageState::NotRequested, false) => {
self.shared.image_cache_task.request_image(url,
self.shared.image_cache_sender.clone(),
None);
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.
(ImageState::Pending, false) => None,
}
}
}
}
}

View file

@ -20,7 +20,6 @@ use fragment::{ScannedTextFragmentInfo, SpecificFragmentInfo};
use inline::InlineFlow;
use list_item::ListItemFlow;
use model::{self, MaybeAuto, ToGfxMatrix};
use opaque_node::OpaqueNodeMethods;
use geom::{Matrix2D, Point2D, Rect, Size2D, SideOffsets2D};
use gfx::color;
@ -36,7 +35,6 @@ use png::{self, PixelsByColorType};
use msg::compositor_msg::ScrollPolicy;
use msg::constellation_msg::Msg as ConstellationMsg;
use msg::constellation_msg::ConstellationChan;
use net_traits::image::holder::ImageHolder;
use util::cursor::Cursor;
use util::geometry::{self, Au, ZERO_POINT, to_px, to_frac_px};
use util::logical_geometry::{LogicalPoint, LogicalRect, LogicalSize, WritingMode};
@ -398,95 +396,86 @@ impl FragmentDisplayListBuilding for Fragment {
clip: &ClippingRegion,
image_url: &Url) {
let background = style.get_background();
let mut holder = ImageHolder::new(image_url.clone(),
layout_context.shared.image_cache.clone());
let image = match holder.get_image(self.node.to_untrusted_node_address()) {
None => {
// No image data at all? Do nothing.
//
// TODO: Add some kind of placeholder background image.
debug!("(building display list) no background image :(");
return
}
Some(image) => image,
};
debug!("(building display list) building background image");
let image = layout_context.get_or_request_image(image_url.clone());
if let Some(image) = image {
debug!("(building display list) building background image");
// Use `background-size` to get the size.
let mut bounds = *absolute_bounds;
let image_size = self.compute_background_image_size(style, &bounds, &*image);
// Use `background-size` to get the size.
let mut bounds = *absolute_bounds;
let image_size = self.compute_background_image_size(style, &bounds, &*image);
// Clip.
//
// TODO: Check the bounds to see if a clip item is actually required.
let clip = clip.clone().intersect_rect(&bounds);
// Clip.
//
// TODO: Check the bounds to see if a clip item is actually required.
let clip = clip.clone().intersect_rect(&bounds);
// Use `background-attachment` to get the initial virtual origin
let (virtual_origin_x, virtual_origin_y) = match background.background_attachment {
background_attachment::T::scroll => {
(absolute_bounds.origin.x, absolute_bounds.origin.y)
}
background_attachment::T::fixed => {
(Au(0), Au(0))
}
};
// Use `background-attachment` to get the initial virtual origin
let (virtual_origin_x, virtual_origin_y) = match background.background_attachment {
background_attachment::T::scroll => {
(absolute_bounds.origin.x, absolute_bounds.origin.y)
}
background_attachment::T::fixed => {
(Au(0), Au(0))
}
};
// Use `background-position` to get the offset.
let horizontal_position = model::specified(background.background_position.horizontal,
bounds.size.width - image_size.width);
let vertical_position = model::specified(background.background_position.vertical,
bounds.size.height - image_size.height);
// Use `background-position` to get the offset.
let horizontal_position = model::specified(background.background_position.horizontal,
bounds.size.width - image_size.width);
let vertical_position = model::specified(background.background_position.vertical,
bounds.size.height - image_size.height);
let abs_x = virtual_origin_x + horizontal_position;
let abs_y = virtual_origin_y + vertical_position;
let abs_x = virtual_origin_x + horizontal_position;
let abs_y = virtual_origin_y + vertical_position;
// Adjust origin and size based on background-repeat
match background.background_repeat {
background_repeat::T::no_repeat => {
bounds.origin.x = abs_x;
bounds.origin.y = abs_y;
bounds.size.width = image_size.width;
bounds.size.height = image_size.height;
}
background_repeat::T::repeat_x => {
bounds.origin.y = abs_y;
bounds.size.height = image_size.height;
ImageFragmentInfo::tile_image(&mut bounds.origin.x,
&mut bounds.size.width,
abs_x,
image_size.width.to_nearest_px() as u32);
}
background_repeat::T::repeat_y => {
bounds.origin.x = abs_x;
bounds.size.width = image_size.width;
ImageFragmentInfo::tile_image(&mut bounds.origin.y,
&mut bounds.size.height,
abs_y,
image_size.height.to_nearest_px() as u32);
}
background_repeat::T::repeat => {
ImageFragmentInfo::tile_image(&mut bounds.origin.x,
&mut bounds.size.width,
abs_x,
image_size.width.to_nearest_px() as u32);
ImageFragmentInfo::tile_image(&mut bounds.origin.y,
&mut bounds.size.height,
abs_y,
image_size.height.to_nearest_px() as u32);
}
};
// Adjust origin and size based on background-repeat
match background.background_repeat {
background_repeat::T::no_repeat => {
bounds.origin.x = abs_x;
bounds.origin.y = abs_y;
bounds.size.width = image_size.width;
bounds.size.height = image_size.height;
}
background_repeat::T::repeat_x => {
bounds.origin.y = abs_y;
bounds.size.height = image_size.height;
ImageFragmentInfo::tile_image(&mut bounds.origin.x,
&mut bounds.size.width,
abs_x,
image_size.width.to_nearest_px() as u32);
}
background_repeat::T::repeat_y => {
bounds.origin.x = abs_x;
bounds.size.width = image_size.width;
ImageFragmentInfo::tile_image(&mut bounds.origin.y,
&mut bounds.size.height,
abs_y,
image_size.height.to_nearest_px() as u32);
}
background_repeat::T::repeat => {
ImageFragmentInfo::tile_image(&mut bounds.origin.x,
&mut bounds.size.width,
abs_x,
image_size.width.to_nearest_px() as u32);
ImageFragmentInfo::tile_image(&mut bounds.origin.y,
&mut bounds.size.height,
abs_y,
image_size.height.to_nearest_px() as u32);
}
};
// Create the image display item.
display_list.push(DisplayItem::ImageClass(box ImageDisplayItem {
base: BaseDisplayItem::new(bounds,
DisplayItemMetadata::new(self.node,
style,
Cursor::DefaultCursor),
clip),
image: image.clone(),
stretch_size: Size2D(image_size.width, image_size.height),
image_rendering: style.get_effects().image_rendering.clone(),
}), level);
// Create the image display item.
display_list.push(DisplayItem::ImageClass(box ImageDisplayItem {
base: BaseDisplayItem::new(bounds,
DisplayItemMetadata::new(self.node,
style,
Cursor::DefaultCursor),
clip),
image: image.clone(),
stretch_size: Size2D(image_size.width, image_size.height),
image_rendering: style.get_effects().image_rendering.clone(),
}), level);
}
}
fn build_display_list_for_background_linear_gradient(&self,
@ -973,11 +962,8 @@ impl FragmentDisplayListBuilding for Fragment {
}
}
SpecificFragmentInfo::Image(ref mut image_fragment) => {
let image_ref = &mut image_fragment.image;
if let Some(image) = image_ref.get_image(self.node.to_untrusted_node_address()) {
debug!("(building display list) building image fragment");
// Place the image into the display list.
// Place the image into the display list.
if let Some(ref image) = image_fragment.image {
display_list.content.push_back(DisplayItem::ImageClass(box ImageDisplayItem {
base: BaseDisplayItem::new(stacking_relative_content_box,
DisplayItemMetadata::new(self.node,
@ -988,11 +974,6 @@ impl FragmentDisplayListBuilding for Fragment {
stretch_size: stacking_relative_content_box.size,
image_rendering: self.style.get_effects().image_rendering.clone(),
}));
} else {
// No image data at all? Do nothing.
//
// TODO: Add some kind of placeholder image.
debug!("(building display list) no image :(");
}
}
SpecificFragmentInfo::Canvas(ref canvas_fragment_info) => {

View file

@ -28,8 +28,7 @@ use gfx::display_list::{BLUR_INFLATION_FACTOR, OpaqueNode};
use gfx::text::glyph::CharIndex;
use gfx::text::text_run::{TextRun, TextRunSlice};
use msg::constellation_msg::{ConstellationChan, Msg, PipelineId, SubpageId};
use net_traits::image::holder::ImageHolder;
use net_traits::local_image_cache::LocalImageCache;
use net_traits::image::base::Image;
use rustc_serialize::{Encodable, Encoder};
use script_traits::UntrustedNodeAddress;
use std::borrow::ToOwned;
@ -297,7 +296,7 @@ impl CanvasFragmentInfo {
pub struct ImageFragmentInfo {
/// The image held within this fragment.
pub replaced_image_fragment_info: ReplacedImageFragmentInfo,
pub image: ImageHolder<UntrustedNodeAddress>,
pub image: Option<Arc<Image>>,
}
impl ImageFragmentInfo {
@ -306,8 +305,8 @@ impl ImageFragmentInfo {
/// FIXME(pcwalton): The fact that image fragments store the cache in the fragment makes little
/// sense to me.
pub fn new(node: &ThreadSafeLayoutNode,
image_url: Url,
local_image_cache: Arc<Mutex<LocalImageCache<UntrustedNodeAddress>>>)
url: Option<Url>,
layout_context: &LayoutContext)
-> ImageFragmentInfo {
fn convert_length(node: &ThreadSafeLayoutNode, name: &Atom) -> Option<Au> {
let element = node.as_element();
@ -316,32 +315,42 @@ impl ImageFragmentInfo {
.map(|pixels| Au::from_px(pixels))
}
let image = url.and_then(|url| layout_context.get_or_request_image(url));
ImageFragmentInfo {
replaced_image_fragment_info: ReplacedImageFragmentInfo::new(node,
convert_length(node, &atom!("width")),
convert_length(node, &atom!("height"))),
image: ImageHolder::new(image_url, local_image_cache)
image: image,
}
}
/// Returns the original inline-size of the image.
pub fn image_inline_size(&mut self) -> Au {
let size = self.image.get_size(self.replaced_image_fragment_info.for_node).unwrap_or(Size2D::zero());
Au::from_px(if self.replaced_image_fragment_info.writing_mode_is_vertical {
size.height
} else {
size.width
} as isize)
match self.image {
Some(ref image) => {
Au::from_px(if self.replaced_image_fragment_info.writing_mode_is_vertical {
image.height
} else {
image.width
} as isize)
}
None => Au(0)
}
}
/// Returns the original block-size of the image.
pub fn image_block_size(&mut self) -> Au {
let size = self.image.get_size(self.replaced_image_fragment_info.for_node).unwrap_or(Size2D::zero());
Au::from_px(if self.replaced_image_fragment_info.writing_mode_is_vertical {
size.width
} else {
size.height
} as isize)
match self.image {
Some(ref image) => {
Au::from_px(if self.replaced_image_fragment_info.writing_mode_is_vertical {
image.width
} else {
image.height
} as isize)
}
None => Au(0)
}
}
/// Tile an image

View file

@ -46,16 +46,15 @@ use profile::mem::{self, Report, ReportsChan};
use profile::time::{self, ProfilerMetadata, profile};
use profile::time::{TimerMetadataFrameType, TimerMetadataReflowType};
use net_traits::{load_bytes_iter, ResourceTask};
use net_traits::image_cache_task::{ImageCacheTask, ImageResponseMsg};
use net_traits::local_image_cache::{ImageResponder, LocalImageCache};
use net_traits::image_cache_task::{ImageCacheTask, ImageCacheResult, ImageCacheChan};
use script::dom::bindings::js::LayoutJS;
use script::dom::node::{LayoutData, Node};
use script::layout_interface::{Animation, ContentBoxResponse, ContentBoxesResponse};
use script::layout_interface::{HitTestResponse, LayoutChan, LayoutRPC};
use script::layout_interface::{MouseOverResponse, Msg, Reflow, ReflowGoal, ReflowQueryType};
use script::layout_interface::{ScriptLayoutChan, ScriptReflow, TrustedNodeAddress};
use script_traits::{ConstellationControlMsg, CompositorEvent, OpaqueScriptLayoutChannel};
use script_traits::{ScriptControlChan, UntrustedNodeAddress};
use script_traits::{ConstellationControlMsg, OpaqueScriptLayoutChannel};
use script_traits::ScriptControlChan;
use std::borrow::ToOwned;
use std::cell::Cell;
use std::mem::transmute;
@ -74,7 +73,7 @@ use util::geometry::{Au, MAX_RECT};
use util::logical_geometry::LogicalPoint;
use util::mem::HeapSizeOf;
use util::opts;
use util::smallvec::{SmallVec, SmallVec1, VecLike};
use util::smallvec::SmallVec;
use util::task::spawn_named_with_send_on_failure;
use util::task_state;
use util::workqueue::WorkQueue;
@ -86,8 +85,8 @@ pub struct LayoutTaskData {
/// The root of the flow tree.
pub root_flow: Option<FlowRef>,
/// The local image cache.
pub local_image_cache: Arc<Mutex<LocalImageCache<UntrustedNodeAddress>>>,
/// The image cache.
pub image_cache_task: ImageCacheTask,
/// The channel on which messages can be sent to the constellation.
pub constellation_chan: ConstellationChan,
@ -145,6 +144,12 @@ pub struct LayoutTask {
/// The port on which we receive messages from the constellation
pub pipeline_port: Receiver<LayoutControlMsg>,
/// The port on which we receive messages from the image cache
image_cache_receiver: Receiver<ImageCacheResult>,
/// The channel on which the image cache can send messages to ourself.
image_cache_sender: ImageCacheChan,
/// The channel on which we or others can send messages to ourselves.
pub chan: LayoutChan,
@ -169,9 +174,6 @@ pub struct LayoutTask {
/// The channel on which messages can be sent to the resource task.
pub resource_task: ResourceTask,
/// The channel on which messages can be sent to the image cache.
pub image_cache_task: ImageCacheTask,
/// Public interface to the font cache task.
pub font_cache_task: FontCacheTask,
@ -185,26 +187,6 @@ pub struct LayoutTask {
pub rw_data: Arc<Mutex<LayoutTaskData>>,
}
struct LayoutImageResponder {
id: PipelineId,
script_chan: ScriptControlChan,
}
impl ImageResponder<UntrustedNodeAddress> for LayoutImageResponder {
fn respond(&self) -> Box<Fn(ImageResponseMsg, UntrustedNodeAddress)+Send> {
let id = self.id.clone();
let script_chan = self.script_chan.clone();
box move |_, node_address| {
let ScriptControlChan(ref chan) = script_chan;
debug!("Dirtying {:p}", node_address.0);
let mut nodes = SmallVec1::new();
nodes.vec_push(node_address);
drop(chan.send(ConstellationControlMsg::SendEvent(
id, CompositorEvent::ReflowEvent(nodes))))
}
}
}
impl LayoutTaskFactory for LayoutTask {
/// Spawns a new layout task.
fn create(_phantom: Option<&mut LayoutTask>,
@ -218,7 +200,7 @@ impl LayoutTaskFactory for LayoutTask {
script_chan: ScriptControlChan,
paint_chan: PaintChan,
resource_task: ResourceTask,
img_cache_task: ImageCacheTask,
image_cache_task: ImageCacheTask,
font_cache_task: FontCacheTask,
time_profiler_chan: time::ProfilerChan,
memory_profiler_chan: mem::ProfilerChan,
@ -237,7 +219,7 @@ impl LayoutTaskFactory for LayoutTask {
script_chan,
paint_chan,
resource_task,
img_cache_task,
image_cache_task,
font_cache_task,
time_profiler_chan,
memory_profiler_chan);
@ -295,8 +277,6 @@ impl LayoutTask {
time_profiler_chan: time::ProfilerChan,
mem_profiler_chan: mem::ProfilerChan)
-> LayoutTask {
let local_image_cache =
Arc::new(Mutex::new(LocalImageCache::new(image_cache_task.clone())));
let screen_size = Size2D(Au(0), Au(0));
let device = Device::new(
MediaType::Screen,
@ -317,6 +297,7 @@ impl LayoutTask {
// Create the channel on which new animations can be sent.
let (new_animations_sender, new_animations_receiver) = channel();
let (image_cache_sender, image_cache_receiver) = channel();
LayoutTask {
id: id,
@ -332,13 +313,14 @@ impl LayoutTask {
mem_profiler_chan: mem_profiler_chan,
reporter_name: reporter_name,
resource_task: resource_task,
image_cache_task: image_cache_task.clone(),
font_cache_task: font_cache_task,
first_reflow: Cell::new(true),
image_cache_receiver: image_cache_receiver,
image_cache_sender: ImageCacheChan(image_cache_sender),
rw_data: Arc::new(Mutex::new(
LayoutTaskData {
root_flow: None,
local_image_cache: local_image_cache,
image_cache_task: image_cache_task,
constellation_chan: constellation_chan,
screen_size: screen_size,
stacking_context: None,
@ -371,7 +353,8 @@ impl LayoutTask {
url: &Url)
-> SharedLayoutContext {
SharedLayoutContext {
image_cache: rw_data.local_image_cache.clone(),
image_cache_task: rw_data.image_cache_task.clone(),
image_cache_sender: self.image_cache_sender.clone(),
screen_size: rw_data.screen_size.clone(),
screen_size_changed: screen_size_changed,
constellation_chan: rw_data.constellation_chan.clone(),
@ -393,21 +376,26 @@ impl LayoutTask {
enum PortToRead {
Pipeline,
Script,
ImageCache,
}
let port_to_read = {
let sel = Select::new();
let mut port1 = sel.handle(&self.port);
let mut port2 = sel.handle(&self.pipeline_port);
let mut port3 = sel.handle(&self.image_cache_receiver);
unsafe {
port1.add();
port2.add();
port3.add();
}
let ret = sel.wait();
if ret == port1.id() {
PortToRead::Script
} else if ret == port2.id() {
PortToRead::Pipeline
} else if ret == port3.id() {
PortToRead::ImageCache
} else {
panic!("invalid select result");
}
@ -424,11 +412,15 @@ impl LayoutTask {
possibly_locked_rw_data)
}
}
},
}
PortToRead::Script => {
let msg = self.port.recv().unwrap();
self.handle_request_helper(msg, possibly_locked_rw_data)
}
PortToRead::ImageCache => {
let _ = self.image_cache_receiver.recv().unwrap();
self.repaint(possibly_locked_rw_data)
}
}
}
@ -458,6 +450,33 @@ impl LayoutTask {
}
}
/// Repaint the scene, without performing style matching. This is typically
/// used when an image arrives asynchronously and triggers a relayout and
/// repaint.
/// TODO: In the future we could detect if the image size hasn't changed
/// since last time and avoid performing a complete layout pass.
fn repaint<'a>(&'a self,
possibly_locked_rw_data: &mut Option<MutexGuard<'a, LayoutTaskData>>) -> bool {
let mut rw_data = self.lock_rw_data(possibly_locked_rw_data);
let reflow_info = Reflow {
goal: ReflowGoal::ForDisplay,
page_clip_rect: MAX_RECT,
};
let mut layout_context = self.build_shared_layout_context(&*rw_data,
false,
None,
&self.url);
self.perform_post_style_recalc_layout_passes(&reflow_info,
&mut *rw_data,
&mut layout_context);
true
}
/// Receives and dispatches messages from other tasks.
fn handle_request_helper<'a>(&'a self,
request: Msg,
@ -823,12 +842,6 @@ impl LayoutTask {
let mut rw_data = self.lock_rw_data(possibly_locked_rw_data);
{
// Reset the image cache.
let mut local_image_cache = rw_data.local_image_cache.lock().unwrap();
local_image_cache.next_round(self.make_on_image_available_cb());
}
// TODO: Calculate the "actual viewport":
// http://www.w3.org/TR/css-device-adapt/#actual-viewport
let viewport_size = data.window_size.initial_viewport;
@ -1039,24 +1052,6 @@ impl LayoutTask {
}
}
/// When images can't be loaded in time to display they trigger
/// this callback in some task somewhere. This will send a message
/// to the script task, and ultimately cause the image to be
/// re-requested. We probably don't need to go all the way back to
/// the script task for this.
///
/// FIXME(pcwalton): Rewrite all of this.
fn make_on_image_available_cb(&self) -> Box<ImageResponder<UntrustedNodeAddress>+Send> {
// This has a crazy signature because the image cache needs to
// make multiple copies of the callback, and the dom event
// channel is not a copyable type, so this is actually a
// little factory to produce callbacks
box LayoutImageResponder {
id: self.id.clone(),
script_chan: self.script_chan.clone(),
} as Box<ImageResponder<UntrustedNodeAddress>+Send>
}
/// Handles a message to destroy layout data. Layout data must be destroyed on *this* task
/// because the struct type is transmuted to a different type on the script side.
unsafe fn handle_reap_layout_data(&self, layout_data: LayoutData) {

View file

@ -116,7 +116,7 @@ pub trait TLayoutNode {
fn image_url(&self) -> Option<Url> {
unsafe {
match HTMLImageElementCast::to_layout_js(self.get_jsmanaged()) {
Some(elem) => elem.image().as_ref().map(|url| (*url).clone()),
Some(elem) => elem.image_url().as_ref().map(|url| (*url).clone()),
None => panic!("not an image!")
}
}