Skip to content

Commit

Permalink
Extract layout image request into separate file. Do not block the doc…
Browse files Browse the repository at this point in the history
…ument load event.
  • Loading branch information
jdm committed Feb 22, 2017
1 parent 0d2ec85 commit b363371
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 72 deletions.
7 changes: 7 additions & 0 deletions components/script/document_loader.rs
Expand Up @@ -116,6 +116,13 @@ impl DocumentLoader {
request: RequestInit,
fetch_target: IpcSender<FetchResponseMsg>) {
self.add_blocking_load(load);
self.fetch_async_background(request, fetch_target);
}

/// Initiate a new fetch that does not block the document load event.
pub fn fetch_async_background(&mut self,
request: RequestInit,
fetch_target: IpcSender<FetchResponseMsg>) {
self.resource_threads.sender().send(CoreResourceMsg::Fetch(request, fetch_target)).unwrap();
}

Expand Down
75 changes: 3 additions & 72 deletions components/script/dom/window.rs
Expand Up @@ -6,7 +6,6 @@ use app_units::Au;
use bluetooth_traits::BluetoothRequest;
use cssparser::Parser;
use devtools_traits::{ScriptToDevtoolsControlMsg, TimelineMarker, TimelineMarkerType};
use document_loader::LoadType;
use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::DocumentBinding::{DocumentMethods, DocumentReadyState};
use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull;
Expand Down Expand Up @@ -43,7 +42,7 @@ use dom::location::Location;
use dom::mediaquerylist::{MediaQueryList, WeakMediaQueryListVec};
use dom::messageevent::MessageEvent;
use dom::navigator::Navigator;
use dom::node::{Node, from_untrusted_node_address, window_from_node, document_from_node, NodeDamage};
use dom::node::{Node, from_untrusted_node_address, window_from_node, NodeDamage};
use dom::performance::Performance;
use dom::promise::Promise;
use dom::screen::Screen;
Expand All @@ -58,14 +57,12 @@ use js::jsapi::{HandleObject, HandleValue, JSAutoCompartment, JSContext};
use js::jsapi::{JS_GC, JS_GetRuntime};
use js::jsval::UndefinedValue;
use js::rust::Runtime;
use layout_image::fetch_image_for_layout;
use msg::constellation_msg::{FrameType, PipelineId};
use net_traits::{FetchResponseMsg, NetworkError};
use net_traits::{ResourceThreads, ReferrerPolicy, FetchResponseListener, FetchMetadata};
use net_traits::{ResourceThreads, ReferrerPolicy};
use net_traits::image_cache_thread::{ImageResponder, ImageResponse};
use net_traits::image_cache_thread::{PendingImageResponse, ImageCacheThread, PendingImageId};
use net_traits::request::{Type as RequestType, RequestInit as FetchRequestInit};
use net_traits::storage_thread::StorageType;
use network_listener::{NetworkListener, PreInvoke};
use num_traits::ToPrimitive;
use open;
use profile_traits::mem::ProfilerChan as MemProfilerChan;
Expand Down Expand Up @@ -1894,69 +1891,3 @@ impl Runnable for PostMessageHandler {
message.handle());
}
}

struct LayoutImageContext {
node: Trusted<Node>,
id: PendingImageId,
url: ServoUrl,
cache: ImageCacheThread,
}

impl FetchResponseListener for LayoutImageContext {
fn process_request_body(&mut self) {}
fn process_request_eof(&mut self) {}
fn process_response(&mut self, metadata: Result<FetchMetadata, NetworkError>) {
self.cache.notify_pending_response(
self.id,
FetchResponseMsg::ProcessResponse(metadata));
}

fn process_response_chunk(&mut self, payload: Vec<u8>) {
self.cache.notify_pending_response(
self.id,
FetchResponseMsg::ProcessResponseChunk(payload));
}

fn process_response_eof(&mut self, response: Result<(), NetworkError>) {
let node = self.node.root();
let document = document_from_node(&*node);
self.cache.notify_pending_response(self.id,
FetchResponseMsg::ProcessResponseEOF(response));
document.finish_load(LoadType::Image(self.url.clone()));
}
}

impl PreInvoke for LayoutImageContext {}

fn fetch_image_for_layout(url: ServoUrl, node: &Node, id: PendingImageId, cache: ImageCacheThread) {
let context = Arc::new(Mutex::new(LayoutImageContext {
node: Trusted::new(node),
id: id,
url: url.clone(),
cache: cache,
}));

let document = document_from_node(node);
let window = window_from_node(node);

let (action_sender, action_receiver) = ipc::channel().unwrap();
let listener = NetworkListener {
context: context,
task_source: window.networking_task_source(),
wrapper: Some(window.get_runnable_wrapper()),
};
ROUTER.add_route(action_receiver.to_opaque(), box move |message| {
listener.notify_fetch(message.to().unwrap());
});

let request = FetchRequestInit {
url: url.clone(),
origin: document.url().clone(),
type_: RequestType::Image,
pipeline_id: Some(document.global().pipeline_id()),
.. FetchRequestInit::default()
};

//XXXjdm should not block load event
document.fetch_async(LoadType::Image(url), request, action_sender);
}
81 changes: 81 additions & 0 deletions components/script/layout_image.rs
@@ -0,0 +1,81 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* 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/. */

//! Infrastructure to initiate network requests for images needed by the layout
//! thread. The script thread needs to be responsible for them because there's
//! no guarantee that the responsible nodes will still exist in the future if the
//! layout thread holds on to them during asynchronous operations.

use dom::bindings::reflector::DomObject;
use dom::node::{Node, document_from_node};
use ipc_channel::ipc;
use ipc_channel::router::ROUTER;
use net_traits::{FetchResponseMsg, FetchResponseListener, FetchMetadata, NetworkError};
use net_traits::image_cache_thread::{ImageCacheThread, PendingImageId};
use net_traits::request::{Type as RequestType, RequestInit as FetchRequestInit};
use network_listener::{NetworkListener, PreInvoke};
use servo_url::ServoUrl;
use std::sync::{Arc, Mutex};

struct LayoutImageContext {
id: PendingImageId,
cache: ImageCacheThread,
}

impl FetchResponseListener for LayoutImageContext {
fn process_request_body(&mut self) {}
fn process_request_eof(&mut self) {}
fn process_response(&mut self, metadata: Result<FetchMetadata, NetworkError>) {
self.cache.notify_pending_response(
self.id,
FetchResponseMsg::ProcessResponse(metadata));
}

fn process_response_chunk(&mut self, payload: Vec<u8>) {
self.cache.notify_pending_response(
self.id,
FetchResponseMsg::ProcessResponseChunk(payload));
}

fn process_response_eof(&mut self, response: Result<(), NetworkError>) {
self.cache.notify_pending_response(self.id,
FetchResponseMsg::ProcessResponseEOF(response));
}
}

impl PreInvoke for LayoutImageContext {}

pub fn fetch_image_for_layout(url: ServoUrl,
node: &Node,
id: PendingImageId,
cache: ImageCacheThread) {
let context = Arc::new(Mutex::new(LayoutImageContext {
id: id,
cache: cache,
}));

let document = document_from_node(node);
let window = document.window();

let (action_sender, action_receiver) = ipc::channel().unwrap();
let listener = NetworkListener {
context: context,
task_source: window.networking_task_source(),
wrapper: Some(window.get_runnable_wrapper()),
};
ROUTER.add_route(action_receiver.to_opaque(), box move |message| {
listener.notify_fetch(message.to().unwrap());
});

let request = FetchRequestInit {
url: url,
origin: document.url().clone(),
type_: RequestType::Image,
pipeline_id: Some(document.global().pipeline_id()),
.. FetchRequestInit::default()
};

// Layout image loads do not delay the document load event.
document.mut_loader().fetch_async_background(request, action_sender);
}
1 change: 1 addition & 0 deletions components/script/lib.rs
Expand Up @@ -110,6 +110,7 @@ pub mod document_loader;
#[macro_use]
mod dom;
pub mod fetch;
mod layout_image;
pub mod layout_wrapper;
mod mem;
mod microtask;
Expand Down

0 comments on commit b363371

Please sign in to comment.