mirror of
https://github.com/servo/servo.git
synced 2025-07-24 15:50:21 +01:00
Storage notifications routed via the constellation.
This commit is contained in:
parent
ef74d8da3b
commit
c91ef86a20
8 changed files with 67 additions and 39 deletions
|
@ -32,7 +32,7 @@ use msg::constellation_msg::{Key, KeyModifiers, KeyState};
|
||||||
use msg::constellation_msg::{PipelineNamespace, PipelineNamespaceId, TraversalDirection};
|
use msg::constellation_msg::{PipelineNamespace, PipelineNamespaceId, TraversalDirection};
|
||||||
use net_traits::{self, IpcSend, ResourceThreads};
|
use net_traits::{self, IpcSend, ResourceThreads};
|
||||||
use net_traits::image_cache_thread::ImageCacheThread;
|
use net_traits::image_cache_thread::ImageCacheThread;
|
||||||
use net_traits::storage_thread::StorageThreadMsg;
|
use net_traits::storage_thread::{StorageThreadMsg, StorageType};
|
||||||
use offscreen_gl_context::{GLContextAttributes, GLLimits};
|
use offscreen_gl_context::{GLContextAttributes, GLLimits};
|
||||||
use pipeline::{ChildProcess, InitialPipelineState, Pipeline};
|
use pipeline::{ChildProcess, InitialPipelineState, Pipeline};
|
||||||
use profile_traits::mem;
|
use profile_traits::mem;
|
||||||
|
@ -1026,6 +1026,9 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
||||||
warn!("Unable to forward DOMMessage for postMessage call");
|
warn!("Unable to forward DOMMessage for postMessage call");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
FromScriptMsg::BroadcastStorageEvent(pipeline_id, storage, url, key, old_value, new_value) => {
|
||||||
|
self.handle_broadcast_storage_event(pipeline_id, storage, url, key, old_value, new_value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1052,6 +1055,21 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn handle_broadcast_storage_event(&self, pipeline_id: PipelineId, storage: StorageType, url: Url,
|
||||||
|
key: Option<String>, old_value: Option<String>, new_value: Option<String>) {
|
||||||
|
let origin = url.origin();
|
||||||
|
for pipeline in self.pipelines.values() {
|
||||||
|
if (pipeline.id != pipeline_id) && (pipeline.url.origin() == origin) {
|
||||||
|
let msg = ConstellationControlMsg::DispatchStorageEvent(
|
||||||
|
pipeline.id, storage, url.clone(), key.clone(), old_value.clone(), new_value.clone()
|
||||||
|
);
|
||||||
|
if let Err(err) = pipeline.script_chan.send(msg) {
|
||||||
|
warn!("Failed to broadcast storage event to pipeline {} ({:?}).", pipeline.id, err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn handle_exit(&mut self) {
|
fn handle_exit(&mut self) {
|
||||||
// TODO: add a timer, which forces shutdown if threads aren't responsive.
|
// TODO: add a timer, which forces shutdown if threads aren't responsive.
|
||||||
if self.shutting_down { return; }
|
if self.shutting_down { return; }
|
||||||
|
|
|
@ -17,6 +17,7 @@ use ipc_channel::ipc::{self, IpcSender};
|
||||||
use net_traits::IpcSend;
|
use net_traits::IpcSend;
|
||||||
use net_traits::storage_thread::{StorageThreadMsg, StorageType};
|
use net_traits::storage_thread::{StorageThreadMsg, StorageType};
|
||||||
use script_thread::{Runnable, ScriptThread};
|
use script_thread::{Runnable, ScriptThread};
|
||||||
|
use script_traits::ScriptMsg;
|
||||||
use task_source::TaskSource;
|
use task_source::TaskSource;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
|
@ -149,60 +150,60 @@ impl Storage {
|
||||||
/// https://html.spec.whatwg.org/multipage/#send-a-storage-notification
|
/// https://html.spec.whatwg.org/multipage/#send-a-storage-notification
|
||||||
fn broadcast_change_notification(&self, key: Option<String>, old_value: Option<String>,
|
fn broadcast_change_notification(&self, key: Option<String>, old_value: Option<String>,
|
||||||
new_value: Option<String>) {
|
new_value: Option<String>) {
|
||||||
|
let pipeline_id = self.global().pipeline_id();
|
||||||
|
let storage = self.storage_type;
|
||||||
|
let url = self.get_url();
|
||||||
|
let msg = ScriptMsg::BroadcastStorageEvent(pipeline_id, storage, url, key, old_value, new_value);
|
||||||
|
self.global().constellation_chan().send(msg).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// https://html.spec.whatwg.org/multipage/#send-a-storage-notification
|
||||||
|
pub fn queue_storage_event(&self, url: Url,
|
||||||
|
key: Option<String>, old_value: Option<String>, new_value: Option<String>) {
|
||||||
let global = self.global();
|
let global = self.global();
|
||||||
let window = global.as_window();
|
let window = global.as_window();
|
||||||
let task_source = window.dom_manipulation_task_source();
|
let task_source = window.dom_manipulation_task_source();
|
||||||
let trusted_storage = Trusted::new(self);
|
let trusted_storage = Trusted::new(self);
|
||||||
task_source
|
task_source
|
||||||
.queue(
|
.queue(
|
||||||
box StorageEventRunnable::new(trusted_storage, key, old_value, new_value), &global)
|
box StorageEventRunnable::new(trusted_storage, url, key, old_value, new_value), &global)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct StorageEventRunnable {
|
pub struct StorageEventRunnable {
|
||||||
element: Trusted<Storage>,
|
element: Trusted<Storage>,
|
||||||
|
url: Url,
|
||||||
key: Option<String>,
|
key: Option<String>,
|
||||||
old_value: Option<String>,
|
old_value: Option<String>,
|
||||||
new_value: Option<String>
|
new_value: Option<String>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StorageEventRunnable {
|
impl StorageEventRunnable {
|
||||||
fn new(storage: Trusted<Storage>, key: Option<String>, old_value: Option<String>,
|
fn new(storage: Trusted<Storage>, url: Url,
|
||||||
new_value: Option<String>) -> StorageEventRunnable {
|
key: Option<String>, old_value: Option<String>, new_value: Option<String>) -> StorageEventRunnable {
|
||||||
StorageEventRunnable { element: storage, key: key, old_value: old_value, new_value: new_value }
|
StorageEventRunnable { element: storage, url: url, key: key, old_value: old_value, new_value: new_value }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Runnable for StorageEventRunnable {
|
impl Runnable for StorageEventRunnable {
|
||||||
fn name(&self) -> &'static str { "StorageEventRunnable" }
|
fn name(&self) -> &'static str { "StorageEventRunnable" }
|
||||||
|
|
||||||
fn main_thread_handler(self: Box<StorageEventRunnable>, script_thread: &ScriptThread) {
|
fn main_thread_handler(self: Box<StorageEventRunnable>, _: &ScriptThread) {
|
||||||
let this = *self;
|
let this = *self;
|
||||||
let storage = this.element.root();
|
let storage = this.element.root();
|
||||||
let global = storage.global();
|
let global = storage.global();
|
||||||
let ev_url = storage.get_url();
|
let window = global.as_window();
|
||||||
|
|
||||||
let storage_event = StorageEvent::new(
|
let storage_event = StorageEvent::new(
|
||||||
&global,
|
&global,
|
||||||
atom!("storage"),
|
atom!("storage"),
|
||||||
EventBubbles::DoesNotBubble, EventCancelable::NotCancelable,
|
EventBubbles::DoesNotBubble, EventCancelable::NotCancelable,
|
||||||
this.key.map(DOMString::from), this.old_value.map(DOMString::from), this.new_value.map(DOMString::from),
|
this.key.map(DOMString::from), this.old_value.map(DOMString::from), this.new_value.map(DOMString::from),
|
||||||
DOMString::from(ev_url.to_string()),
|
DOMString::from(this.url.into_string()),
|
||||||
Some(&storage)
|
Some(&storage)
|
||||||
);
|
);
|
||||||
|
|
||||||
// TODO: This is only iterating over documents in the current script
|
storage_event.upcast::<Event>().fire(window.upcast());
|
||||||
// thread, so we are not firing events to other script threads.
|
|
||||||
// NOTE: once that is fixed, we can remove borrow_documents from ScriptThread.
|
|
||||||
for (id, document) in script_thread.borrow_documents().iter() {
|
|
||||||
if ev_url.origin() == document.window().get_url().origin() {
|
|
||||||
// TODO: Such a Document object is not necessarily fully active, but events fired on such
|
|
||||||
// objects are ignored by the event loop until the Document becomes fully active again.
|
|
||||||
if global.pipeline_id() != id {
|
|
||||||
storage_event.upcast::<Event>().fire(document.window().upcast());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,6 +75,7 @@ use msg::constellation_msg::{FrameId, FrameType, PipelineId, PipelineNamespace};
|
||||||
use net_traits::{CoreResourceMsg, IpcSend, Metadata, ReferrerPolicy, ResourceThreads};
|
use net_traits::{CoreResourceMsg, IpcSend, Metadata, ReferrerPolicy, ResourceThreads};
|
||||||
use net_traits::image_cache_thread::{ImageCacheChan, ImageCacheResult, ImageCacheThread};
|
use net_traits::image_cache_thread::{ImageCacheChan, ImageCacheResult, ImageCacheThread};
|
||||||
use net_traits::request::{CredentialsMode, Destination, RequestInit};
|
use net_traits::request::{CredentialsMode, Destination, RequestInit};
|
||||||
|
use net_traits::storage_thread::StorageType;
|
||||||
use network_listener::NetworkListener;
|
use network_listener::NetworkListener;
|
||||||
use profile_traits::mem::{self, OpaqueSender, Report, ReportKind, ReportsChan};
|
use profile_traits::mem::{self, OpaqueSender, Report, ReportKind, ReportsChan};
|
||||||
use profile_traits::time::{self, ProfilerCategory, profile};
|
use profile_traits::time::{self, ProfilerCategory, profile};
|
||||||
|
@ -90,7 +91,7 @@ use script_traits::CompositorEvent::{KeyEvent, MouseButtonEvent, MouseMoveEvent,
|
||||||
use script_traits::CompositorEvent::{TouchEvent, TouchpadPressureEvent};
|
use script_traits::CompositorEvent::{TouchEvent, TouchpadPressureEvent};
|
||||||
use script_traits::webdriver_msg::WebDriverScriptCommand;
|
use script_traits::webdriver_msg::WebDriverScriptCommand;
|
||||||
use std::borrow::ToOwned;
|
use std::borrow::ToOwned;
|
||||||
use std::cell::{Cell, Ref};
|
use std::cell::Cell;
|
||||||
use std::collections::{hash_map, HashMap, HashSet};
|
use std::collections::{hash_map, HashMap, HashSet};
|
||||||
use std::option::Option;
|
use std::option::Option;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
@ -605,12 +606,6 @@ impl ScriptThread {
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: This method is only needed for storage, and can be removed
|
|
||||||
// once storage event dispatch is moved to the constellation.
|
|
||||||
pub fn borrow_documents(&self) -> Ref<Documents> {
|
|
||||||
self.documents.borrow()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a new script thread.
|
/// Creates a new script thread.
|
||||||
pub fn new(state: InitialScriptState,
|
pub fn new(state: InitialScriptState,
|
||||||
port: Receiver<MainThreadScriptMsg>,
|
port: Receiver<MainThreadScriptMsg>,
|
||||||
|
@ -981,6 +976,8 @@ impl ScriptThread {
|
||||||
ConstellationControlMsg::DispatchFrameLoadEvent {
|
ConstellationControlMsg::DispatchFrameLoadEvent {
|
||||||
target: frame_id, parent: parent_id, child: child_id } =>
|
target: frame_id, parent: parent_id, child: child_id } =>
|
||||||
self.handle_frame_load_event(parent_id, frame_id, child_id),
|
self.handle_frame_load_event(parent_id, frame_id, child_id),
|
||||||
|
ConstellationControlMsg::DispatchStorageEvent(pipeline_id, storage, url, key, old_value, new_value) =>
|
||||||
|
self.handle_storage_event(pipeline_id, storage, url, key, old_value, new_value),
|
||||||
ConstellationControlMsg::FramedContentChanged(parent_pipeline_id, frame_id) =>
|
ConstellationControlMsg::FramedContentChanged(parent_pipeline_id, frame_id) =>
|
||||||
self.handle_framed_content_changed(parent_pipeline_id, frame_id),
|
self.handle_framed_content_changed(parent_pipeline_id, frame_id),
|
||||||
ConstellationControlMsg::ReportCSSError(pipeline_id, filename, line, column, msg) =>
|
ConstellationControlMsg::ReportCSSError(pipeline_id, filename, line, column, msg) =>
|
||||||
|
@ -1582,6 +1579,20 @@ impl ScriptThread {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Notify a window of a storage event
|
||||||
|
fn handle_storage_event(&self, pipeline_id: PipelineId, storage_type: StorageType, url: Url,
|
||||||
|
key: Option<String>, old_value: Option<String>, new_value: Option<String>) {
|
||||||
|
let storage = match self.documents.borrow().find_window(pipeline_id) {
|
||||||
|
None => return warn!("Storage event sent to closed pipeline {}.", pipeline_id),
|
||||||
|
Some(window) => match storage_type {
|
||||||
|
StorageType::Local => window.LocalStorage(),
|
||||||
|
StorageType::Session => window.SessionStorage(),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
storage.queue_storage_event(url, key, old_value, new_value);
|
||||||
|
}
|
||||||
|
|
||||||
/// Notify the containing document of a child frame that has completed loading.
|
/// Notify the containing document of a child frame that has completed loading.
|
||||||
fn handle_frame_load_event(&self, parent_id: PipelineId, frame_id: FrameId, child_id: PipelineId) {
|
fn handle_frame_load_event(&self, parent_id: PipelineId, frame_id: FrameId, child_id: PipelineId) {
|
||||||
match self.documents.borrow().find_iframe(parent_id, frame_id) {
|
match self.documents.borrow().find_iframe(parent_id, frame_id) {
|
||||||
|
|
|
@ -60,6 +60,7 @@ use net_traits::{ReferrerPolicy, ResourceThreads};
|
||||||
use net_traits::image::base::Image;
|
use net_traits::image::base::Image;
|
||||||
use net_traits::image_cache_thread::ImageCacheThread;
|
use net_traits::image_cache_thread::ImageCacheThread;
|
||||||
use net_traits::response::HttpsState;
|
use net_traits::response::HttpsState;
|
||||||
|
use net_traits::storage_thread::StorageType;
|
||||||
use profile_traits::mem;
|
use profile_traits::mem;
|
||||||
use profile_traits::time as profile_time;
|
use profile_traits::time as profile_time;
|
||||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||||
|
@ -244,6 +245,9 @@ pub enum ConstellationControlMsg {
|
||||||
/// The pipeline that has completed loading.
|
/// The pipeline that has completed loading.
|
||||||
child: PipelineId,
|
child: PipelineId,
|
||||||
},
|
},
|
||||||
|
/// Cause a `storage` event to be dispatched at the appropriate window.
|
||||||
|
/// The strings are key, old value and new value.
|
||||||
|
DispatchStorageEvent(PipelineId, StorageType, Url, Option<String>, Option<String>, Option<String>),
|
||||||
/// Notifies a parent pipeline that one of its child frames is now active.
|
/// Notifies a parent pipeline that one of its child frames is now active.
|
||||||
/// PipelineId is for the parent, FrameId is the child frame.
|
/// PipelineId is for the parent, FrameId is the child frame.
|
||||||
FramedContentChanged(PipelineId, FrameId),
|
FramedContentChanged(PipelineId, FrameId),
|
||||||
|
@ -279,6 +283,7 @@ impl fmt::Debug for ConstellationControlMsg {
|
||||||
TransitionEnd(..) => "TransitionEnd",
|
TransitionEnd(..) => "TransitionEnd",
|
||||||
WebFontLoaded(..) => "WebFontLoaded",
|
WebFontLoaded(..) => "WebFontLoaded",
|
||||||
DispatchFrameLoadEvent { .. } => "DispatchFrameLoadEvent",
|
DispatchFrameLoadEvent { .. } => "DispatchFrameLoadEvent",
|
||||||
|
DispatchStorageEvent(..) => "DispatchStorageEvent",
|
||||||
FramedContentChanged(..) => "FramedContentChanged",
|
FramedContentChanged(..) => "FramedContentChanged",
|
||||||
ReportCSSError(..) => "ReportCSSError",
|
ReportCSSError(..) => "ReportCSSError",
|
||||||
Reload(..) => "Reload"
|
Reload(..) => "Reload"
|
||||||
|
|
|
@ -18,6 +18,7 @@ use ipc_channel::ipc::IpcSender;
|
||||||
use msg::constellation_msg::{Key, KeyModifiers, KeyState};
|
use msg::constellation_msg::{Key, KeyModifiers, KeyState};
|
||||||
use msg::constellation_msg::{PipelineId, TraversalDirection};
|
use msg::constellation_msg::{PipelineId, TraversalDirection};
|
||||||
use net_traits::CoreResourceMsg;
|
use net_traits::CoreResourceMsg;
|
||||||
|
use net_traits::storage_thread::StorageType;
|
||||||
use offscreen_gl_context::{GLContextAttributes, GLLimits};
|
use offscreen_gl_context::{GLContextAttributes, GLLimits};
|
||||||
use style_traits::cursor::Cursor;
|
use style_traits::cursor::Cursor;
|
||||||
use style_traits::viewport::ViewportConstraints;
|
use style_traits::viewport::ViewportConstraints;
|
||||||
|
@ -59,6 +60,9 @@ pub enum LogEntry {
|
||||||
/// Messages from the script to the constellation.
|
/// Messages from the script to the constellation.
|
||||||
#[derive(Deserialize, Serialize)]
|
#[derive(Deserialize, Serialize)]
|
||||||
pub enum ScriptMsg {
|
pub enum ScriptMsg {
|
||||||
|
/// Broadcast a storage event to every same-origin pipeline.
|
||||||
|
/// The strings are key, old value and new value.
|
||||||
|
BroadcastStorageEvent(PipelineId, StorageType, Url, Option<String>, Option<String>, Option<String>),
|
||||||
/// Indicates whether this pipeline is currently running animations.
|
/// Indicates whether this pipeline is currently running animations.
|
||||||
ChangeRunningAnimationsState(PipelineId, AnimationState),
|
ChangeRunningAnimationsState(PipelineId, AnimationState),
|
||||||
/// Requests that a new 2D canvas thread be created. (This is done in the constellation because
|
/// Requests that a new 2D canvas thread be created. (This is done in the constellation because
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
[noreferrer.html]
|
[noreferrer.html]
|
||||||
type: testharness
|
type: testharness
|
||||||
expected: CRASH
|
|
||||||
[rel=noreferrer nullifies window.opener]
|
[rel=noreferrer nullifies window.opener]
|
||||||
expected: CRASH
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
[event_local_removeitem.html]
|
|
||||||
type: testharness
|
|
||||||
[key property test of local event]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
[event_session_removeitem.html]
|
|
||||||
type: testharness
|
|
||||||
[key property test of session event]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue