Storage notifications routed via the constellation.

This commit is contained in:
Alan Jeffrey 2016-11-01 20:49:46 -05:00
parent ef74d8da3b
commit c91ef86a20
8 changed files with 67 additions and 39 deletions

View file

@ -17,6 +17,7 @@ use ipc_channel::ipc::{self, IpcSender};
use net_traits::IpcSend;
use net_traits::storage_thread::{StorageThreadMsg, StorageType};
use script_thread::{Runnable, ScriptThread};
use script_traits::ScriptMsg;
use task_source::TaskSource;
use url::Url;
@ -149,60 +150,60 @@ impl Storage {
/// https://html.spec.whatwg.org/multipage/#send-a-storage-notification
fn broadcast_change_notification(&self, key: Option<String>, old_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 window = global.as_window();
let task_source = window.dom_manipulation_task_source();
let trusted_storage = Trusted::new(self);
task_source
.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();
}
}
pub struct StorageEventRunnable {
element: Trusted<Storage>,
url: Url,
key: Option<String>,
old_value: Option<String>,
new_value: Option<String>
}
impl StorageEventRunnable {
fn new(storage: Trusted<Storage>, 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 }
fn new(storage: Trusted<Storage>, url: Url,
key: Option<String>, old_value: Option<String>, new_value: Option<String>) -> StorageEventRunnable {
StorageEventRunnable { element: storage, url: url, key: key, old_value: old_value, new_value: new_value }
}
}
impl Runnable for 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 storage = this.element.root();
let global = storage.global();
let ev_url = storage.get_url();
let window = global.as_window();
let storage_event = StorageEvent::new(
&global,
atom!("storage"),
EventBubbles::DoesNotBubble, EventCancelable::NotCancelable,
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)
);
// TODO: This is only iterating over documents in the current script
// 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());
}
}
}
storage_event.upcast::<Event>().fire(window.upcast());
}
}

View file

@ -75,6 +75,7 @@ use msg::constellation_msg::{FrameId, FrameType, PipelineId, PipelineNamespace};
use net_traits::{CoreResourceMsg, IpcSend, Metadata, ReferrerPolicy, ResourceThreads};
use net_traits::image_cache_thread::{ImageCacheChan, ImageCacheResult, ImageCacheThread};
use net_traits::request::{CredentialsMode, Destination, RequestInit};
use net_traits::storage_thread::StorageType;
use network_listener::NetworkListener;
use profile_traits::mem::{self, OpaqueSender, Report, ReportKind, ReportsChan};
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::webdriver_msg::WebDriverScriptCommand;
use std::borrow::ToOwned;
use std::cell::{Cell, Ref};
use std::cell::Cell;
use std::collections::{hash_map, HashMap, HashSet};
use std::option::Option;
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.
pub fn new(state: InitialScriptState,
port: Receiver<MainThreadScriptMsg>,
@ -981,6 +976,8 @@ impl ScriptThread {
ConstellationControlMsg::DispatchFrameLoadEvent {
target: frame_id, parent: parent_id, child: 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) =>
self.handle_framed_content_changed(parent_pipeline_id, frame_id),
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.
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) {