diff options
Diffstat (limited to 'components/script')
-rw-r--r-- | components/script/Cargo.toml | 1 | ||||
-rw-r--r-- | components/script/blob_url_store.rs | 59 | ||||
-rw-r--r-- | components/script/dom/canvasrenderingcontext2d.rs | 37 | ||||
-rw-r--r-- | components/script/dom/htmlformelement.rs | 7 | ||||
-rw-r--r-- | components/script/dom/htmliframeelement.rs | 54 | ||||
-rw-r--r-- | components/script/dom/htmlinputelement.rs | 17 | ||||
-rw-r--r-- | components/script/dom/nodelist.rs | 6 | ||||
-rw-r--r-- | components/script/dom/url.rs | 91 | ||||
-rw-r--r-- | components/script/dom/webidls/BrowserElement.webidl | 22 | ||||
-rw-r--r-- | components/script/dom/webidls/HTMLFormElement.webidl | 2 | ||||
-rw-r--r-- | components/script/dom/webidls/URL.webidl | 5 | ||||
-rw-r--r-- | components/script/dom/window.rs | 13 | ||||
-rw-r--r-- | components/script/dom/worker.rs | 5 | ||||
-rw-r--r-- | components/script/dom/workerglobalscope.rs | 5 | ||||
-rw-r--r-- | components/script/dom/xmlhttprequest.rs | 6 | ||||
-rw-r--r-- | components/script/lib.rs | 2 | ||||
-rw-r--r-- | components/script/script_thread.rs | 60 | ||||
-rw-r--r-- | components/script/timers.rs | 38 |
18 files changed, 307 insertions, 123 deletions
diff --git a/components/script/Cargo.toml b/components/script/Cargo.toml index 95f1044fd36..9aa39fc12af 100644 --- a/components/script/Cargo.toml +++ b/components/script/Cargo.toml @@ -20,7 +20,6 @@ tinyfiledialogs = {git = "https://github.com/jdm/tinyfiledialogs"} angle = {git = "https://github.com/servo/angle", branch = "servo"} app_units = {version = "0.2.3", features = ["plugins"]} bitflags = "0.7" -canvas = {path = "../canvas"} canvas_traits = {path = "../canvas_traits"} caseless = "0.1.0" cssparser = {version = "0.5.4", features = ["heap_size", "serde-serialization"]} diff --git a/components/script/blob_url_store.rs b/components/script/blob_url_store.rs deleted file mode 100644 index 7f6f34ea406..00000000000 --- a/components/script/blob_url_store.rs +++ /dev/null @@ -1,59 +0,0 @@ -/* 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/. */ - -#![allow(dead_code)] - -use dom::bindings::js::JS; -use dom::blob::Blob; -use origin::Origin; -use std::collections::HashMap; -use uuid::Uuid; - -#[must_root] -#[derive(JSTraceable, HeapSizeOf)] -struct EntryPair(Origin, JS<Blob>); - -// HACK: to work around the HeapSizeOf of Uuid -#[derive(PartialEq, HeapSizeOf, Eq, Hash, JSTraceable)] -struct BlobUrlId(#[ignore_heap_size_of = "defined in uuid"] Uuid); - -#[must_root] -#[derive(JSTraceable, HeapSizeOf)] -pub struct BlobURLStore { - entries: HashMap<BlobUrlId, EntryPair>, -} - -pub enum BlobURLStoreError { - InvalidKey, - InvalidOrigin, -} - -impl BlobURLStore { - pub fn new() -> BlobURLStore { - BlobURLStore { - entries: HashMap::new(), - } - } - - pub fn request(&self, id: Uuid, origin: &Origin) -> Result<&Blob, BlobURLStoreError> { - match self.entries.get(&BlobUrlId(id)) { - Some(ref pair) => { - if pair.0.same_origin(origin) { - Ok(&pair.1) - } else { - Err(BlobURLStoreError::InvalidOrigin) - } - } - None => Err(BlobURLStoreError::InvalidKey) - } - } - - pub fn add_entry(&mut self, id: Uuid, origin: Origin, blob: &Blob) { - self.entries.insert(BlobUrlId(id), EntryPair(origin, JS::from_ref(blob))); - } - - pub fn delete_entry(&mut self, id: Uuid) { - self.entries.remove(&BlobUrlId(id)); - } -} diff --git a/components/script/dom/canvasrenderingcontext2d.rs b/components/script/dom/canvasrenderingcontext2d.rs index cd3583edf4f..fc6afdc2b25 100644 --- a/components/script/dom/canvasrenderingcontext2d.rs +++ b/components/script/dom/canvasrenderingcontext2d.rs @@ -2,7 +2,6 @@ * 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 canvas::canvas_paint_thread::RectToi32; use canvas_traits::{Canvas2dMsg, CanvasCommonMsg, CanvasMsg}; use canvas_traits::{CompositionOrBlending, LineCapStyle, LineJoinStyle}; use canvas_traits::{FillOrStrokeStyle, FillRule, LinearGradientStyle, RadialGradientStyle, RepetitionStyle}; @@ -363,36 +362,30 @@ impl CanvasRenderingContext2D { let smoothing_enabled = self.state.borrow().image_smoothing_enabled; - // If the source and target canvas are the same - let msg = if &*self.canvas == canvas { - CanvasMsg::Canvas2d(Canvas2dMsg::DrawImageSelf(image_size, - dest_rect, - source_rect, - smoothing_enabled)) + if &*self.canvas == canvas { + let msg = CanvasMsg::Canvas2d(Canvas2dMsg::DrawImageSelf( + image_size, dest_rect, source_rect, smoothing_enabled)); + self.ipc_renderer.send(msg).unwrap(); } else { - // Source and target canvases are different let context = match canvas.get_or_init_2d_context() { Some(context) => context, None => return Err(Error::InvalidState), }; + let (sender, receiver) = ipc::channel().unwrap(); + let msg = CanvasMsg::Canvas2d(Canvas2dMsg::DrawImageInOther( + self.ipc_renderer.clone(), + image_size, + dest_rect, + source_rect, + smoothing_enabled, + sender)); + let renderer = context.get_ipc_renderer(); - let (sender, receiver) = ipc::channel::<Vec<u8>>().unwrap(); - // Reads pixels from source image - renderer.send(CanvasMsg::Canvas2d(Canvas2dMsg::GetImageData(source_rect.to_i32(), - image_size, - sender))) - .unwrap(); - let imagedata = receiver.recv().unwrap(); - // Writes pixels to destination canvas - CanvasMsg::Canvas2d(Canvas2dMsg::DrawImage(imagedata, - source_rect.size, - dest_rect, - source_rect, - smoothing_enabled)) + renderer.send(msg).unwrap(); + receiver.recv().unwrap(); }; - self.ipc_renderer.send(msg).unwrap(); self.mark_as_dirty(); Ok(()) } diff --git a/components/script/dom/htmlformelement.rs b/components/script/dom/htmlformelement.rs index fcc10e3d134..515d49c0f7c 100644 --- a/components/script/dom/htmlformelement.rs +++ b/components/script/dom/htmlformelement.rs @@ -6,6 +6,7 @@ use dom::bindings::codegen::Bindings::BlobBinding::BlobMethods; use dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods; use dom::bindings::codegen::Bindings::EventBinding::EventMethods; use dom::bindings::codegen::Bindings::HTMLButtonElementBinding::HTMLButtonElementMethods; +use dom::bindings::codegen::Bindings::HTMLFormControlsCollectionBinding::HTMLFormControlsCollectionMethods; use dom::bindings::codegen::Bindings::HTMLFormElementBinding; use dom::bindings::codegen::Bindings::HTMLFormElementBinding::HTMLFormElementMethods; use dom::bindings::codegen::Bindings::HTMLInputElementBinding::HTMLInputElementMethods; @@ -229,6 +230,12 @@ impl HTMLFormElementMethods for HTMLFormElement { fn Length(&self) -> u32 { self.Elements().Length() as u32 } + + // https://html.spec.whatwg.org/multipage/#dom-form-item + fn IndexedGetter(&self, index: u32, found: &mut bool) -> Option<Root<Element>> { + let elements = self.Elements(); + elements.IndexedGetter(index, found) + } } #[derive(Copy, Clone, HeapSizeOf, PartialEq)] diff --git a/components/script/dom/htmliframeelement.rs b/components/script/dom/htmliframeelement.rs index 57248c03e97..86146b8e915 100644 --- a/components/script/dom/htmliframeelement.rs +++ b/components/script/dom/htmliframeelement.rs @@ -11,12 +11,13 @@ use dom::bindings::codegen::Bindings::BrowserElementBinding::BrowserElementLocat use dom::bindings::codegen::Bindings::BrowserElementBinding::BrowserElementOpenTabEventDetail; use dom::bindings::codegen::Bindings::BrowserElementBinding::BrowserElementOpenWindowEventDetail; use dom::bindings::codegen::Bindings::BrowserElementBinding::BrowserElementSecurityChangeDetail; +use dom::bindings::codegen::Bindings::BrowserElementBinding::BrowserElementVisibilityChangeEventDetail; use dom::bindings::codegen::Bindings::BrowserElementBinding::BrowserShowModalPromptEventDetail; use dom::bindings::codegen::Bindings::HTMLIFrameElementBinding; use dom::bindings::codegen::Bindings::HTMLIFrameElementBinding::HTMLIFrameElementMethods; use dom::bindings::codegen::Bindings::WindowBinding::WindowMethods; use dom::bindings::conversions::ToJSValConvertible; -use dom::bindings::error::{Error, ErrorResult}; +use dom::bindings::error::{Error, ErrorResult, Fallible}; use dom::bindings::global::GlobalRef; use dom::bindings::inheritance::Castable; use dom::bindings::js::{JS, MutNullableHeap, Root, LayoutJS}; @@ -68,6 +69,7 @@ pub struct HTMLIFrameElement { sandbox: MutNullableHeap<JS<DOMTokenList>>, sandbox_allowance: Cell<Option<u8>>, load_blocker: DOMRefCell<Option<LoadBlocker>>, + visibility: Cell<bool>, } impl HTMLIFrameElement { @@ -199,6 +201,7 @@ impl HTMLIFrameElement { sandbox: Default::default(), sandbox_allowance: Cell::new(None), load_blocker: DOMRefCell::new(None), + visibility: Cell::new(true), } } @@ -224,6 +227,26 @@ impl HTMLIFrameElement { self.pipeline_id.get() } + pub fn change_visibility_status(&self, visibility: bool) { + if self.visibility.get() != visibility { + self.visibility.set(visibility); + + // Visibility changes are only exposed to Mozbrowser iframes + if self.Mozbrowser() { + self.dispatch_mozbrowser_event(MozBrowserEvent::VisibilityChange(visibility)); + } + } + } + + pub fn set_visible(&self, visible: bool) { + if let Some(pipeline_id) = self.pipeline_id.get() { + let window = window_from_node(self); + let window = window.r(); + let msg = ConstellationMsg::SetVisible(pipeline_id, visible); + window.constellation_chan().send(msg).unwrap(); + } + } + /// https://html.spec.whatwg.org/multipage/#iframe-load-event-steps steps 1-4 pub fn iframe_load_event_steps(&self, loaded_pipeline: PipelineId) { // TODO(#9592): assert that the load blocker is present at all times when we @@ -390,6 +413,11 @@ impl MozBrowserEventDetailBuilder for HTMLIFrameElement { returnValue: Some(DOMString::from(return_value)), }.to_jsval(cx, rval) } + MozBrowserEvent::VisibilityChange(visibility) => { + BrowserElementVisibilityChangeEventDetail { + visible: Some(visibility), + }.to_jsval(cx, rval); + } } } } @@ -496,6 +524,30 @@ impl HTMLIFrameElementMethods for HTMLIFrameElement { } } + // https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement/setVisible + fn SetVisible(&self, visible: bool) -> ErrorResult { + if self.Mozbrowser() { + self.set_visible(visible); + Ok(()) + } else { + debug!("this frame is not mozbrowser: mozbrowser attribute missing, or not a top + level window, or mozbrowser preference not set (use --pref dom.mozbrowser.enabled)"); + Err(Error::NotSupported) + } + } + + // https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement/getVisible + fn GetVisible(&self) -> Fallible<bool> { + if self.Mozbrowser() { + Ok(self.visibility.get()) + } else { + debug!("this frame is not mozbrowser: mozbrowser attribute missing, or not a top + level window, or mozbrowser preference not set (use --pref dom.mozbrowser.enabled)"); + Err(Error::NotSupported) + } + } + + // https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement/stop fn Stop(&self) -> ErrorResult { Err(Error::NotSupported) diff --git a/components/script/dom/htmlinputelement.rs b/components/script/dom/htmlinputelement.rs index 4c164f2c819..561ccc647f2 100644 --- a/components/script/dom/htmlinputelement.rs +++ b/components/script/dom/htmlinputelement.rs @@ -33,7 +33,7 @@ use dom::validation::Validatable; use dom::virtualmethods::VirtualMethods; use ipc_channel::ipc::{self, IpcSender}; use net_traits::IpcSend; -use net_traits::filemanager_thread::FileManagerThreadMsg; +use net_traits::filemanager_thread::{FileManagerThreadMsg, FilterPattern}; use script_traits::ScriptMsg as ConstellationMsg; use std::borrow::ToOwned; use std::cell::Cell; @@ -993,7 +993,7 @@ impl Activatable for HTMLInputElement { // https://html.spec.whatwg.org/multipage/#reset-button-state-%28type=reset%29:activation-behaviour-2 // https://html.spec.whatwg.org/multipage/#checkbox-state-%28type=checkbox%29:activation-behaviour-2 // https://html.spec.whatwg.org/multipage/#radio-button-state-%28type=radio%29:activation-behaviour-2 - InputType::InputSubmit | InputType::InputReset + InputType::InputSubmit | InputType::InputReset | InputType::InputFile | InputType::InputCheckbox | InputType::InputRadio => self.is_mutable(), _ => false } @@ -1140,9 +1140,11 @@ impl Activatable for HTMLInputElement { let mut files: Vec<Root<File>> = vec![]; let mut error = None; + let filter = filter_from_accept(self.Accept()); + if self.Multiple() { let (chan, recv) = ipc::channel().expect("Error initializing channel"); - let msg = FileManagerThreadMsg::SelectFiles(chan); + let msg = FileManagerThreadMsg::SelectFiles(filter, chan); let _ = filemanager.send(msg).unwrap(); match recv.recv().expect("IpcSender side error") { @@ -1155,7 +1157,7 @@ impl Activatable for HTMLInputElement { }; } else { let (chan, recv) = ipc::channel().expect("Error initializing channel"); - let msg = FileManagerThreadMsg::SelectFile(chan); + let msg = FileManagerThreadMsg::SelectFile(filter, chan); let _ = filemanager.send(msg).unwrap(); match recv.recv().expect("IpcSender side error") { @@ -1228,3 +1230,10 @@ impl Activatable for HTMLInputElement { } } } + +fn filter_from_accept(_s: DOMString) -> Vec<FilterPattern> { + /// TODO: it means not pattern restriction now + /// Blocked by https://github.com/cybergeek94/mime_guess/issues/19 + vec![] +} + diff --git a/components/script/dom/nodelist.rs b/components/script/dom/nodelist.rs index fc4e13d6fbe..2503378187e 100644 --- a/components/script/dom/nodelist.rs +++ b/components/script/dom/nodelist.rs @@ -217,9 +217,9 @@ impl ChildrenList { // by ChildrenMutation::replace(). unreachable!() }, - (_, [node, ..], _) => node, - (_, [], Some(next)) => next, - (Some(prev), [], None) => { + (_, &[node, ..], _) => node, + (_, &[], Some(next)) => next, + (Some(prev), &[], None) => { list.last_index.set(index - 1u32); prev }, diff --git a/components/script/dom/url.rs b/components/script/dom/url.rs index 8ecffe60b33..c6d23bd7d4c 100644 --- a/components/script/dom/url.rs +++ b/components/script/dom/url.rs @@ -3,18 +3,25 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use dom::bindings::cell::DOMRefCell; +use dom::bindings::codegen::Bindings::BlobBinding::BlobMethods; use dom::bindings::codegen::Bindings::URLBinding::{self, URLMethods}; use dom::bindings::error::{Error, ErrorResult, Fallible}; use dom::bindings::global::GlobalRef; use dom::bindings::js::{JS, MutNullableHeap, Root}; use dom::bindings::reflector::{Reflectable, Reflector, reflect_dom_object}; use dom::bindings::str::{DOMString, USVString}; +use dom::blob::Blob; use dom::urlhelper::UrlHelper; use dom::urlsearchparams::URLSearchParams; +use ipc_channel::ipc; +use net_traits::IpcSend; +use net_traits::blob_url_store::{BlobURLStoreEntry, BlobURLStoreMsg, parse_blob_url}; +use net_traits::filemanager_thread::FileManagerThreadMsg; use std::borrow::ToOwned; use std::default::Default; use url::quirks::domain_to_unicode; use url::{Host, Url}; +use uuid::Uuid; // https://url.spec.whatwg.org/#url #[dom_struct] @@ -105,6 +112,90 @@ impl URL { pub fn DomainToUnicode(_: GlobalRef, origin: USVString) -> USVString { USVString(domain_to_unicode(&origin.0)) } + + // https://w3c.github.io/FileAPI/#dfn-createObjectURL + pub fn CreateObjectURL(global: GlobalRef, blob: &Blob) -> DOMString { + /// XXX: Second field is an unicode-serialized Origin, it is a temporary workaround + /// and should not be trusted. See issue https://github.com/servo/servo/issues/11722 + let origin = global.get_url().origin().unicode_serialization(); + + if blob.IsClosed() { + // Generate a dummy id + let id = Uuid::new_v4().simple().to_string(); + return DOMString::from(URL::unicode_serialization_blob_url(&origin, &id)); + } + + let filemanager = global.resource_threads().sender(); + + let slice = blob.get_slice_or_empty(); + let bytes = slice.get_bytes(); + + let entry = BlobURLStoreEntry { + type_string: blob.Type().to_string(), + filename: None, // XXX: the filename is currently only in File object now + size: blob.Size(), + bytes: bytes.to_vec(), + }; + + let (tx, rx) = ipc::channel().unwrap(); + + let msg = BlobURLStoreMsg::AddEntry(entry, origin.clone(), tx); + + let _ = filemanager.send(FileManagerThreadMsg::BlobURLStoreMsg(msg)); + + match rx.recv().unwrap() { + Ok(id) => { + DOMString::from(URL::unicode_serialization_blob_url(&origin, &id)) + } + Err(_) => { + // Generate a dummy id + let id = Uuid::new_v4().simple().to_string(); + DOMString::from(URL::unicode_serialization_blob_url(&origin, &id)) + } + } + } + + // https://w3c.github.io/FileAPI/#dfn-revokeObjectURL + pub fn RevokeObjectURL(global: GlobalRef, url: DOMString) { + /* + If the url refers to a Blob that has a readability state of CLOSED OR + if the value provided for the url argument is not a Blob URL, OR + if the value provided for the url argument does not have an entry in the Blob URL Store, + + this method call does nothing. User agents may display a message on the error console. + + NOTE: The first step is unnecessary, since closed blobs do not exist in the store + */ + + match Url::parse(&url) { + Ok(url) => match parse_blob_url(&url) { + Some((id, _)) => { + let filemanager = global.resource_threads().sender(); + let msg = BlobURLStoreMsg::DeleteEntry(id.simple().to_string()); + let _ = filemanager.send(FileManagerThreadMsg::BlobURLStoreMsg(msg)); + } + None => {} + }, + Err(_) => {} + } + } + + // https://w3c.github.io/FileAPI/#unicodeSerializationOfBlobURL + fn unicode_serialization_blob_url(origin: &str, id: &str) -> String { + // Step 1, 2 + let mut result = "blob:".to_string(); + + // Step 3 + result.push_str(origin); + + // Step 4 + result.push('/'); + + // Step 5 + result.push_str(id); + + result + } } impl URLMethods for URL { diff --git a/components/script/dom/webidls/BrowserElement.webidl b/components/script/dom/webidls/BrowserElement.webidl index 9351cc9377a..f183b5cf813 100644 --- a/components/script/dom/webidls/BrowserElement.webidl +++ b/components/script/dom/webidls/BrowserElement.webidl @@ -96,20 +96,24 @@ dictionary BrowserElementOpenWindowEventDetail { // Element frameElement; }; +dictionary BrowserElementVisibilityChangeEventDetail { + boolean visible; +}; + BrowserElement implements BrowserElementCommon; BrowserElement implements BrowserElementPrivileged; [NoInterfaceObject] interface BrowserElementCommon { - //[Throws, - // Pref="dom.mozBrowserFramesEnabled", - // CheckAnyPermissions="browser embed-widgets"] - //void setVisible(boolean visible); - - //[Throws, - // Pref="dom.mozBrowserFramesEnabled", - // CheckAnyPermissions="browser embed-widgets"] - //DOMRequest getVisible(); + [Throws, + Pref="dom.mozbrowser.enabled", + CheckAnyPermissions="browser embed-widgets"] + void setVisible(boolean visible); + + [Throws, + Pref="dom.mozbrowser.enabled", + CheckAnyPermissions="browser embed-widgets"] + boolean getVisible(); //[Throws, // Pref="dom.mozBrowserFramesEnabled", diff --git a/components/script/dom/webidls/HTMLFormElement.webidl b/components/script/dom/webidls/HTMLFormElement.webidl index a56b83235b6..fba10d25509 100644 --- a/components/script/dom/webidls/HTMLFormElement.webidl +++ b/components/script/dom/webidls/HTMLFormElement.webidl @@ -17,7 +17,7 @@ interface HTMLFormElement : HTMLElement { [SameObject] readonly attribute HTMLFormControlsCollection elements; readonly attribute unsigned long length; - //getter Element (unsigned long index); + getter Element? (unsigned long index); //getter (RadioNodeList or Element) (DOMString name); void submit(); diff --git a/components/script/dom/webidls/URL.webidl b/components/script/dom/webidls/URL.webidl index dc4c71f512e..88f8704ef93 100644 --- a/components/script/dom/webidls/URL.webidl +++ b/components/script/dom/webidls/URL.webidl @@ -23,6 +23,11 @@ interface URL { readonly attribute URLSearchParams searchParams; attribute USVString hash; + // https://w3c.github.io/FileAPI/#creating-revoking + static DOMString createObjectURL(Blob blob); + // static DOMString createFor(Blob blob); + static void revokeObjectURL(DOMString url); + // This is only doing as well as gecko right now. // https://github.com/servo/servo/issues/7590 is on file for // adding attribute stringifier support. diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index 34f7c1acdb0..03fbe2b2a2b 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use app_units::Au; -use blob_url_store::BlobURLStore; use devtools_traits::{ScriptToDevtoolsControlMsg, TimelineMarker, TimelineMarkerType, WorkerId}; use dom::bindings::callback::ExceptionHandling; use dom::bindings::cell::DOMRefCell; @@ -167,9 +166,6 @@ pub struct Window { scheduler_chan: IpcSender<TimerEventRequest>, timers: OneshotTimers, - /// Blob URL store - blob_url_store: DOMRefCell<BlobURLStore>, - next_worker_id: Cell<WorkerId>, /// For sending messages to the memory profiler. @@ -1509,6 +1505,14 @@ impl Window { self.timers.suspend(); } + pub fn slow_down_timers(&self) { + self.timers.slow_down(); + } + + pub fn speed_up_timers(&self) { + self.timers.speed_up(); + } + pub fn need_emit_timeline_marker(&self, timeline_type: TimelineMarkerType) -> bool { let markers = self.devtools_markers.borrow(); markers.contains(&timeline_type) @@ -1633,7 +1637,6 @@ impl Window { console: Default::default(), crypto: Default::default(), navigator: Default::default(), - blob_url_store: DOMRefCell::new(BlobURLStore::new()), image_cache_thread: image_cache_thread, mem_profiler_chan: mem_profiler_chan, time_profiler_chan: time_profiler_chan, diff --git a/components/script/dom/worker.rs b/components/script/dom/worker.rs index 5762e2aa63f..a136f4ec8ca 100644 --- a/components/script/dom/worker.rs +++ b/components/script/dom/worker.rs @@ -147,7 +147,10 @@ impl WorkerMethods for Worker { fn PostMessage(&self, cx: *mut JSContext, message: HandleValue) -> ErrorResult { let data = try!(StructuredCloneData::write(cx, message)); let address = Trusted::new(self); - self.sender.send((address, WorkerScriptMsg::DOMMessage(data))).unwrap(); + + // NOTE: step 9 of https://html.spec.whatwg.org/multipage/#dom-messageport-postmessage + // indicates that a nonexistent communication channel should result in a silent error. + let _ = self.sender.send((address, WorkerScriptMsg::DOMMessage(data))); Ok(()) } diff --git a/components/script/dom/workerglobalscope.rs b/components/script/dom/workerglobalscope.rs index b10916a4b6e..0ca45c509b7 100644 --- a/components/script/dom/workerglobalscope.rs +++ b/components/script/dom/workerglobalscope.rs @@ -2,9 +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 blob_url_store::BlobURLStore; use devtools_traits::{DevtoolScriptControlMsg, ScriptToDevtoolsControlMsg, WorkerId, DevtoolsPageInfo}; -use dom::bindings::cell::DOMRefCell; use dom::bindings::codegen::Bindings::FunctionBinding::Function; use dom::bindings::codegen::Bindings::WorkerGlobalScopeBinding::WorkerGlobalScopeMethods; use dom::bindings::error::{Error, ErrorResult, Fallible, report_pending_exception}; @@ -115,8 +113,6 @@ pub struct WorkerGlobalScope { console: MutNullableHeap<JS<Console>>, crypto: MutNullableHeap<JS<Crypto>>, timers: OneshotTimers, - /// Blob URL store - blob_url_store: DOMRefCell<BlobURLStore>, #[ignore_heap_size_of = "Defined in std"] mem_profiler_chan: mem::ProfilerChan, @@ -177,7 +173,6 @@ impl WorkerGlobalScope { console: Default::default(), crypto: Default::default(), timers: OneshotTimers::new(timer_event_chan, init.scheduler_chan.clone()), - blob_url_store: DOMRefCell::new(BlobURLStore::new()), mem_profiler_chan: init.mem_profiler_chan, time_profiler_chan: init.time_profiler_chan, to_devtools_sender: init.to_devtools_sender, diff --git a/components/script/dom/xmlhttprequest.rs b/components/script/dom/xmlhttprequest.rs index 785a5928c9f..edae06fe66c 100644 --- a/components/script/dom/xmlhttprequest.rs +++ b/components/script/dom/xmlhttprequest.rs @@ -1041,12 +1041,6 @@ impl XMLHttpRequest { self.response_status.set(Ok(())); } - fn insert_trusted_header(&self, name: String, value: String) { - // Insert a header without checking spec-compliance - // Use for hardcoded headers - self.request_headers.borrow_mut().set_raw(name, vec![value.into_bytes()]); - } - fn dispatch_progress_event(&self, upload: bool, type_: Atom, loaded: u64, total: Option<u64>) { let global = self.global(); let progressevent = ProgressEvent::new(global.r(), diff --git a/components/script/lib.rs b/components/script/lib.rs index 2f76a112c0a..307376854ca 100644 --- a/components/script/lib.rs +++ b/components/script/lib.rs @@ -34,7 +34,6 @@ extern crate app_units; #[allow(unused_extern_crates)] #[macro_use] extern crate bitflags; -extern crate canvas; extern crate canvas_traits; extern crate caseless; extern crate core; @@ -87,7 +86,6 @@ extern crate webrender_traits; extern crate websocket; extern crate xml5ever; -mod blob_url_store; pub mod bluetooth_blacklist; pub mod clipboard_provider; mod devtools; diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs index 4750a8d6390..3459e5ddcfa 100644 --- a/components/script/script_thread.rs +++ b/components/script/script_thread.rs @@ -140,6 +140,8 @@ struct InProgressLoad { clip_rect: Option<Rect<f32>>, /// Window is frozen (navigated away while loading for example). is_frozen: bool, + /// Window is visible. + is_visible: bool, /// The requested URL of the load. url: Url, } @@ -158,6 +160,7 @@ impl InProgressLoad { window_size: window_size, clip_rect: None, is_frozen: false, + is_visible: true, url: url, } } @@ -919,6 +922,10 @@ impl ScriptThread { self.handle_freeze_msg(pipeline_id), ConstellationControlMsg::Thaw(pipeline_id) => self.handle_thaw_msg(pipeline_id), + ConstellationControlMsg::ChangeFrameVisibilityStatus(pipeline_id, visible) => + self.handle_visibility_change_msg(pipeline_id, visible), + ConstellationControlMsg::NotifyVisibilityChange(containing_id, pipeline_id, visible) => + self.handle_visibility_change_complete_msg(containing_id, pipeline_id, visible), ConstellationControlMsg::MozBrowserEvent(parent_pipeline_id, subpage_id, event) => @@ -1232,6 +1239,55 @@ impl ScriptThread { reports_chan.send(reports); } + /// To slow/speed up timers and manage any other script thread resource based on visibility. + /// Returns true if successful. + fn alter_resource_utilization(&self, id: PipelineId, visible: bool) -> bool { + if let Some(root_context) = self.browsing_context.get() { + if let Some(ref inner_context) = root_context.find(id) { + let window = inner_context.active_window(); + if visible { + window.speed_up_timers(); + } else { + window.slow_down_timers(); + } + return true; + } + } + false + } + + /// Updates iframe element after a change in visibility + fn handle_visibility_change_complete_msg(&self, containing_id: PipelineId, id: PipelineId, visible: bool) { + if let Some(root_context) = self.browsing_context.get() { + if let Some(ref inner_context) = root_context.find(containing_id) { + if let Some(iframe) = inner_context.active_document().find_iframe_by_pipeline(id) { + iframe.change_visibility_status(visible); + } + } + } + } + + /// Handle visibility change message + fn handle_visibility_change_msg(&self, id: PipelineId, visible: bool) { + let resources_altered = self.alter_resource_utilization(id, visible); + + // Separate message sent since parent script thread could be different (Iframe of different + // domain) + self.constellation_chan.send(ConstellationMsg::VisibilityChangeComplete(id, visible)).unwrap(); + + if !resources_altered { + let mut loads = self.incomplete_loads.borrow_mut(); + if let Some(ref mut load) = loads.iter_mut().find(|load| load.pipeline_id == id) { + load.is_visible = visible; + return; + } + } else { + return; + } + + warn!("change visibility message sent to nonexistent pipeline"); + } + /// Handles freeze message fn handle_freeze_msg(&self, id: PipelineId) { if let Some(root_context) = self.browsing_context.get() { @@ -1707,6 +1763,10 @@ impl ScriptThread { window.freeze(); } + if !incomplete.is_visible { + self.alter_resource_utilization(browsing_context.pipeline(), false); + } + context_remover.neuter(); document.get_current_parser().unwrap() diff --git a/components/script/timers.rs b/components/script/timers.rs index 504dbb8aaaf..989382e80fe 100644 --- a/components/script/timers.rs +++ b/components/script/timers.rs @@ -22,6 +22,7 @@ use std::cmp::{self, Ord, Ordering}; use std::collections::HashMap; use std::default::Default; use std::rc::Rc; +use util::prefs::get_pref; #[derive(JSTraceable, PartialEq, Eq, Copy, Clone, HeapSizeOf, Hash, PartialOrd, Ord, Debug)] pub struct OneshotTimerHandle(i32); @@ -212,6 +213,15 @@ impl OneshotTimers { } } + pub fn slow_down(&self) { + let duration = get_pref("js.timers.minimum_duration").as_u64().unwrap_or(1000); + self.js_timers.set_min_duration(MsDuration::new(duration)); + } + + pub fn speed_up(&self) { + self.js_timers.remove_min_duration(); + } + pub fn suspend(&self) { assert!(self.suspended_since.get().is_none()); @@ -290,6 +300,8 @@ pub struct JsTimers { active_timers: DOMRefCell<HashMap<JsTimerHandle, JsTimerEntry>>, /// The nesting level of the currently executing timer task or 0. nesting_level: Cell<u32>, + /// Used to introduce a minimum delay in event intervals + min_duration: Cell<Option<MsDuration>>, } #[derive(JSTraceable, HeapSizeOf)] @@ -344,6 +356,7 @@ impl JsTimers { next_timer_handle: Cell::new(JsTimerHandle(1)), active_timers: DOMRefCell::new(HashMap::new()), nesting_level: Cell::new(0), + min_duration: Cell::new(None), } } @@ -407,6 +420,24 @@ impl JsTimers { } } + pub fn set_min_duration(&self, duration: MsDuration) { + self.min_duration.set(Some(duration)); + } + + pub fn remove_min_duration(&self) { + self.min_duration.set(None); + } + + // see step 13 of https://html.spec.whatwg.org/multipage/#timer-initialisation-steps + fn user_agent_pad(&self, current_duration: MsDuration) -> MsDuration { + match self.min_duration.get() { + Some(min_duration) => { + cmp::max(min_duration, current_duration) + }, + None => current_duration + } + } + // see https://html.spec.whatwg.org/multipage/#timer-initialisation-steps fn initialize_and_schedule(&self, global: GlobalRef, mut task: JsTimerTask) { let handle = task.handle; @@ -415,13 +446,12 @@ impl JsTimers { // step 6 let nesting_level = self.nesting_level.get(); - // step 7 - let duration = clamp_duration(nesting_level, task.duration); - + // step 7, 13 + let duration = self.user_agent_pad(clamp_duration(nesting_level, task.duration)); // step 8, 9 task.nesting_level = nesting_level + 1; - // essentially step 11-14 + // essentially step 11, 12, and 14 let callback = OneshotTimerCallback::JsTimer(task); let oneshot_handle = global.schedule_callback(callback, duration); |