Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement document load tracking. #3714

Closed
wants to merge 4 commits into from
Closed
Changes from 1 commit
Commits
File filter...
Filter file types
Jump to…
Jump to file
Failed to load files.

Always

Just for now

Prev

Make image loads block document load.

  • Loading branch information
jdm committed Jan 11, 2015
commit 2f5b4cf7c723b259e3cacc14c7bbf420f8be8aab
@@ -4,8 +4,9 @@

use image::base::{Image, load_from_memory};
use resource_task;
use resource_task::{LoadData, ResourceTask};
use resource_task::{LoadData, ResourceTask, PendingAsyncLoad};
use resource_task::ProgressMsg::{Payload, Done};
use servo_msg::constellation_msg::PipelineId;

use servo_util::task::spawn_named;
use servo_util::taskpool::TaskPool;
@@ -17,10 +18,31 @@ use std::sync::{Arc, Mutex};
use serialize::{Encoder, Encodable};
use url::Url;

pub struct ImageCacheChannel {
task: ImageCacheTask,
pipeline: PipelineId,
notifier: Sender<ImageNotification>,
}

impl ImageCacheChannel {
pub fn new(task: ImageCacheTask, pipeline: PipelineId, notifier: Sender<ImageNotification>)
-> ImageCacheChannel {
ImageCacheChannel {
task: task,
pipeline: pipeline,
notifier: notifier,
}
}
pub fn load(&self, load: PendingAsyncLoad) {
self.task.send(Msg::Prefetch(load.url().clone(),
Some((self.notifier.clone(), self.pipeline))));
}
}

pub enum Msg {
/// Tell the cache that we may need a particular image soon. Must be posted
/// before Decode
Prefetch(Url),
Prefetch(Url, Option<(Sender<ImageNotification>, PipelineId)>),

/// Tell the cache to decode an image. Must be posted before GetImage/WaitForImage
Decode(Url),
@@ -162,22 +184,53 @@ enum AfterPrefetch {
DoNotDecode
}

pub enum ImageNotification {
ImageLoadComplete(PipelineId, Url)
}

impl ImageCache {
pub fn run(&mut self) {
let mut store_chan: Option<Sender<()>> = None;
let mut store_prefetched_chan: Option<Sender<()>> = None;
let mut pending_clients: HashMap<Url, Vec<(Sender<ImageNotification>, PipelineId)>> = HashMap::new();

loop {
let msg = self.port.recv();

match msg {
Msg::Prefetch(url) => self.prefetch(url),
Msg::Prefetch(url, notifier) => {
let pending_request = self.prefetch(url.clone());
notifier.map(|(notifier, pipeline)| {
if pending_request {
let new_client = (notifier, pipeline);
match pending_clients.entry(url.clone()) {
Occupied(mut clients) => {
clients.get_mut().push(new_client);
}
Vacant(entry) => {
entry.set(vec!(new_client));
}
}
} else {
notifier.send(ImageNotification::ImageLoadComplete(pipeline,
url.clone()));
}
});
}
Msg::StorePrefetchedImageData(url, data) => {
store_prefetched_chan.map(|chan| {
chan.send(());
});
store_prefetched_chan = None;

pending_clients.get(&url).map(|clients| {
for &(ref chan, ref pipeline) in clients.iter() {
chan.send(ImageNotification::ImageLoadComplete(pipeline.clone(),
url.clone()));
}
});
pending_clients.remove(&url);

self.store_prefetched_image_data(url, data);
}
Msg::Decode(url) => self.decode(url),
@@ -241,7 +294,8 @@ impl ImageCache {
self.state_map.insert(url, state);
}

fn prefetch(&mut self, url: Url) {
// returns true if a network request is in progress, false otherwise
fn prefetch(&mut self, url: Url) -> bool {
match self.get_state(&url) {
ImageState::Init => {
let to_cache = self.chan.clone();
@@ -258,11 +312,15 @@ impl ImageCache {
});

self.set_state(url, ImageState::Prefetching(AfterPrefetch::DoNotDecode));
true
}

ImageState::Prefetching(..) | ImageState::Prefetched(..) |
ImageState::Decoding | ImageState::Decoded(..) | ImageState::Failed => {
ImageState::Prefetching(..) => true,

ImageState::Prefetched(..) | ImageState::Decoding | ImageState::Decoded(..) |
ImageState::Failed => {
// We've already begun working on this image
false
}
}
}
@@ -15,6 +15,7 @@ extern crate png;
#[phase(plugin, link)]
extern crate log;
extern crate serialize;
extern crate "msg" as servo_msg;
extern crate "util" as servo_util;
extern crate stb_image;
extern crate time;
@@ -64,7 +64,7 @@ impl<NodeAddress: Send> LocalImageCache<NodeAddress> {
state.prefetched = true;
}

self.image_cache_task.send(Msg::Prefetch((*url).clone()));
self.image_cache_task.send(Msg::Prefetch((*url).clone(), None));
}

pub fn decode(&mut self, url: &Url) {
@@ -45,11 +45,11 @@ use js::rust::Cx;
use layout_interface::{LayoutRPC, LayoutChan};
use libc;
use msg::constellation_msg::{PipelineId, SubpageId, WindowSizeData};
use net::image_cache_task::ImageCacheTask;
use script_traits::ScriptControlChan;
use script_traits::UntrustedNodeAddress;
use servo_msg::compositor_msg::ScriptListener;
use servo_msg::constellation_msg::ConstellationChan;
use servo_net::image_cache_task::ImageCacheChannel;
use servo_util::smallvec::{SmallVec1, SmallVec};
use servo_util::str::{LengthOrPercentageOrAuto};
use std::cell::{Cell, RefCell};
@@ -203,7 +203,7 @@ no_jsmanaged_fields!(int, i8, i16, i32, i64)
no_jsmanaged_fields!(Sender<T>)
no_jsmanaged_fields!(Receiver<T>)
no_jsmanaged_fields!(Rect<T>)
no_jsmanaged_fields!(ImageCacheTask, ScriptControlChan)
no_jsmanaged_fields!(ImageCacheChannel, ScriptControlChan)
no_jsmanaged_fields!(Atom, Namespace, Timer)
no_jsmanaged_fields!(Trusted<T>)
no_jsmanaged_fields!(PropertyDeclarationBlock)
@@ -2,6 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use document_loader::LoadType;
use dom::attr::Attr;
use dom::attr::{AttrHelpers, AttrValue};
use dom::bindings::cell::DOMRefCell;
@@ -17,7 +18,6 @@ use dom::element::ElementTypeId;
use dom::htmlelement::{HTMLElement, HTMLElementTypeId};
use dom::node::{Node, NodeTypeId, NodeHelpers, NodeDamage, window_from_node};
use dom::virtualmethods::VirtualMethods;
use servo_net::image_cache_task;
use servo_util::geometry::to_px;
use servo_util::str::DOMString;
use string_cache::Atom;
@@ -47,8 +47,6 @@ impl<'a> PrivateHTMLImageElementHelpers for JSRef<'a, HTMLImageElement> {
let node: JSRef<Node> = NodeCast::from_ref(self);
let document = node.owner_doc().root();
let window = document.r().window().root();
let window = window.r();
let image_cache = window.image_cache_task();
match value {
None => {
*self.image.borrow_mut() = None;
@@ -61,7 +59,8 @@ impl<'a> PrivateHTMLImageElementHelpers for JSRef<'a, HTMLImageElement> {

// inform the image cache to load this, but don't store a
// handle.
image_cache.send(image_cache_task::Msg::Prefetch(img_url));
let load = document.prep_async_load(LoadType::Image(img_url));
window.r().image_cache_task().load(load);
}
}
}
@@ -2,6 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use document_loader::LoadType;
use dom::attr::Attr;
use dom::attr::AttrHelpers;
use dom::bindings::codegen::Bindings::AttrBinding::AttrMethods;
@@ -10,18 +11,16 @@ use dom::bindings::codegen::Bindings::HTMLObjectElementBinding::HTMLObjectElemen
use dom::bindings::codegen::InheritTypes::HTMLObjectElementDerived;
use dom::bindings::codegen::InheritTypes::{ElementCast, HTMLElementCast};
use dom::bindings::js::{JSRef, Temporary};
use dom::document::Document;
use dom::document::{Document, DocumentHelpers};
use dom::element::Element;
use dom::element::AttributeHandlers;
use dom::eventtarget::{EventTarget, EventTargetTypeId};
use dom::element::ElementTypeId;
use dom::htmlelement::{HTMLElement, HTMLElementTypeId};
use dom::node::{Node, NodeTypeId, NodeHelpers, window_from_node};
use dom::node::{Node, NodeTypeId, NodeHelpers, window_from_node, document_from_node};
use dom::validitystate::ValidityState;
use dom::virtualmethods::VirtualMethods;

use servo_net::image_cache_task;
use servo_net::image_cache_task::ImageCacheTask;
use servo_util::str::DOMString;
use string_cache::Atom;

@@ -53,14 +52,14 @@ impl HTMLObjectElement {
}

trait ProcessDataURL {
fn process_data_url(&self, image_cache: ImageCacheTask);
fn process_data_url(self);
}

impl<'a> ProcessDataURL for JSRef<'a, HTMLObjectElement> {
// Makes the local `data` member match the status of the `data` attribute and starts
/// prefetching the image. This method must be called after `data` is changed.
fn process_data_url(&self, image_cache: ImageCacheTask) {
let elem: JSRef<Element> = ElementCast::from_ref(*self);
fn process_data_url(self) {
let elem: JSRef<Element> = ElementCast::from_ref(self);

// TODO: support other values
match (elem.get_attribute(ns!(""), &atom!("type")).map(|x| x.root().r().Value()),
@@ -69,7 +68,10 @@ impl<'a> ProcessDataURL for JSRef<'a, HTMLObjectElement> {
if is_image_data(uri.as_slice()) {
let data_url = Url::parse(uri.as_slice()).unwrap();
// Issue #84
image_cache.send(image_cache_task::Msg::Prefetch(data_url));
let window = window_from_node(self).root();
let document = document_from_node(self).root();
let load = document.prep_async_load(LoadType::Image(data_url.clone()));
window.image_cache_task().load(load);
}
}
_ => { }
@@ -108,10 +110,7 @@ impl<'a> VirtualMethods for JSRef<'a, HTMLObjectElement> {
}

match attr.local_name() {
&atom!("data") => {
let window = window_from_node(*self).root();
self.process_data_url(window.r().image_cache_task().clone());
},
&atom!("data") => self.process_data_url(),
_ => ()
}
}
@@ -32,7 +32,7 @@ use timers::{IsInterval, TimerId, TimerManager, TimerCallback};

use servo_msg::compositor_msg::ScriptListener;
use servo_msg::constellation_msg::LoadData;
use servo_net::image_cache_task::ImageCacheTask;
use servo_net::image_cache_task::{ImageCacheTask, ImageCacheChannel, ImageNotification};
use servo_net::storage_task::StorageTask;
use servo_util::str::{DOMString,HTML_SPACE_CHARACTERS};

@@ -55,10 +55,11 @@ pub struct Window {
eventtarget: EventTarget,
script_chan: Box<ScriptChan+Send>,
control_chan: ScriptControlChan,
script_image_chan: Sender<ImageNotification>,
console: MutNullableJS<Console>,
location: MutNullableJS<Location>,
navigator: MutNullableJS<Navigator>,
image_cache_task: ImageCacheTask,
image_cache_task: ImageCacheChannel,
compositor: DOMRefCell<Box<ScriptListener+'static>>,
browser_context: DOMRefCell<Option<BrowserContext>>,
page: Rc<Page>,
@@ -84,7 +85,11 @@ impl Window {
&self.control_chan
}

pub fn image_cache_task<'a>(&'a self) -> &'a ImageCacheTask {
pub fn script_image_chan<'a>(&'a self) -> &'a Sender<ImageNotification> {
&self.script_image_chan
}

pub fn image_cache_task<'a>(&'a self) -> &'a ImageCacheChannel {
&self.image_cache_task
}

@@ -385,19 +390,22 @@ impl Window {
page: Rc<Page>,
script_chan: Box<ScriptChan+Send>,
control_chan: ScriptControlChan,
script_image_chan: Sender<ImageNotification>,
compositor: Box<ScriptListener+'static>,
image_cache_task: ImageCacheTask)
-> Temporary<Window> {
let id = page.id;
let win = box Window {
eventtarget: EventTarget::new_inherited(EventTargetTypeId::Window),
script_chan: script_chan,
control_chan: control_chan,
script_image_chan: script_image_chan.clone(),
console: Default::default(),
compositor: DOMRefCell::new(compositor),
page: page,
location: Default::default(),
navigator: Default::default(),
image_cache_task: image_cache_task,
image_cache_task: ImageCacheChannel::new(image_cache_task, id, script_image_chan),
browser_context: DOMRefCell::new(None),
performance: Default::default(),
navigation_start: time::get_time().sec as u64,
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.