diff options
Diffstat (limited to 'components/script/script_thread.rs')
-rw-r--r-- | components/script/script_thread.rs | 173 |
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, |