aboutsummaryrefslogtreecommitdiffstats
path: root/components/script
diff options
context:
space:
mode:
Diffstat (limited to 'components/script')
-rw-r--r--components/script/Cargo.toml1
-rw-r--r--components/script/blob_url_store.rs59
-rw-r--r--components/script/dom/canvasrenderingcontext2d.rs37
-rw-r--r--components/script/dom/htmlformelement.rs7
-rw-r--r--components/script/dom/htmliframeelement.rs54
-rw-r--r--components/script/dom/htmlinputelement.rs17
-rw-r--r--components/script/dom/nodelist.rs6
-rw-r--r--components/script/dom/url.rs91
-rw-r--r--components/script/dom/webidls/BrowserElement.webidl22
-rw-r--r--components/script/dom/webidls/HTMLFormElement.webidl2
-rw-r--r--components/script/dom/webidls/URL.webidl5
-rw-r--r--components/script/dom/window.rs13
-rw-r--r--components/script/dom/worker.rs5
-rw-r--r--components/script/dom/workerglobalscope.rs5
-rw-r--r--components/script/dom/xmlhttprequest.rs6
-rw-r--r--components/script/lib.rs2
-rw-r--r--components/script/script_thread.rs60
-rw-r--r--components/script/timers.rs38
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);