aboutsummaryrefslogtreecommitdiffstats
path: root/components/script/script_thread.rs
diff options
context:
space:
mode:
Diffstat (limited to 'components/script/script_thread.rs')
-rw-r--r--components/script/script_thread.rs173
1 files changed, 83 insertions, 90 deletions
diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs
index 1d434f591b8..135fccf58c3 100644
--- a/components/script/script_thread.rs
+++ b/components/script/script_thread.rs
@@ -59,7 +59,6 @@ use euclid::Rect;
use euclid::point::Point2D;
use hyper::header::{ContentType, HttpDate, LastModified};
use hyper::header::ReferrerPolicy as ReferrerPolicyHeader;
-use hyper::method::Method;
use hyper::mime::{Mime, SubLevel, TopLevel};
use hyper_serde::Serde;
use ipc_channel::ipc::{self, IpcSender};
@@ -90,8 +89,8 @@ use script_traits::{TouchEventType, TouchId, UntrustedNodeAddress, WindowSizeDat
use script_traits::CompositorEvent::{KeyEvent, MouseButtonEvent, MouseMoveEvent, ResizeEvent};
use script_traits::CompositorEvent::{TouchEvent, TouchpadPressureEvent};
use script_traits::webdriver_msg::WebDriverScriptCommand;
+use serviceworkerjob::{Job, JobQueue, AsyncJobHandler, FinishJobHandler, InvokeType, SettleType};
use servo_url::ServoUrl;
-use std::borrow::ToOwned;
use std::cell::Cell;
use std::collections::{hash_map, HashMap, HashSet};
use std::option::Option;
@@ -399,6 +398,8 @@ pub struct ScriptThread {
incomplete_loads: DOMRefCell<Vec<InProgressLoad>>,
/// A map to store service worker registrations for a given origin
registration_map: DOMRefCell<HashMap<ServoUrl, JS<ServiceWorkerRegistration>>>,
+ /// A job queue for Service Workers keyed by their scope url
+ job_queue_map: Rc<JobQueue>,
/// A handle to the image cache thread.
image_cache_thread: ImageCacheThread,
/// A handle to the resource thread. This is an `Arc` to avoid running out of file descriptors if
@@ -517,8 +518,8 @@ impl ScriptThreadFactory for ScriptThread {
thread::spawn_named(format!("ScriptThread {:?}", state.id),
move || {
thread_state::initialize(thread_state::SCRIPT);
- PipelineId::install(state.id);
PipelineNamespace::install(state.pipeline_namespace_id);
+ FrameId::install(state.top_level_frame_id);
let roots = RootCollection::new();
let _stack_roots_tls = StackRootTLS::new(&roots);
let id = state.id;
@@ -563,11 +564,12 @@ impl ScriptThread {
})
}
- // stores a service worker registration
- pub fn set_registration(scope_url: ServoUrl, registration:&ServiceWorkerRegistration, pipeline_id: PipelineId) {
+ #[allow(unrooted_must_root)]
+ pub fn schedule_job(job: Job, global: &GlobalScope) {
SCRIPT_THREAD_ROOT.with(|root| {
let script_thread = unsafe { &*root.get().unwrap() };
- script_thread.handle_serviceworker_registration(scope_url, registration, pipeline_id);
+ let job_queue = &*script_thread.job_queue_map;
+ job_queue.schedule_job(job, global, &script_thread);
});
}
@@ -640,6 +642,7 @@ impl ScriptThread {
documents: DOMRefCell::new(Documents::new()),
incomplete_loads: DOMRefCell::new(vec!()),
registration_map: DOMRefCell::new(HashMap::new()),
+ job_queue_map: Rc::new(JobQueue::new()),
image_cache_thread: state.image_cache_thread,
image_cache_channel: ImageCacheChan(ipc_image_cache_channel),
@@ -1170,11 +1173,11 @@ impl ScriptThread {
fn handle_new_layout(&self, new_layout_info: NewLayoutInfo) {
let NewLayoutInfo {
- parent_pipeline_id,
+ parent_info,
new_pipeline_id,
frame_id,
- frame_type,
load_data,
+ window_size,
pipeline_port,
layout_to_constellation_chan,
content_process_shutdown_chan,
@@ -1184,7 +1187,7 @@ impl ScriptThread {
let layout_pair = channel();
let layout_chan = layout_pair.0.clone();
- let layout_creation_info = NewLayoutThreadInfo {
+ let msg = message::Msg::CreateLayoutThread(NewLayoutThreadInfo {
id: new_pipeline_id,
url: load_data.url.clone(),
is_parent: false,
@@ -1195,19 +1198,18 @@ impl ScriptThread {
image_cache_thread: self.image_cache_thread.clone(),
content_process_shutdown_chan: content_process_shutdown_chan,
layout_threads: layout_threads,
- };
-
- let parent_window = self.documents.borrow().find_window(parent_pipeline_id)
- .expect("ScriptThread: received a layout for a parent pipeline not in this script thread. This is a bug.");
+ });
- // Tell layout to actually spawn the thread.
- parent_window.layout_chan()
- .send(message::Msg::CreateLayoutThread(layout_creation_info))
- .unwrap();
+ // Pick a layout thread, any layout thread
+ match self.documents.borrow().iter().next() {
+ None => panic!("Layout attached to empty script thread."),
+ // Tell the layout thread factory to actually spawn the thread.
+ Some((_, document)) => document.window().layout_chan().send(msg).unwrap(),
+ };
// Kick off the fetch for the new resource.
- let new_load = InProgressLoad::new(new_pipeline_id, frame_id, Some((parent_pipeline_id, frame_type)),
- layout_chan, parent_window.window_size(),
+ let new_load = InProgressLoad::new(new_pipeline_id, frame_id, parent_info,
+ layout_chan, window_size,
load_data.url.clone());
self.start_page_load(new_load, load_data);
}
@@ -1231,20 +1233,8 @@ impl ScriptThread {
self.dom_manipulation_task_source.queue(handler, doc.window().upcast()).unwrap();
if let Some(fragment) = doc.url().fragment() {
- self.check_and_scroll_fragment(fragment, pipeline, &doc);
- }
- }
-
- fn check_and_scroll_fragment(&self, fragment: &str, pipeline_id: PipelineId, doc: &Document) {
- match doc.find_fragment_node(fragment) {
- Some(ref node) => {
- doc.set_target_element(Some(&node));
- self.scroll_fragment_point(pipeline_id, &node);
- }
- None => {
- doc.set_target_element(None);
- }
- }
+ doc.check_and_scroll_fragment(fragment);
+ };
}
fn collect_reports(&self, reports_chan: ReportsChan) {
@@ -1253,7 +1243,7 @@ impl ScriptThread {
let mut reports = vec![];
for (_, document) in self.documents.borrow().iter() {
- let current_url = document.url().as_str();
+ let current_url = document.url();
for child in document.upcast::<Node>().traverse_preorder() {
dom_tree_size += heap_size_of_self_and_children(&*child);
@@ -1263,10 +1253,10 @@ impl ScriptThread {
if reports.len() > 0 {
path_seg.push_str(", ");
}
- path_seg.push_str(current_url);
+ path_seg.push_str(current_url.as_str());
reports.push(Report {
- path: path![format!("url({})", current_url), "dom-tree"],
+ path: path![format!("url({})", current_url.as_str()), "dom-tree"],
kind: ReportKind::ExplicitJemallocHeapSize,
size: dom_tree_size,
});
@@ -1448,33 +1438,84 @@ impl ScriptThread {
}
}
- fn handle_serviceworker_registration(&self,
- scope: ServoUrl,
+ pub fn handle_get_registration(&self, scope_url: &ServoUrl) -> Option<Root<ServiceWorkerRegistration>> {
+ let maybe_registration_ref = self.registration_map.borrow();
+ maybe_registration_ref.get(scope_url).map(|x| Root::from_ref(&**x))
+ }
+
+ pub fn handle_serviceworker_registration(&self,
+ scope: &ServoUrl,
registration: &ServiceWorkerRegistration,
pipeline_id: PipelineId) {
{
let ref mut reg_ref = *self.registration_map.borrow_mut();
// according to spec we should replace if an older registration exists for
// same scope otherwise just insert the new one
- let _ = reg_ref.remove(&scope);
+ let _ = reg_ref.remove(scope);
reg_ref.insert(scope.clone(), JS::from_ref(registration));
}
// send ScopeThings to sw-manager
let ref maybe_registration_ref = *self.registration_map.borrow();
- let maybe_registration = match maybe_registration_ref.get(&scope) {
+ let maybe_registration = match maybe_registration_ref.get(scope) {
Some(r) => r,
None => return
};
if let Some(window) = self.documents.borrow().find_window(pipeline_id) {
let script_url = maybe_registration.get_installed().get_script_url();
let scope_things = ServiceWorkerRegistration::create_scope_things(window.upcast(), script_url);
- let _ = self.constellation_chan.send(ConstellationMsg::RegisterServiceWorker(scope_things, scope));
+ let _ = self.constellation_chan.send(ConstellationMsg::RegisterServiceWorker(scope_things, scope.clone()));
} else {
warn!("Registration failed for {}", scope);
}
}
+ pub fn dispatch_job_queue(&self, job_handler: Box<AsyncJobHandler>) {
+ let scope_url = job_handler.scope_url.clone();
+ let queue_ref = self.job_queue_map.0.borrow();
+ let front_job = {
+ let job_vec = queue_ref.get(&scope_url);
+ job_vec.unwrap().first().unwrap()
+ };
+ match job_handler.invoke_type {
+ InvokeType::Run => (&*self.job_queue_map).run_job(job_handler, self),
+ InvokeType::Register => self.job_queue_map.run_register(front_job, job_handler, self),
+ InvokeType::Update => self.job_queue_map.update(front_job, &*front_job.client.global(), self),
+ InvokeType::Settle(settle_type) => {
+ let promise = &front_job.promise;
+ let global = &*front_job.client.global();
+ let trusted_global = Trusted::new(global);
+ let _ac = JSAutoCompartment::new(global.get_cx(), promise.reflector().get_jsobject().get());
+ match settle_type {
+ SettleType::Resolve(reg) => promise.resolve_native(global.get_cx(), &*reg.root()),
+ SettleType::Reject(err) => promise.reject_error(global.get_cx(), err)
+ }
+ let finish_job_handler = box FinishJobHandler::new(scope_url, trusted_global);
+ self.queue_finish_job(finish_job_handler, global);
+ }
+ }
+ }
+
+ pub fn queue_serviceworker_job(&self, async_job_handler: Box<AsyncJobHandler>, global: &GlobalScope) {
+ let _ = self.dom_manipulation_task_source.queue(async_job_handler, &*global);
+ }
+
+ pub fn queue_finish_job(&self, finish_job_handler: Box<FinishJobHandler>, global: &GlobalScope) {
+ let _ = self.dom_manipulation_task_source.queue(finish_job_handler, global);
+ }
+
+ pub fn invoke_finish_job(&self, finish_job_handler: Box<FinishJobHandler>) {
+ let job_queue = &*self.job_queue_map;
+ let global = &*finish_job_handler.global.root();
+ let scope_url = (*finish_job_handler).scope_url;
+ job_queue.finish_job(scope_url, global, self);
+ }
+
+ pub fn invoke_job_update(&self, job: &Job, global: &GlobalScope) {
+ let job_queue = &*self.job_queue_map;
+ job_queue.update(job, global, self);
+ }
+
/// Handles a request for the window title.
fn handle_get_title_msg(&self, pipeline_id: PipelineId) {
let document = match self.documents.borrow().find_document(pipeline_id) {
@@ -1753,7 +1794,7 @@ impl ScriptThread {
// Start with the scheme data of the parsed URL;
// append question mark and query component, if any;
// append number sign and fragment component if any.
- let encoded = &incomplete.url.as_url().unwrap()[Position::BeforePath..];
+ let encoded = &incomplete.url[Position::BeforePath..];
// Percent-decode (8.) and UTF-8 decode (9.)
let script_source = percent_decode(encoded.as_bytes()).decode_utf8_lossy();
@@ -1826,26 +1867,6 @@ impl ScriptThread {
}
}
- fn scroll_fragment_point(&self, pipeline_id: PipelineId, element: &Element) {
- // FIXME(#8275, pcwalton): This is pretty bogus when multiple layers are involved.
- // Really what needs to happen is that this needs to go through layout to ask which
- // layer the element belongs to, and have it send the scroll message to the
- // compositor.
- let rect = element.upcast::<Node>().bounding_content_box();
-
- // In order to align with element edges, we snap to unscaled pixel boundaries, since the
- // paint thread currently does the same for drawing elements. This is important for pages
- // that require pixel perfect scroll positioning for proper display (like Acid2). Since we
- // don't have the device pixel ratio here, this might not be accurate, but should work as
- // long as the ratio is a whole number. Once #8275 is fixed this should actually take into
- // account the real device pixel ratio.
- let point = Point2D::new(rect.origin.x.to_nearest_px() as f32,
- rect.origin.y.to_nearest_px() as f32);
-
- let message = ConstellationMsg::ScrollFragmentPoint(pipeline_id, point, false);
- self.constellation_chan.send(message).unwrap();
- }
-
/// Reflows non-incrementally, rebuilding the entire layout tree in the process.
fn rebuild_and_force_reflow(&self, document: &Document, reason: ReflowReason) {
let window = window_from_node(&*document);
@@ -1987,25 +2008,6 @@ impl ScriptThread {
frame_id: Option<FrameId>,
load_data: LoadData,
replace: bool) {
- // Step 7.
- {
- let nurl = &load_data.url;
- if let Some(fragment) = nurl.fragment() {
- let document = match self.documents.borrow().find_document(parent_pipeline_id) {
- Some(document) => document,
- None => return warn!("Message sent to closed pipeline {}.", parent_pipeline_id),
- };
- let nurl = nurl.as_url().unwrap();
- if let Some(url) = document.url().as_url() {
- if &url[..Position::AfterQuery] == &nurl[..Position::AfterQuery] &&
- load_data.method == Method::Get {
- self.check_and_scroll_fragment(fragment, parent_pipeline_id, &document);
- return;
- }
- }
- }
- }
-
match frame_id {
Some(frame_id) => {
if let Some(iframe) = self.documents.borrow().find_iframe(parent_pipeline_id, frame_id) {
@@ -2032,13 +2034,6 @@ impl ScriptThread {
ReflowQueryType::NoQuery,
ReflowReason::WindowResize);
- let fragment_node = window.steal_fragment_name()
- .and_then(|name| document.find_fragment_node(&*name));
- match fragment_node {
- Some(ref node) => self.scroll_fragment_point(pipeline_id, &node),
- None => {}
- }
-
// http://dev.w3.org/csswg/cssom-view/#resizing-viewports
if size_type == WindowSizeType::Resize {
let uievent = UIEvent::new(&window,
@@ -2118,8 +2113,6 @@ impl ScriptThread {
// https://html.spec.whatwg.org/multipage/#the-end steps 3-4.
document.process_deferred_scripts();
-
- window.set_fragment_name(final_url.fragment().map(str::to_owned));
}
fn handle_css_error_reporting(&self, pipeline_id: PipelineId, filename: String,