mirror of
https://github.com/servo/servo.git
synced 2025-08-07 06:25:32 +01:00
Auto merge of #20678 - gterzian:improve_follow_hyperlinks, r=jdm
Implement Window.open and related infrastructure <!-- Please describe your changes on the following line: --> Implement https://html.spec.whatwg.org/multipage/window-object.html#window-open-steps and related infra... --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: --> - [ ] `./mach build -d` does not report any errors - [ ] `./mach build-geckolib` does not report any errors - [ ] `./mach test-tidy` does not report any errors - [ ] These changes fix #20673 fix #13241 fix #20887 fix #20713 (github issue number if applicable). <!-- Either: --> - [ ] There are tests for these changes OR - [ ] These changes do not require tests because _____ <!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.--> <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/20678) <!-- Reviewable:end -->
This commit is contained in:
commit
9c24c16d82
114 changed files with 831 additions and 529 deletions
|
@ -8,7 +8,6 @@ use embedder_traits::EventLoopWaker;
|
||||||
use euclid::TypedScale;
|
use euclid::TypedScale;
|
||||||
#[cfg(feature = "gleam")]
|
#[cfg(feature = "gleam")]
|
||||||
use gleam::gl;
|
use gleam::gl;
|
||||||
use ipc_channel::ipc::IpcSender;
|
|
||||||
use msg::constellation_msg::{Key, KeyModifiers, KeyState, TopLevelBrowsingContextId, TraversalDirection};
|
use msg::constellation_msg::{Key, KeyModifiers, KeyState, TopLevelBrowsingContextId, TraversalDirection};
|
||||||
use script_traits::{MouseButton, TouchEventType, TouchId};
|
use script_traits::{MouseButton, TouchEventType, TouchId};
|
||||||
use servo_geometry::{DeviceIndependentPixel, DeviceUintLength};
|
use servo_geometry::{DeviceIndependentPixel, DeviceUintLength};
|
||||||
|
@ -75,7 +74,7 @@ pub enum WindowEvent {
|
||||||
/// Sent when Ctr+R/Apple+R is called to reload the current page.
|
/// Sent when Ctr+R/Apple+R is called to reload the current page.
|
||||||
Reload(TopLevelBrowsingContextId),
|
Reload(TopLevelBrowsingContextId),
|
||||||
/// Create a new top level browsing context
|
/// Create a new top level browsing context
|
||||||
NewBrowser(ServoUrl, IpcSender<TopLevelBrowsingContextId>),
|
NewBrowser(ServoUrl, TopLevelBrowsingContextId),
|
||||||
/// Close a top level browsing context
|
/// Close a top level browsing context
|
||||||
CloseBrowser(TopLevelBrowsingContextId),
|
CloseBrowser(TopLevelBrowsingContextId),
|
||||||
/// Panic a top level browsing context.
|
/// Panic a top level browsing context.
|
||||||
|
|
|
@ -123,7 +123,7 @@ use network_listener::NetworkListener;
|
||||||
use pipeline::{InitialPipelineState, Pipeline};
|
use pipeline::{InitialPipelineState, Pipeline};
|
||||||
use profile_traits::mem;
|
use profile_traits::mem;
|
||||||
use profile_traits::time;
|
use profile_traits::time;
|
||||||
use script_traits::{AnimationState, AnimationTickType, CompositorEvent};
|
use script_traits::{AnimationState, AuxiliaryBrowsingContextLoadInfo, AnimationTickType, CompositorEvent};
|
||||||
use script_traits::{ConstellationControlMsg, ConstellationMsg as FromCompositorMsg, DiscardBrowsingContext};
|
use script_traits::{ConstellationControlMsg, ConstellationMsg as FromCompositorMsg, DiscardBrowsingContext};
|
||||||
use script_traits::{DocumentActivity, DocumentState, LayoutControlMsg, LoadData};
|
use script_traits::{DocumentActivity, DocumentState, LayoutControlMsg, LoadData};
|
||||||
use script_traits::{IFrameLoadInfo, IFrameLoadInfoWithData, IFrameSandboxState, TimerSchedulerMsg};
|
use script_traits::{IFrameLoadInfo, IFrameLoadInfoWithData, IFrameSandboxState, TimerSchedulerMsg};
|
||||||
|
@ -264,18 +264,13 @@ pub struct Constellation<Message, LTF, STF> {
|
||||||
/// WebRender thread.
|
/// WebRender thread.
|
||||||
webrender_api_sender: webrender_api::RenderApiSender,
|
webrender_api_sender: webrender_api::RenderApiSender,
|
||||||
|
|
||||||
/// The set of all event loops in the browser. We generate a new
|
/// The set of all event loops in the browser.
|
||||||
/// event loop for each registered domain name (aka eTLD+1) in
|
/// We store the event loops in a map
|
||||||
/// each top-level browsing context. We store the event loops in a map
|
/// indexed by registered domain name (as a `Host`) to event loops.
|
||||||
/// indexed by top-level browsing context id
|
|
||||||
/// (as a `TopLevelBrowsingContextId`) and registered
|
|
||||||
/// domain name (as a `Host`) to event loops. This double
|
|
||||||
/// indirection ensures that separate tabs do not share event
|
|
||||||
/// loops, even if the same domain is loaded in each.
|
|
||||||
/// It is important that scripts with the same eTLD+1
|
/// It is important that scripts with the same eTLD+1
|
||||||
/// share an event loop, since they can use `document.domain`
|
/// share an event loop, since they can use `document.domain`
|
||||||
/// to become same-origin, at which point they can share DOM objects.
|
/// to become same-origin, at which point they can share DOM objects.
|
||||||
event_loops: HashMap<TopLevelBrowsingContextId, HashMap<Host, Weak<EventLoop>>>,
|
event_loops: HashMap<Host, Weak<EventLoop>>,
|
||||||
|
|
||||||
joint_session_histories: HashMap<TopLevelBrowsingContextId, JointSessionHistory>,
|
joint_session_histories: HashMap<TopLevelBrowsingContextId, JointSessionHistory>,
|
||||||
|
|
||||||
|
@ -583,7 +578,8 @@ where
|
||||||
let swmanager_receiver =
|
let swmanager_receiver =
|
||||||
route_ipc_receiver_to_new_mpsc_receiver_preserving_errors(swmanager_receiver);
|
route_ipc_receiver_to_new_mpsc_receiver_preserving_errors(swmanager_receiver);
|
||||||
|
|
||||||
PipelineNamespace::install(PipelineNamespaceId(0));
|
// Zero is reserved for the embedder.
|
||||||
|
PipelineNamespace::install(PipelineNamespaceId(1));
|
||||||
|
|
||||||
let mut constellation: Constellation<Message, LTF, STF> = Constellation {
|
let mut constellation: Constellation<Message, LTF, STF> = Constellation {
|
||||||
script_sender: ipc_script_sender,
|
script_sender: ipc_script_sender,
|
||||||
|
@ -610,8 +606,10 @@ where
|
||||||
pipelines: HashMap::new(),
|
pipelines: HashMap::new(),
|
||||||
browsing_contexts: HashMap::new(),
|
browsing_contexts: HashMap::new(),
|
||||||
pending_changes: vec![],
|
pending_changes: vec![],
|
||||||
// We initialize the namespace at 1, since we reserved namespace 0 for the constellation
|
// We initialize the namespace at 2,
|
||||||
next_pipeline_namespace_id: PipelineNamespaceId(1),
|
// since we reserved namespace 0 for the embedder,
|
||||||
|
// and 0 for the constellation
|
||||||
|
next_pipeline_namespace_id: PipelineNamespaceId(2),
|
||||||
focus_pipeline_id: None,
|
focus_pipeline_id: None,
|
||||||
time_profiler_chan: state.time_profiler_chan,
|
time_profiler_chan: state.time_profiler_chan,
|
||||||
mem_profiler_chan: state.mem_profiler_chan,
|
mem_profiler_chan: state.mem_profiler_chan,
|
||||||
|
@ -690,6 +688,7 @@ where
|
||||||
browsing_context_id: BrowsingContextId,
|
browsing_context_id: BrowsingContextId,
|
||||||
top_level_browsing_context_id: TopLevelBrowsingContextId,
|
top_level_browsing_context_id: TopLevelBrowsingContextId,
|
||||||
parent_info: Option<PipelineId>,
|
parent_info: Option<PipelineId>,
|
||||||
|
opener: Option<BrowsingContextId>,
|
||||||
initial_window_size: Option<TypedSize2D<f32, CSSPixel>>,
|
initial_window_size: Option<TypedSize2D<f32, CSSPixel>>,
|
||||||
// TODO: we have to provide ownership of the LoadData
|
// TODO: we have to provide ownership of the LoadData
|
||||||
// here, because it will be send on an ipc channel,
|
// here, because it will be send on an ipc channel,
|
||||||
|
@ -717,9 +716,7 @@ where
|
||||||
None => (None, None),
|
None => (None, None),
|
||||||
Some(host) => {
|
Some(host) => {
|
||||||
let event_loop = self
|
let event_loop = self
|
||||||
.event_loops
|
.event_loops.get(&host)
|
||||||
.get(&top_level_browsing_context_id)
|
|
||||||
.and_then(|map| map.get(&host))
|
|
||||||
.and_then(|weak| weak.upgrade());
|
.and_then(|weak| weak.upgrade());
|
||||||
match event_loop {
|
match event_loop {
|
||||||
None => (None, Some(host)),
|
None => (None, Some(host)),
|
||||||
|
@ -764,6 +761,7 @@ where
|
||||||
browsing_context_id,
|
browsing_context_id,
|
||||||
top_level_browsing_context_id,
|
top_level_browsing_context_id,
|
||||||
parent_info,
|
parent_info,
|
||||||
|
opener,
|
||||||
script_to_constellation_chan: ScriptToConstellationChan {
|
script_to_constellation_chan: ScriptToConstellationChan {
|
||||||
sender: self.script_sender.clone(),
|
sender: self.script_sender.clone(),
|
||||||
pipeline_id: pipeline_id,
|
pipeline_id: pipeline_id,
|
||||||
|
@ -804,9 +802,8 @@ where
|
||||||
"Adding new host entry {} for top-level browsing context {}.",
|
"Adding new host entry {} for top-level browsing context {}.",
|
||||||
host, top_level_browsing_context_id
|
host, top_level_browsing_context_id
|
||||||
);
|
);
|
||||||
self.event_loops
|
let _ = self
|
||||||
.entry(top_level_browsing_context_id)
|
.event_loops
|
||||||
.or_insert_with(HashMap::new)
|
|
||||||
.insert(host, Rc::downgrade(&pipeline.event_loop));
|
.insert(host, Rc::downgrade(&pipeline.event_loop));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1032,8 +1029,8 @@ where
|
||||||
},
|
},
|
||||||
// Create a new top level browsing context. Will use response_chan to return
|
// Create a new top level browsing context. Will use response_chan to return
|
||||||
// the browsing context id.
|
// the browsing context id.
|
||||||
FromCompositorMsg::NewBrowser(url, response_chan) => {
|
FromCompositorMsg::NewBrowser(url, top_level_browsing_context_id) => {
|
||||||
self.handle_new_top_level_browsing_context(url, response_chan);
|
self.handle_new_top_level_browsing_context(url, top_level_browsing_context_id);
|
||||||
},
|
},
|
||||||
// Close a top level browsing context.
|
// Close a top level browsing context.
|
||||||
FromCompositorMsg::CloseBrowser(top_level_browsing_context_id) => {
|
FromCompositorMsg::CloseBrowser(top_level_browsing_context_id) => {
|
||||||
|
@ -1121,6 +1118,9 @@ where
|
||||||
FromScriptMsg::ScriptNewIFrame(load_info, layout_sender) => {
|
FromScriptMsg::ScriptNewIFrame(load_info, layout_sender) => {
|
||||||
self.handle_script_new_iframe(load_info, layout_sender);
|
self.handle_script_new_iframe(load_info, layout_sender);
|
||||||
},
|
},
|
||||||
|
FromScriptMsg::ScriptNewAuxiliary(load_info, layout_sender) => {
|
||||||
|
self.handle_script_new_auxiliary(load_info, layout_sender);
|
||||||
|
},
|
||||||
FromScriptMsg::ChangeRunningAnimationsState(animation_state) => {
|
FromScriptMsg::ChangeRunningAnimationsState(animation_state) => {
|
||||||
self.handle_change_running_animations_state(source_pipeline_id, animation_state)
|
self.handle_change_running_animations_state(source_pipeline_id, animation_state)
|
||||||
},
|
},
|
||||||
|
@ -1253,6 +1253,13 @@ where
|
||||||
warn!("Sending reply to get parent info failed ({:?}).", e);
|
warn!("Sending reply to get parent info failed ({:?}).", e);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
FromScriptMsg::GetTopForBrowsingContext(browsing_context_id, sender) => {
|
||||||
|
let result = self.browsing_contexts.get(&browsing_context_id)
|
||||||
|
.and_then(|bc| Some(bc.top_level_id));
|
||||||
|
if let Err(e) = sender.send(result) {
|
||||||
|
warn!("Sending reply to get top for browsing context info failed ({:?}).", e);
|
||||||
|
}
|
||||||
|
},
|
||||||
FromScriptMsg::GetChildBrowsingContextId(browsing_context_id, index, sender) => {
|
FromScriptMsg::GetChildBrowsingContextId(browsing_context_id, index, sender) => {
|
||||||
let result = self
|
let result = self
|
||||||
.browsing_contexts
|
.browsing_contexts
|
||||||
|
@ -1544,11 +1551,12 @@ where
|
||||||
(window_size, pipeline_id)
|
(window_size, pipeline_id)
|
||||||
};
|
};
|
||||||
|
|
||||||
let (pipeline_url, parent_info) = {
|
let (pipeline_url, parent_info, opener) = {
|
||||||
let pipeline = pipeline_id.and_then(|id| self.pipelines.get(&id));
|
let pipeline = pipeline_id.and_then(|id| self.pipelines.get(&id));
|
||||||
let pipeline_url = pipeline.map(|pipeline| pipeline.url.clone());
|
let pipeline_url = pipeline.map(|pipeline| pipeline.url.clone());
|
||||||
let parent_info = pipeline.and_then(|pipeline| pipeline.parent_info);
|
let parent_info = pipeline.and_then(|pipeline| pipeline.parent_info);
|
||||||
(pipeline_url, parent_info)
|
let opener = pipeline.and_then(|pipeline| pipeline.opener);
|
||||||
|
(pipeline_url, parent_info, opener)
|
||||||
};
|
};
|
||||||
|
|
||||||
self.close_browsing_context_children(
|
self.close_browsing_context_children(
|
||||||
|
@ -1575,6 +1583,7 @@ where
|
||||||
browsing_context_id,
|
browsing_context_id,
|
||||||
top_level_browsing_context_id,
|
top_level_browsing_context_id,
|
||||||
parent_info,
|
parent_info,
|
||||||
|
opener,
|
||||||
window_size,
|
window_size,
|
||||||
load_data.clone(),
|
load_data.clone(),
|
||||||
sandbox,
|
sandbox,
|
||||||
|
@ -1645,17 +1654,12 @@ where
|
||||||
fn handle_new_top_level_browsing_context(
|
fn handle_new_top_level_browsing_context(
|
||||||
&mut self,
|
&mut self,
|
||||||
url: ServoUrl,
|
url: ServoUrl,
|
||||||
reply: IpcSender<TopLevelBrowsingContextId>,
|
top_level_browsing_context_id: TopLevelBrowsingContextId
|
||||||
) {
|
) {
|
||||||
let window_size = self.window_size.initial_viewport;
|
let window_size = self.window_size.initial_viewport;
|
||||||
let pipeline_id = PipelineId::new();
|
let pipeline_id = PipelineId::new();
|
||||||
let top_level_browsing_context_id = TopLevelBrowsingContextId::new();
|
let msg = (Some(top_level_browsing_context_id), EmbedderMsg::BrowserCreated(top_level_browsing_context_id));
|
||||||
if let Err(e) = reply.send(top_level_browsing_context_id) {
|
self.embedder_proxy.send(msg);
|
||||||
warn!(
|
|
||||||
"Failed to send newly created top level browsing context ({}).",
|
|
||||||
e
|
|
||||||
);
|
|
||||||
}
|
|
||||||
let browsing_context_id = BrowsingContextId::from(top_level_browsing_context_id);
|
let browsing_context_id = BrowsingContextId::from(top_level_browsing_context_id);
|
||||||
let load_data = LoadData::new(url.clone(), None, None, None);
|
let load_data = LoadData::new(url.clone(), None, None, None);
|
||||||
let sandbox = IFrameSandboxState::IFrameUnsandboxed;
|
let sandbox = IFrameSandboxState::IFrameUnsandboxed;
|
||||||
|
@ -1669,6 +1673,7 @@ where
|
||||||
browsing_context_id,
|
browsing_context_id,
|
||||||
top_level_browsing_context_id,
|
top_level_browsing_context_id,
|
||||||
None,
|
None,
|
||||||
|
None,
|
||||||
Some(window_size),
|
Some(window_size),
|
||||||
load_data.clone(),
|
load_data.clone(),
|
||||||
sandbox,
|
sandbox,
|
||||||
|
@ -1802,6 +1807,7 @@ where
|
||||||
load_info.info.browsing_context_id,
|
load_info.info.browsing_context_id,
|
||||||
load_info.info.top_level_browsing_context_id,
|
load_info.info.top_level_browsing_context_id,
|
||||||
Some(load_info.info.parent_pipeline_id),
|
Some(load_info.info.parent_pipeline_id),
|
||||||
|
None,
|
||||||
window_size,
|
window_size,
|
||||||
load_data.clone(),
|
load_data.clone(),
|
||||||
load_info.sandbox,
|
load_info.sandbox,
|
||||||
|
@ -1847,6 +1853,7 @@ where
|
||||||
browsing_context_id,
|
browsing_context_id,
|
||||||
top_level_browsing_context_id,
|
top_level_browsing_context_id,
|
||||||
Some(parent_pipeline_id),
|
Some(parent_pipeline_id),
|
||||||
|
None,
|
||||||
script_sender,
|
script_sender,
|
||||||
layout_sender,
|
layout_sender,
|
||||||
self.compositor_proxy.clone(),
|
self.compositor_proxy.clone(),
|
||||||
|
@ -1868,6 +1875,52 @@ where
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn handle_script_new_auxiliary(&mut self,
|
||||||
|
load_info: AuxiliaryBrowsingContextLoadInfo,
|
||||||
|
layout_sender: IpcSender<LayoutControlMsg>) {
|
||||||
|
let AuxiliaryBrowsingContextLoadInfo {
|
||||||
|
opener_pipeline_id,
|
||||||
|
new_top_level_browsing_context_id,
|
||||||
|
new_browsing_context_id,
|
||||||
|
new_pipeline_id,
|
||||||
|
} = load_info;
|
||||||
|
|
||||||
|
let url = ServoUrl::parse("about:blank").expect("infallible");
|
||||||
|
|
||||||
|
// TODO: Referrer?
|
||||||
|
let load_data = LoadData::new(url.clone(), None, None, None);
|
||||||
|
|
||||||
|
let pipeline = {
|
||||||
|
let (opener_pipeline, opener_id) = match self.pipelines.get(&opener_pipeline_id) {
|
||||||
|
Some(opener_pipeline) => (opener_pipeline, opener_pipeline.browsing_context_id),
|
||||||
|
None => return warn!("Auxiliary loaded url in closed pipeline {}.", opener_pipeline_id),
|
||||||
|
};
|
||||||
|
let script_sender = opener_pipeline.event_loop.clone();
|
||||||
|
Pipeline::new(new_pipeline_id,
|
||||||
|
new_browsing_context_id,
|
||||||
|
new_top_level_browsing_context_id,
|
||||||
|
None,
|
||||||
|
Some(opener_id),
|
||||||
|
script_sender,
|
||||||
|
layout_sender,
|
||||||
|
self.compositor_proxy.clone(),
|
||||||
|
opener_pipeline.is_private,
|
||||||
|
url,
|
||||||
|
opener_pipeline.visible,
|
||||||
|
load_data)
|
||||||
|
};
|
||||||
|
|
||||||
|
assert!(!self.pipelines.contains_key(&new_pipeline_id));
|
||||||
|
self.pipelines.insert(new_pipeline_id, pipeline);
|
||||||
|
self.joint_session_histories.insert(new_top_level_browsing_context_id, JointSessionHistory::new());
|
||||||
|
self.add_pending_change(SessionHistoryChange {
|
||||||
|
top_level_browsing_context_id: new_top_level_browsing_context_id,
|
||||||
|
browsing_context_id: new_browsing_context_id,
|
||||||
|
new_pipeline_id: new_pipeline_id,
|
||||||
|
replace: None,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
fn handle_pending_paint_metric(&self, pipeline_id: PipelineId, epoch: Epoch) {
|
fn handle_pending_paint_metric(&self, pipeline_id: PipelineId, epoch: Epoch) {
|
||||||
self.compositor_proxy
|
self.compositor_proxy
|
||||||
.send(ToCompositorMsg::PendingPaintMetric(pipeline_id, epoch))
|
.send(ToCompositorMsg::PendingPaintMetric(pipeline_id, epoch))
|
||||||
|
@ -1951,8 +2004,8 @@ where
|
||||||
// requested change so it can update its internal state.
|
// requested change so it can update its internal state.
|
||||||
//
|
//
|
||||||
// If replace is true, the current entry is replaced instead of a new entry being added.
|
// If replace is true, the current entry is replaced instead of a new entry being added.
|
||||||
let (browsing_context_id, parent_info) = match self.pipelines.get(&source_id) {
|
let (browsing_context_id, parent_info, opener) = match self.pipelines.get(&source_id) {
|
||||||
Some(pipeline) => (pipeline.browsing_context_id, pipeline.parent_info),
|
Some(pipeline) => (pipeline.browsing_context_id, pipeline.parent_info, pipeline.opener),
|
||||||
None => {
|
None => {
|
||||||
warn!("Pipeline {} loaded after closure.", source_id);
|
warn!("Pipeline {} loaded after closure.", source_id);
|
||||||
return None;
|
return None;
|
||||||
|
@ -2029,6 +2082,7 @@ where
|
||||||
browsing_context_id,
|
browsing_context_id,
|
||||||
top_level_id,
|
top_level_id,
|
||||||
None,
|
None,
|
||||||
|
opener,
|
||||||
window_size,
|
window_size,
|
||||||
load_data.clone(),
|
load_data.clone(),
|
||||||
sandbox,
|
sandbox,
|
||||||
|
@ -2313,19 +2367,21 @@ where
|
||||||
// TODO: Save the sandbox state so it can be restored here.
|
// TODO: Save the sandbox state so it can be restored here.
|
||||||
let sandbox = IFrameSandboxState::IFrameUnsandboxed;
|
let sandbox = IFrameSandboxState::IFrameUnsandboxed;
|
||||||
let new_pipeline_id = PipelineId::new();
|
let new_pipeline_id = PipelineId::new();
|
||||||
let (top_level_id, parent_info, window_size, is_private) =
|
let (top_level_id, parent_info, opener, window_size, is_private) =
|
||||||
match self.browsing_contexts.get(&browsing_context_id) {
|
match self.browsing_contexts.get(&browsing_context_id) {
|
||||||
Some(browsing_context) => {
|
Some(browsing_context) => {
|
||||||
match self.pipelines.get(&browsing_context.pipeline_id) {
|
match self.pipelines.get(&browsing_context.pipeline_id) {
|
||||||
Some(pipeline) => (
|
Some(pipeline) => (
|
||||||
browsing_context.top_level_id,
|
browsing_context.top_level_id,
|
||||||
pipeline.parent_info,
|
pipeline.parent_info,
|
||||||
|
pipeline.opener,
|
||||||
browsing_context.size,
|
browsing_context.size,
|
||||||
pipeline.is_private,
|
pipeline.is_private,
|
||||||
),
|
),
|
||||||
None => (
|
None => (
|
||||||
browsing_context.top_level_id,
|
browsing_context.top_level_id,
|
||||||
None,
|
None,
|
||||||
|
None,
|
||||||
browsing_context.size,
|
browsing_context.size,
|
||||||
false,
|
false,
|
||||||
),
|
),
|
||||||
|
@ -2338,6 +2394,7 @@ where
|
||||||
browsing_context_id,
|
browsing_context_id,
|
||||||
top_level_id,
|
top_level_id,
|
||||||
parent_info,
|
parent_info,
|
||||||
|
opener,
|
||||||
window_size,
|
window_size,
|
||||||
load_data.clone(),
|
load_data.clone(),
|
||||||
sandbox,
|
sandbox,
|
||||||
|
@ -3487,10 +3544,6 @@ where
|
||||||
session_history.remove_entries_for_browsing_context(browsing_context_id);
|
session_history.remove_entries_for_browsing_context(browsing_context_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if BrowsingContextId::from(browsing_context.top_level_id) == browsing_context_id {
|
|
||||||
self.event_loops.remove(&browsing_context.top_level_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
let parent_info = self
|
let parent_info = self
|
||||||
.pipelines
|
.pipelines
|
||||||
.get(&browsing_context.pipeline_id)
|
.get(&browsing_context.pipeline_id)
|
||||||
|
|
|
@ -62,6 +62,8 @@ pub struct Pipeline {
|
||||||
/// TODO: move this field to `BrowsingContext`.
|
/// TODO: move this field to `BrowsingContext`.
|
||||||
pub parent_info: Option<PipelineId>,
|
pub parent_info: Option<PipelineId>,
|
||||||
|
|
||||||
|
pub opener: Option<BrowsingContextId>,
|
||||||
|
|
||||||
/// The event loop handling this pipeline.
|
/// The event loop handling this pipeline.
|
||||||
pub event_loop: Rc<EventLoop>,
|
pub event_loop: Rc<EventLoop>,
|
||||||
|
|
||||||
|
@ -119,6 +121,8 @@ pub struct InitialPipelineState {
|
||||||
/// If `None`, this is the root.
|
/// If `None`, this is the root.
|
||||||
pub parent_info: Option<PipelineId>,
|
pub parent_info: Option<PipelineId>,
|
||||||
|
|
||||||
|
pub opener: Option<BrowsingContextId>,
|
||||||
|
|
||||||
/// A channel to the associated constellation.
|
/// A channel to the associated constellation.
|
||||||
pub script_to_constellation_chan: ScriptToConstellationChan,
|
pub script_to_constellation_chan: ScriptToConstellationChan,
|
||||||
|
|
||||||
|
@ -216,6 +220,7 @@ impl Pipeline {
|
||||||
new_pipeline_id: state.id,
|
new_pipeline_id: state.id,
|
||||||
browsing_context_id: state.browsing_context_id,
|
browsing_context_id: state.browsing_context_id,
|
||||||
top_level_browsing_context_id: state.top_level_browsing_context_id,
|
top_level_browsing_context_id: state.top_level_browsing_context_id,
|
||||||
|
opener: state.opener,
|
||||||
load_data: state.load_data.clone(),
|
load_data: state.load_data.clone(),
|
||||||
window_size: window_size,
|
window_size: window_size,
|
||||||
pipeline_port: pipeline_port,
|
pipeline_port: pipeline_port,
|
||||||
|
@ -266,6 +271,7 @@ impl Pipeline {
|
||||||
browsing_context_id: state.browsing_context_id,
|
browsing_context_id: state.browsing_context_id,
|
||||||
top_level_browsing_context_id: state.top_level_browsing_context_id,
|
top_level_browsing_context_id: state.top_level_browsing_context_id,
|
||||||
parent_info: state.parent_info,
|
parent_info: state.parent_info,
|
||||||
|
opener: state.opener,
|
||||||
script_to_constellation_chan: state.script_to_constellation_chan.clone(),
|
script_to_constellation_chan: state.script_to_constellation_chan.clone(),
|
||||||
scheduler_chan: state.scheduler_chan,
|
scheduler_chan: state.scheduler_chan,
|
||||||
devtools_chan: script_to_devtools_chan,
|
devtools_chan: script_to_devtools_chan,
|
||||||
|
@ -312,6 +318,7 @@ impl Pipeline {
|
||||||
state.browsing_context_id,
|
state.browsing_context_id,
|
||||||
state.top_level_browsing_context_id,
|
state.top_level_browsing_context_id,
|
||||||
state.parent_info,
|
state.parent_info,
|
||||||
|
state.opener,
|
||||||
script_chan,
|
script_chan,
|
||||||
pipeline_chan,
|
pipeline_chan,
|
||||||
state.compositor_proxy,
|
state.compositor_proxy,
|
||||||
|
@ -329,6 +336,7 @@ impl Pipeline {
|
||||||
browsing_context_id: BrowsingContextId,
|
browsing_context_id: BrowsingContextId,
|
||||||
top_level_browsing_context_id: TopLevelBrowsingContextId,
|
top_level_browsing_context_id: TopLevelBrowsingContextId,
|
||||||
parent_info: Option<PipelineId>,
|
parent_info: Option<PipelineId>,
|
||||||
|
opener: Option<BrowsingContextId>,
|
||||||
event_loop: Rc<EventLoop>,
|
event_loop: Rc<EventLoop>,
|
||||||
layout_chan: IpcSender<LayoutControlMsg>,
|
layout_chan: IpcSender<LayoutControlMsg>,
|
||||||
compositor_proxy: CompositorProxy,
|
compositor_proxy: CompositorProxy,
|
||||||
|
@ -342,6 +350,7 @@ impl Pipeline {
|
||||||
browsing_context_id: browsing_context_id,
|
browsing_context_id: browsing_context_id,
|
||||||
top_level_browsing_context_id: top_level_browsing_context_id,
|
top_level_browsing_context_id: top_level_browsing_context_id,
|
||||||
parent_info: parent_info,
|
parent_info: parent_info,
|
||||||
|
opener: opener,
|
||||||
event_loop: event_loop,
|
event_loop: event_loop,
|
||||||
layout_chan: layout_chan,
|
layout_chan: layout_chan,
|
||||||
compositor_proxy: compositor_proxy,
|
compositor_proxy: compositor_proxy,
|
||||||
|
@ -469,6 +478,7 @@ pub struct UnprivilegedPipelineContent {
|
||||||
top_level_browsing_context_id: TopLevelBrowsingContextId,
|
top_level_browsing_context_id: TopLevelBrowsingContextId,
|
||||||
browsing_context_id: BrowsingContextId,
|
browsing_context_id: BrowsingContextId,
|
||||||
parent_info: Option<PipelineId>,
|
parent_info: Option<PipelineId>,
|
||||||
|
opener: Option<BrowsingContextId>,
|
||||||
script_to_constellation_chan: ScriptToConstellationChan,
|
script_to_constellation_chan: ScriptToConstellationChan,
|
||||||
layout_to_constellation_chan: IpcSender<LayoutMsg>,
|
layout_to_constellation_chan: IpcSender<LayoutMsg>,
|
||||||
scheduler_chan: IpcSender<TimerSchedulerMsg>,
|
scheduler_chan: IpcSender<TimerSchedulerMsg>,
|
||||||
|
@ -517,6 +527,7 @@ impl UnprivilegedPipelineContent {
|
||||||
browsing_context_id: self.browsing_context_id,
|
browsing_context_id: self.browsing_context_id,
|
||||||
top_level_browsing_context_id: self.top_level_browsing_context_id,
|
top_level_browsing_context_id: self.top_level_browsing_context_id,
|
||||||
parent_info: self.parent_info,
|
parent_info: self.parent_info,
|
||||||
|
opener: self.opener,
|
||||||
control_chan: self.script_chan.clone(),
|
control_chan: self.script_chan.clone(),
|
||||||
control_port: self.script_port,
|
control_port: self.script_port,
|
||||||
script_to_constellation_chan: self.script_to_constellation_chan.clone(),
|
script_to_constellation_chan: self.script_to_constellation_chan.clone(),
|
||||||
|
|
|
@ -84,6 +84,10 @@ pub enum EmbedderMsg {
|
||||||
Alert(String, IpcSender<()>),
|
Alert(String, IpcSender<()>),
|
||||||
/// Wether or not to follow a link
|
/// Wether or not to follow a link
|
||||||
AllowNavigation(ServoUrl, IpcSender<bool>),
|
AllowNavigation(ServoUrl, IpcSender<bool>),
|
||||||
|
/// Whether or not to allow script to open a new tab/browser
|
||||||
|
AllowOpeningBrowser(IpcSender<bool>),
|
||||||
|
/// A new browser was created by script
|
||||||
|
BrowserCreated(TopLevelBrowsingContextId),
|
||||||
/// Wether or not to unload a document
|
/// Wether or not to unload a document
|
||||||
AllowUnload(IpcSender<bool>),
|
AllowUnload(IpcSender<bool>),
|
||||||
/// Sends an unconsumed key event back to the embedder.
|
/// Sends an unconsumed key event back to the embedder.
|
||||||
|
@ -143,6 +147,8 @@ impl Debug for EmbedderMsg {
|
||||||
EmbedderMsg::ShowIME(..) => write!(f, "ShowIME"),
|
EmbedderMsg::ShowIME(..) => write!(f, "ShowIME"),
|
||||||
EmbedderMsg::HideIME => write!(f, "HideIME"),
|
EmbedderMsg::HideIME => write!(f, "HideIME"),
|
||||||
EmbedderMsg::Shutdown => write!(f, "Shutdown"),
|
EmbedderMsg::Shutdown => write!(f, "Shutdown"),
|
||||||
|
EmbedderMsg::AllowOpeningBrowser(..) => write!(f, "AllowOpeningBrowser"),
|
||||||
|
EmbedderMsg::BrowserCreated(..) => write!(f, "BrowserCreated")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -574,45 +574,61 @@ impl Activatable for HTMLAnchorElement {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <https://html.spec.whatwg.org/multipage/#the-rules-for-choosing-a-browsing-context-given-a-browsing-context-name>
|
|
||||||
fn is_current_browsing_context(target: DOMString) -> bool {
|
|
||||||
target.is_empty() || target == "_self"
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <https://html.spec.whatwg.org/multipage/#following-hyperlinks-2>
|
/// <https://html.spec.whatwg.org/multipage/#following-hyperlinks-2>
|
||||||
pub fn follow_hyperlink(subject: &Element, hyperlink_suffix: Option<String>, referrer_policy: Option<ReferrerPolicy>) {
|
pub fn follow_hyperlink(subject: &Element, hyperlink_suffix: Option<String>, referrer_policy: Option<ReferrerPolicy>) {
|
||||||
// Step 1: replace.
|
// Step 1: TODO: If subject cannot navigate, then return.
|
||||||
// Step 2: source browsing context.
|
// Step 2, done in Step 7.
|
||||||
// Step 3: target browsing context.
|
|
||||||
let target = subject.get_attribute(&ns!(), &local_name!("target"));
|
|
||||||
|
|
||||||
// Step 4: disown target's opener if needed.
|
|
||||||
let attribute = subject.get_attribute(&ns!(), &local_name!("href")).unwrap();
|
|
||||||
let mut href = attribute.Value();
|
|
||||||
|
|
||||||
// Step 7: append a hyperlink suffix.
|
|
||||||
// https://www.w3.org/Bugs/Public/show_bug.cgi?id=28925
|
|
||||||
if let Some(suffix) = hyperlink_suffix {
|
|
||||||
href.push_str(&suffix);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 5: parse the URL.
|
|
||||||
// Step 6: navigate to an error document if parsing failed.
|
|
||||||
let document = document_from_node(subject);
|
let document = document_from_node(subject);
|
||||||
let url = match document.url().join(&href) {
|
let window = document.window();
|
||||||
Ok(url) => url,
|
|
||||||
Err(_) => return,
|
// Step 3: source browsing context.
|
||||||
|
let source = document.browsing_context().unwrap();
|
||||||
|
|
||||||
|
// Step 4-5: target attribute.
|
||||||
|
let target_attribute_value = subject.get_attribute(&ns!(), &local_name!("target"));
|
||||||
|
|
||||||
|
// Step 6.
|
||||||
|
let noopener = if let Some(link_types) = subject.get_attribute(&ns!(), &local_name!("rel")) {
|
||||||
|
let values = link_types.Value();
|
||||||
|
let contains_noopener = values.contains("noopener");
|
||||||
|
let contains_noreferrer = values.contains("noreferrer");
|
||||||
|
contains_noreferrer || contains_noopener
|
||||||
|
} else {
|
||||||
|
false
|
||||||
};
|
};
|
||||||
|
|
||||||
// Step 8: navigate to the URL.
|
// Step 7.
|
||||||
if let Some(target) = target {
|
let (maybe_chosen, replace) = match target_attribute_value {
|
||||||
if !is_current_browsing_context(target.Value()) {
|
Some(name) => source.choose_browsing_context(name.Value(), noopener),
|
||||||
// https://github.com/servo/servo/issues/13241
|
None => (Some(window.window_proxy()), false)
|
||||||
|
};
|
||||||
|
let chosen = match maybe_chosen {
|
||||||
|
Some(proxy) => proxy,
|
||||||
|
None => return,
|
||||||
|
};
|
||||||
|
if let Some(target_document) = chosen.document() {
|
||||||
|
let target_window = target_document.window();
|
||||||
|
|
||||||
|
// Step 9, dis-owning target's opener, if necessary
|
||||||
|
// will have been done as part of Step 7 above
|
||||||
|
// in choose_browsing_context/create_auxiliary_browsing_context.
|
||||||
|
|
||||||
|
// Step 10, 11, 12, 13. TODO: if parsing the URL failed, navigate to error page.
|
||||||
|
let attribute = subject.get_attribute(&ns!(), &local_name!("href")).unwrap();
|
||||||
|
let mut href = attribute.Value();
|
||||||
|
// Step 12: append a hyperlink suffix.
|
||||||
|
// https://www.w3.org/Bugs/Public/show_bug.cgi?id=28925
|
||||||
|
if let Some(suffix) = hyperlink_suffix {
|
||||||
|
href.push_str(&suffix);
|
||||||
}
|
}
|
||||||
}
|
let url = match document.url().join(&href) {
|
||||||
|
Ok(url) => url,
|
||||||
|
Err(_) => return,
|
||||||
|
};
|
||||||
|
|
||||||
debug!("following hyperlink to {}", url);
|
// Step 13, 14.
|
||||||
|
debug!("following hyperlink to {}", url);
|
||||||
let window = document.window();
|
target_window.load_url(url, replace, false, referrer_policy);
|
||||||
window.load_url(url, false, false, referrer_policy);
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,6 +41,7 @@ use dom::node::{Node, NodeFlags, UnbindContext, VecPreOrderInsertionHelper};
|
||||||
use dom::node::{document_from_node, window_from_node};
|
use dom::node::{document_from_node, window_from_node};
|
||||||
use dom::validitystate::ValidationFlags;
|
use dom::validitystate::ValidationFlags;
|
||||||
use dom::virtualmethods::VirtualMethods;
|
use dom::virtualmethods::VirtualMethods;
|
||||||
|
use dom::window::Window;
|
||||||
use dom_struct::dom_struct;
|
use dom_struct::dom_struct;
|
||||||
use encoding_rs::{Encoding, UTF_8};
|
use encoding_rs::{Encoding, UTF_8};
|
||||||
use html5ever::{LocalName, Prefix};
|
use html5ever::{LocalName, Prefix};
|
||||||
|
@ -337,10 +338,24 @@ impl HTMLFormElement {
|
||||||
let scheme = action_components.scheme().to_owned();
|
let scheme = action_components.scheme().to_owned();
|
||||||
let enctype = submitter.enctype();
|
let enctype = submitter.enctype();
|
||||||
let method = submitter.method();
|
let method = submitter.method();
|
||||||
let _target = submitter.target();
|
|
||||||
// TODO: Handle browsing contexts, partially loaded documents (step 16-17)
|
|
||||||
|
|
||||||
let mut load_data = LoadData::new(action_components, None, doc.get_referrer_policy(), Some(doc.url()));
|
// Step 16, 17
|
||||||
|
let target_attribute_value = submitter.target();
|
||||||
|
let source = doc.browsing_context().unwrap();
|
||||||
|
let (maybe_chosen, _new) = source.choose_browsing_context(target_attribute_value, false);
|
||||||
|
let chosen = match maybe_chosen {
|
||||||
|
Some(proxy) => proxy,
|
||||||
|
None => return
|
||||||
|
};
|
||||||
|
let target_document = match chosen.document() {
|
||||||
|
Some(doc) => doc,
|
||||||
|
None => return
|
||||||
|
};
|
||||||
|
let target_window = target_document.window();
|
||||||
|
let mut load_data = LoadData::new(action_components,
|
||||||
|
None,
|
||||||
|
target_document.get_referrer_policy(),
|
||||||
|
Some(target_document.url()));
|
||||||
|
|
||||||
// Step 18
|
// Step 18
|
||||||
match (&*scheme, method) {
|
match (&*scheme, method) {
|
||||||
|
@ -351,17 +366,17 @@ impl HTMLFormElement {
|
||||||
// https://html.spec.whatwg.org/multipage/#submit-mutate-action
|
// https://html.spec.whatwg.org/multipage/#submit-mutate-action
|
||||||
("http", FormMethod::FormGet) | ("https", FormMethod::FormGet) | ("data", FormMethod::FormGet) => {
|
("http", FormMethod::FormGet) | ("https", FormMethod::FormGet) | ("data", FormMethod::FormGet) => {
|
||||||
load_data.headers.set(ContentType::form_url_encoded());
|
load_data.headers.set(ContentType::form_url_encoded());
|
||||||
self.mutate_action_url(&mut form_data, load_data, encoding);
|
self.mutate_action_url(&mut form_data, load_data, encoding, &target_window);
|
||||||
}
|
}
|
||||||
// https://html.spec.whatwg.org/multipage/#submit-body
|
// https://html.spec.whatwg.org/multipage/#submit-body
|
||||||
("http", FormMethod::FormPost) | ("https", FormMethod::FormPost) => {
|
("http", FormMethod::FormPost) | ("https", FormMethod::FormPost) => {
|
||||||
load_data.method = Method::Post;
|
load_data.method = Method::Post;
|
||||||
self.submit_entity_body(&mut form_data, load_data, enctype, encoding);
|
self.submit_entity_body(&mut form_data, load_data, enctype, encoding, &target_window);
|
||||||
}
|
}
|
||||||
// https://html.spec.whatwg.org/multipage/#submit-get-action
|
// https://html.spec.whatwg.org/multipage/#submit-get-action
|
||||||
("file", _) | ("about", _) | ("data", FormMethod::FormPost) |
|
("file", _) | ("about", _) | ("data", FormMethod::FormPost) |
|
||||||
("ftp", _) | ("javascript", _) => {
|
("ftp", _) | ("javascript", _) => {
|
||||||
self.plan_to_navigate(load_data);
|
self.plan_to_navigate(load_data, &target_window);
|
||||||
}
|
}
|
||||||
("mailto", FormMethod::FormPost) => {
|
("mailto", FormMethod::FormPost) => {
|
||||||
// TODO: Mail as body
|
// TODO: Mail as body
|
||||||
|
@ -376,7 +391,11 @@ impl HTMLFormElement {
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#submit-mutate-action
|
// https://html.spec.whatwg.org/multipage/#submit-mutate-action
|
||||||
fn mutate_action_url(&self, form_data: &mut Vec<FormDatum>, mut load_data: LoadData, encoding: &'static Encoding) {
|
fn mutate_action_url(&self,
|
||||||
|
form_data: &mut Vec<FormDatum>,
|
||||||
|
mut load_data: LoadData,
|
||||||
|
encoding: &'static Encoding,
|
||||||
|
target: &Window) {
|
||||||
let charset = encoding.name();
|
let charset = encoding.name();
|
||||||
|
|
||||||
self.set_encoding_override(load_data.url.as_mut_url().query_pairs_mut())
|
self.set_encoding_override(load_data.url.as_mut_url().query_pairs_mut())
|
||||||
|
@ -384,12 +403,16 @@ impl HTMLFormElement {
|
||||||
.extend_pairs(form_data.into_iter()
|
.extend_pairs(form_data.into_iter()
|
||||||
.map(|field| (field.name.clone(), field.replace_value(charset))));
|
.map(|field| (field.name.clone(), field.replace_value(charset))));
|
||||||
|
|
||||||
self.plan_to_navigate(load_data);
|
self.plan_to_navigate(load_data, target);
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#submit-body
|
// https://html.spec.whatwg.org/multipage/#submit-body
|
||||||
fn submit_entity_body(&self, form_data: &mut Vec<FormDatum>, mut load_data: LoadData,
|
fn submit_entity_body(&self,
|
||||||
enctype: FormEncType, encoding: &'static Encoding) {
|
form_data: &mut Vec<FormDatum>,
|
||||||
|
mut load_data: LoadData,
|
||||||
|
enctype: FormEncType,
|
||||||
|
encoding: &'static Encoding,
|
||||||
|
target: &Window) {
|
||||||
let boundary = generate_boundary();
|
let boundary = generate_boundary();
|
||||||
let bytes = match enctype {
|
let bytes = match enctype {
|
||||||
FormEncType::UrlEncoded => {
|
FormEncType::UrlEncoded => {
|
||||||
|
@ -415,7 +438,7 @@ impl HTMLFormElement {
|
||||||
};
|
};
|
||||||
|
|
||||||
load_data.data = Some(bytes);
|
load_data.data = Some(bytes);
|
||||||
self.plan_to_navigate(load_data);
|
self.plan_to_navigate(load_data, target);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_encoding_override<'a>(&self, mut serializer: Serializer<UrlQuery<'a>>)
|
fn set_encoding_override<'a>(&self, mut serializer: Serializer<UrlQuery<'a>>)
|
||||||
|
@ -426,9 +449,7 @@ impl HTMLFormElement {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// [Planned navigation](https://html.spec.whatwg.org/multipage/#planned-navigation)
|
/// [Planned navigation](https://html.spec.whatwg.org/multipage/#planned-navigation)
|
||||||
fn plan_to_navigate(&self, load_data: LoadData) {
|
fn plan_to_navigate(&self, load_data: LoadData, target: &Window) {
|
||||||
let window = window_from_node(self);
|
|
||||||
|
|
||||||
// Step 1
|
// Step 1
|
||||||
// Each planned navigation task is tagged with a generation ID, and
|
// Each planned navigation task is tagged with a generation ID, and
|
||||||
// before the task is handled, it first checks whether the HTMLFormElement's
|
// before the task is handled, it first checks whether the HTMLFormElement's
|
||||||
|
@ -437,8 +458,8 @@ impl HTMLFormElement {
|
||||||
self.generation_id.set(generation_id);
|
self.generation_id.set(generation_id);
|
||||||
|
|
||||||
// Step 2.
|
// Step 2.
|
||||||
let pipeline_id = window.upcast::<GlobalScope>().pipeline_id();
|
let pipeline_id = target.upcast::<GlobalScope>().pipeline_id();
|
||||||
let script_chan = window.main_thread_script_chan().clone();
|
let script_chan = target.main_thread_script_chan().clone();
|
||||||
let this = Trusted::new(self);
|
let this = Trusted::new(self);
|
||||||
let task = task!(navigate_to_form_planned_navigation: move || {
|
let task = task!(navigate_to_form_planned_navigation: move || {
|
||||||
if generation_id != this.root().generation_id.get() {
|
if generation_id != this.root().generation_id.get() {
|
||||||
|
@ -452,7 +473,7 @@ impl HTMLFormElement {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Step 3.
|
// Step 3.
|
||||||
window.dom_manipulation_task_source().queue(task, window.upcast()).unwrap();
|
target.dom_manipulation_task_source().queue(task, target.upcast()).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Interactively validate the constraints of form elements
|
/// Interactively validate the constraints of form elements
|
||||||
|
|
|
@ -76,6 +76,7 @@ pub struct HTMLIFrameElement {
|
||||||
sandbox_allowance: Cell<Option<SandboxAllowance>>,
|
sandbox_allowance: Cell<Option<SandboxAllowance>>,
|
||||||
load_blocker: DomRefCell<Option<LoadBlocker>>,
|
load_blocker: DomRefCell<Option<LoadBlocker>>,
|
||||||
visibility: Cell<bool>,
|
visibility: Cell<bool>,
|
||||||
|
name: DomRefCell<DOMString>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HTMLIFrameElement {
|
impl HTMLIFrameElement {
|
||||||
|
@ -177,6 +178,7 @@ impl HTMLIFrameElement {
|
||||||
new_pipeline_id: new_pipeline_id,
|
new_pipeline_id: new_pipeline_id,
|
||||||
browsing_context_id: browsing_context_id,
|
browsing_context_id: browsing_context_id,
|
||||||
top_level_browsing_context_id: top_level_browsing_context_id,
|
top_level_browsing_context_id: top_level_browsing_context_id,
|
||||||
|
opener: None,
|
||||||
load_data: load_data.unwrap(),
|
load_data: load_data.unwrap(),
|
||||||
pipeline_port: pipeline_receiver,
|
pipeline_port: pipeline_receiver,
|
||||||
content_process_shutdown_chan: None,
|
content_process_shutdown_chan: None,
|
||||||
|
@ -222,6 +224,16 @@ impl HTMLIFrameElement {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://html.spec.whatwg.org/multipage/#attr-iframe-name
|
||||||
|
// Note: the spec says to set the name 'when the nested browsing context is created'.
|
||||||
|
// The current implementation sets the name on the window,
|
||||||
|
// when the iframe attributes are first processed.
|
||||||
|
if mode == ProcessingMode::FirstTime {
|
||||||
|
if let Some(window) = self.GetContentWindow() {
|
||||||
|
window.set_name(self.name.borrow().clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let url = self.get_url();
|
let url = self.get_url();
|
||||||
|
|
||||||
// TODO: check ancestor browsing contexts for same URL
|
// TODO: check ancestor browsing contexts for same URL
|
||||||
|
@ -298,6 +310,7 @@ impl HTMLIFrameElement {
|
||||||
sandbox_allowance: Cell::new(None),
|
sandbox_allowance: Cell::new(None),
|
||||||
load_blocker: DomRefCell::new(None),
|
load_blocker: DomRefCell::new(None),
|
||||||
visibility: Cell::new(true),
|
visibility: Cell::new(true),
|
||||||
|
name: DomRefCell::new(DOMString::new())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -470,6 +483,7 @@ impl HTMLIFrameElementMethods for HTMLIFrameElement {
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#dom-iframe-name
|
// https://html.spec.whatwg.org/multipage/#dom-iframe-name
|
||||||
fn SetName(&self, name: DOMString) {
|
fn SetName(&self, name: DOMString) {
|
||||||
|
*self.name.borrow_mut() = name.clone();
|
||||||
if let Some(window) = self.GetContentWindow() {
|
if let Some(window) = self.GetContentWindow() {
|
||||||
window.set_name(name)
|
window.set_name(name)
|
||||||
}
|
}
|
||||||
|
@ -480,7 +494,7 @@ impl HTMLIFrameElementMethods for HTMLIFrameElement {
|
||||||
if let Some(window) = self.GetContentWindow() {
|
if let Some(window) = self.GetContentWindow() {
|
||||||
window.get_name()
|
window.get_name()
|
||||||
} else {
|
} else {
|
||||||
DOMString::new()
|
self.name.borrow().clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,13 +35,13 @@
|
||||||
// Note that this can return null in the case that the browsing context has been discarded.
|
// Note that this can return null in the case that the browsing context has been discarded.
|
||||||
// https://github.com/whatwg/html/issues/2115
|
// https://github.com/whatwg/html/issues/2115
|
||||||
[Unforgeable] readonly attribute WindowProxy? top;
|
[Unforgeable] readonly attribute WindowProxy? top;
|
||||||
// attribute any opener;
|
attribute any opener;
|
||||||
// Note that this can return null in the case that the browsing context has been discarded.
|
// Note that this can return null in the case that the browsing context has been discarded.
|
||||||
// https://github.com/whatwg/html/issues/2115
|
// https://github.com/whatwg/html/issues/2115
|
||||||
[Replaceable] readonly attribute WindowProxy? parent;
|
[Replaceable] readonly attribute WindowProxy? parent;
|
||||||
readonly attribute Element? frameElement;
|
readonly attribute Element? frameElement;
|
||||||
//WindowProxy open(optional DOMString url = "about:blank", optional DOMString target = "_blank",
|
WindowProxy? open(optional DOMString url = "about:blank", optional DOMString target = "_blank",
|
||||||
// optional DOMString features = "", optional boolean replace = false);
|
optional DOMString features = "");
|
||||||
//getter WindowProxy (unsigned long index);
|
//getter WindowProxy (unsigned long index);
|
||||||
|
|
||||||
// https://github.com/servo/servo/issues/14453
|
// https://github.com/servo/servo/issues/14453
|
||||||
|
|
|
@ -61,10 +61,12 @@ use fetch;
|
||||||
use ipc_channel::ipc::IpcSender;
|
use ipc_channel::ipc::IpcSender;
|
||||||
use ipc_channel::router::ROUTER;
|
use ipc_channel::router::ROUTER;
|
||||||
use js::jsapi::{JSAutoCompartment, JSContext};
|
use js::jsapi::{JSAutoCompartment, JSContext};
|
||||||
use js::jsapi::{JS_GC, JS_GetRuntime};
|
use js::jsapi::{JS_GC, JS_GetRuntime, JSPROP_ENUMERATE};
|
||||||
use js::jsval::UndefinedValue;
|
use js::jsval::{JSVal, UndefinedValue};
|
||||||
use js::rust::HandleValue;
|
use js::rust::HandleValue;
|
||||||
|
use js::rust::wrappers::JS_DefineProperty;
|
||||||
use layout_image::fetch_image_for_layout;
|
use layout_image::fetch_image_for_layout;
|
||||||
|
use libc;
|
||||||
use microtask::MicrotaskQueue;
|
use microtask::MicrotaskQueue;
|
||||||
use msg::constellation_msg::PipelineId;
|
use msg::constellation_msg::PipelineId;
|
||||||
use net_traits::{ResourceThreads, ReferrerPolicy};
|
use net_traits::{ResourceThreads, ReferrerPolicy};
|
||||||
|
@ -565,6 +567,39 @@ impl WindowMethods for Window {
|
||||||
doc.abort();
|
doc.abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://html.spec.whatwg.org/multipage/#dom-open
|
||||||
|
fn Open(&self,
|
||||||
|
url: DOMString,
|
||||||
|
target: DOMString,
|
||||||
|
features: DOMString)
|
||||||
|
-> Option<DomRoot<WindowProxy>> {
|
||||||
|
self.window_proxy().open(url, target, features)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unsafe_code)]
|
||||||
|
// https://html.spec.whatwg.org/multipage/#dom-opener
|
||||||
|
unsafe fn Opener(&self, cx: *mut JSContext) -> JSVal {
|
||||||
|
self.window_proxy().opener(cx)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unsafe_code)]
|
||||||
|
// https://html.spec.whatwg.org/multipage/#dom-opener
|
||||||
|
unsafe fn SetOpener(&self, cx: *mut JSContext, value: HandleValue) {
|
||||||
|
// Step 1.
|
||||||
|
if value.is_null() {
|
||||||
|
return self.window_proxy().disown();
|
||||||
|
}
|
||||||
|
// Step 2.
|
||||||
|
let obj = self.reflector().get_jsobject();
|
||||||
|
assert!(JS_DefineProperty(cx,
|
||||||
|
obj,
|
||||||
|
"opener\0".as_ptr() as *const libc::c_char,
|
||||||
|
value,
|
||||||
|
JSPROP_ENUMERATE,
|
||||||
|
None,
|
||||||
|
None));
|
||||||
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#dom-window-closed
|
// https://html.spec.whatwg.org/multipage/#dom-window-closed
|
||||||
fn Closed(&self) -> bool {
|
fn Closed(&self) -> bool {
|
||||||
self.window_proxy.get()
|
self.window_proxy.get()
|
||||||
|
@ -574,13 +609,13 @@ impl WindowMethods for Window {
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#dom-window-close
|
// https://html.spec.whatwg.org/multipage/#dom-window-close
|
||||||
fn Close(&self) {
|
fn Close(&self) {
|
||||||
|
let window_proxy = self.window_proxy();
|
||||||
// Note: check the length of the "session history", as opposed to the joint session history?
|
// Note: check the length of the "session history", as opposed to the joint session history?
|
||||||
// see https://github.com/whatwg/html/issues/3734
|
// see https://github.com/whatwg/html/issues/3734
|
||||||
if let Ok(history_length) = self.History().GetLength() {
|
if let Ok(history_length) = self.History().GetLength() {
|
||||||
// TODO: allow auxilliary browsing contexts created by script to be script-closeable,
|
let is_auxiliary = window_proxy.is_auxiliary();
|
||||||
// regardless of history length.
|
|
||||||
// https://html.spec.whatwg.org/multipage/#script-closable
|
// https://html.spec.whatwg.org/multipage/#script-closable
|
||||||
let is_script_closable = self.is_top_level() && history_length == 1;
|
let is_script_closable = (self.is_top_level() && history_length == 1) || is_auxiliary;
|
||||||
if is_script_closable {
|
if is_script_closable {
|
||||||
let doc = self.Document();
|
let doc = self.Document();
|
||||||
// https://html.spec.whatwg.org/multipage/#closing-browsing-contexts
|
// https://html.spec.whatwg.org/multipage/#closing-browsing-contexts
|
||||||
|
|
|
@ -13,10 +13,12 @@ use dom::bindings::str::DOMString;
|
||||||
use dom::bindings::trace::JSTraceable;
|
use dom::bindings::trace::JSTraceable;
|
||||||
use dom::bindings::utils::{WindowProxyHandler, get_array_index_from_id, AsVoidPtr};
|
use dom::bindings::utils::{WindowProxyHandler, get_array_index_from_id, AsVoidPtr};
|
||||||
use dom::dissimilaroriginwindow::DissimilarOriginWindow;
|
use dom::dissimilaroriginwindow::DissimilarOriginWindow;
|
||||||
|
use dom::document::Document;
|
||||||
use dom::element::Element;
|
use dom::element::Element;
|
||||||
use dom::globalscope::GlobalScope;
|
use dom::globalscope::GlobalScope;
|
||||||
use dom::window::Window;
|
use dom::window::Window;
|
||||||
use dom_struct::dom_struct;
|
use dom_struct::dom_struct;
|
||||||
|
use embedder_traits::EmbedderMsg;
|
||||||
use ipc_channel::ipc;
|
use ipc_channel::ipc;
|
||||||
use js::JSCLASS_IS_GLOBAL;
|
use js::JSCLASS_IS_GLOBAL;
|
||||||
use js::glue::{CreateWrapperProxyHandler, ProxyTraps};
|
use js::glue::{CreateWrapperProxyHandler, ProxyTraps};
|
||||||
|
@ -34,7 +36,7 @@ use js::jsapi::HandleValue as RawHandleValue;
|
||||||
use js::jsapi::MutableHandle as RawMutableHandle;
|
use js::jsapi::MutableHandle as RawMutableHandle;
|
||||||
use js::jsapi::MutableHandleObject as RawMutableHandleObject;
|
use js::jsapi::MutableHandleObject as RawMutableHandleObject;
|
||||||
use js::jsapi::MutableHandleValue as RawMutableHandleValue;
|
use js::jsapi::MutableHandleValue as RawMutableHandleValue;
|
||||||
use js::jsval::{UndefinedValue, PrivateValue};
|
use js::jsval::{JSVal, NullValue, UndefinedValue, PrivateValue};
|
||||||
use js::rust::{Handle, MutableHandle};
|
use js::rust::{Handle, MutableHandle};
|
||||||
use js::rust::get_object_class;
|
use js::rust::get_object_class;
|
||||||
use js::rust::wrappers::{NewWindowProxy, SetWindowProxy, JS_TransplantObject};
|
use js::rust::wrappers::{NewWindowProxy, SetWindowProxy, JS_TransplantObject};
|
||||||
|
@ -42,7 +44,9 @@ use msg::constellation_msg::BrowsingContextId;
|
||||||
use msg::constellation_msg::PipelineId;
|
use msg::constellation_msg::PipelineId;
|
||||||
use msg::constellation_msg::TopLevelBrowsingContextId;
|
use msg::constellation_msg::TopLevelBrowsingContextId;
|
||||||
use script_thread::ScriptThread;
|
use script_thread::ScriptThread;
|
||||||
use script_traits::ScriptMsg;
|
use script_traits::{AuxiliaryBrowsingContextLoadInfo, LoadData, NewLayoutInfo, ScriptMsg};
|
||||||
|
use servo_config::prefs::PREFS;
|
||||||
|
use servo_url::ServoUrl;
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
|
||||||
|
@ -63,6 +67,9 @@ pub struct WindowProxy {
|
||||||
/// of the container.
|
/// of the container.
|
||||||
browsing_context_id: BrowsingContextId,
|
browsing_context_id: BrowsingContextId,
|
||||||
|
|
||||||
|
// https://html.spec.whatwg.org/multipage/#opener-browsing-context
|
||||||
|
opener: Option<BrowsingContextId>,
|
||||||
|
|
||||||
/// The frame id of the top-level ancestor browsing context.
|
/// The frame id of the top-level ancestor browsing context.
|
||||||
/// In the case that this is a top-level window, this is our id.
|
/// In the case that this is a top-level window, this is our id.
|
||||||
top_level_browsing_context_id: TopLevelBrowsingContextId,
|
top_level_browsing_context_id: TopLevelBrowsingContextId,
|
||||||
|
@ -79,6 +86,9 @@ pub struct WindowProxy {
|
||||||
/// Has the browsing context been discarded?
|
/// Has the browsing context been discarded?
|
||||||
discarded: Cell<bool>,
|
discarded: Cell<bool>,
|
||||||
|
|
||||||
|
/// Has the browsing context been disowned?
|
||||||
|
disowned: Cell<bool>,
|
||||||
|
|
||||||
/// The containing iframe element, if this is a same-origin iframe
|
/// The containing iframe element, if this is a same-origin iframe
|
||||||
frame_element: Option<Dom<Element>>,
|
frame_element: Option<Dom<Element>>,
|
||||||
|
|
||||||
|
@ -91,7 +101,8 @@ impl WindowProxy {
|
||||||
top_level_browsing_context_id: TopLevelBrowsingContextId,
|
top_level_browsing_context_id: TopLevelBrowsingContextId,
|
||||||
currently_active: Option<PipelineId>,
|
currently_active: Option<PipelineId>,
|
||||||
frame_element: Option<&Element>,
|
frame_element: Option<&Element>,
|
||||||
parent: Option<&WindowProxy>)
|
parent: Option<&WindowProxy>,
|
||||||
|
opener: Option<BrowsingContextId>)
|
||||||
-> WindowProxy
|
-> WindowProxy
|
||||||
{
|
{
|
||||||
let name = frame_element.map_or(DOMString::new(), |e| e.get_string_attribute(&local_name!("name")));
|
let name = frame_element.map_or(DOMString::new(), |e| e.get_string_attribute(&local_name!("name")));
|
||||||
|
@ -102,8 +113,10 @@ impl WindowProxy {
|
||||||
name: DomRefCell::new(name),
|
name: DomRefCell::new(name),
|
||||||
currently_active: Cell::new(currently_active),
|
currently_active: Cell::new(currently_active),
|
||||||
discarded: Cell::new(false),
|
discarded: Cell::new(false),
|
||||||
|
disowned: Cell::new(false),
|
||||||
frame_element: frame_element.map(Dom::from_ref),
|
frame_element: frame_element.map(Dom::from_ref),
|
||||||
parent: parent.map(Dom::from_ref),
|
parent: parent.map(Dom::from_ref),
|
||||||
|
opener,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,7 +125,8 @@ impl WindowProxy {
|
||||||
browsing_context_id: BrowsingContextId,
|
browsing_context_id: BrowsingContextId,
|
||||||
top_level_browsing_context_id: TopLevelBrowsingContextId,
|
top_level_browsing_context_id: TopLevelBrowsingContextId,
|
||||||
frame_element: Option<&Element>,
|
frame_element: Option<&Element>,
|
||||||
parent: Option<&WindowProxy>)
|
parent: Option<&WindowProxy>,
|
||||||
|
opener: Option<BrowsingContextId>)
|
||||||
-> DomRoot<WindowProxy>
|
-> DomRoot<WindowProxy>
|
||||||
{
|
{
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -136,7 +150,8 @@ impl WindowProxy {
|
||||||
top_level_browsing_context_id,
|
top_level_browsing_context_id,
|
||||||
current,
|
current,
|
||||||
frame_element,
|
frame_element,
|
||||||
parent
|
parent,
|
||||||
|
opener,
|
||||||
));
|
));
|
||||||
|
|
||||||
// The window proxy owns the browsing context.
|
// The window proxy owns the browsing context.
|
||||||
|
@ -157,7 +172,8 @@ impl WindowProxy {
|
||||||
pub fn new_dissimilar_origin(global_to_clone_from: &GlobalScope,
|
pub fn new_dissimilar_origin(global_to_clone_from: &GlobalScope,
|
||||||
browsing_context_id: BrowsingContextId,
|
browsing_context_id: BrowsingContextId,
|
||||||
top_level_browsing_context_id: TopLevelBrowsingContextId,
|
top_level_browsing_context_id: TopLevelBrowsingContextId,
|
||||||
parent: Option<&WindowProxy>)
|
parent: Option<&WindowProxy>,
|
||||||
|
opener: Option<BrowsingContextId>)
|
||||||
-> DomRoot<WindowProxy>
|
-> DomRoot<WindowProxy>
|
||||||
{
|
{
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -172,7 +188,8 @@ impl WindowProxy {
|
||||||
top_level_browsing_context_id,
|
top_level_browsing_context_id,
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
parent
|
parent,
|
||||||
|
opener
|
||||||
));
|
));
|
||||||
|
|
||||||
// Create a new dissimilar-origin window.
|
// Create a new dissimilar-origin window.
|
||||||
|
@ -200,6 +217,194 @@ impl WindowProxy {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://html.spec.whatwg.org/multipage/#auxiliary-browsing-context
|
||||||
|
fn create_auxiliary_browsing_context(&self, name: DOMString, noopener: bool) -> Option<DomRoot<WindowProxy>> {
|
||||||
|
let (chan, port) = ipc::channel().unwrap();
|
||||||
|
let window = self.currently_active.get()
|
||||||
|
.and_then(|id| ScriptThread::find_document(id))
|
||||||
|
.and_then(|doc| Some(DomRoot::from_ref(doc.window())))
|
||||||
|
.unwrap();
|
||||||
|
let msg = EmbedderMsg::AllowOpeningBrowser(chan);
|
||||||
|
window.send_to_embedder(msg);
|
||||||
|
if port.recv().unwrap() {
|
||||||
|
let new_top_level_browsing_context_id = TopLevelBrowsingContextId::new();
|
||||||
|
let new_browsing_context_id = BrowsingContextId::from(new_top_level_browsing_context_id);
|
||||||
|
let new_pipeline_id = PipelineId::new();
|
||||||
|
let load_info = AuxiliaryBrowsingContextLoadInfo {
|
||||||
|
opener_pipeline_id: self.currently_active.get().unwrap(),
|
||||||
|
new_browsing_context_id: new_browsing_context_id,
|
||||||
|
new_top_level_browsing_context_id: new_top_level_browsing_context_id,
|
||||||
|
new_pipeline_id: new_pipeline_id,
|
||||||
|
};
|
||||||
|
let document = self.currently_active.get()
|
||||||
|
.and_then(|id| ScriptThread::find_document(id))
|
||||||
|
.unwrap();
|
||||||
|
let blank_url = ServoUrl::parse("about:blank").ok().unwrap();
|
||||||
|
let load_data = LoadData::new(blank_url,
|
||||||
|
None,
|
||||||
|
document.get_referrer_policy(),
|
||||||
|
Some(document.url().clone()));
|
||||||
|
let (pipeline_sender, pipeline_receiver) = ipc::channel().unwrap();
|
||||||
|
let new_layout_info = NewLayoutInfo {
|
||||||
|
parent_info: None,
|
||||||
|
new_pipeline_id: new_pipeline_id,
|
||||||
|
browsing_context_id: new_browsing_context_id,
|
||||||
|
top_level_browsing_context_id: new_top_level_browsing_context_id,
|
||||||
|
opener: Some(self.browsing_context_id),
|
||||||
|
load_data: load_data,
|
||||||
|
pipeline_port: pipeline_receiver,
|
||||||
|
content_process_shutdown_chan: None,
|
||||||
|
window_size: None,
|
||||||
|
layout_threads: PREFS.get("layout.threads").as_u64().expect("count") as usize,
|
||||||
|
};
|
||||||
|
let constellation_msg = ScriptMsg::ScriptNewAuxiliary(load_info, pipeline_sender);
|
||||||
|
window.send_to_constellation(constellation_msg);
|
||||||
|
ScriptThread::process_attach_layout(new_layout_info, document.origin().clone());
|
||||||
|
let msg = EmbedderMsg::BrowserCreated(new_top_level_browsing_context_id);
|
||||||
|
window.send_to_embedder(msg);
|
||||||
|
// TODO: if noopener is false, copy the sessionStorage storage area of the creator origin.
|
||||||
|
// See step 14 of https://html.spec.whatwg.org/multipage/#creating-a-new-browsing-context
|
||||||
|
let auxiliary = ScriptThread::find_document(new_pipeline_id).and_then(|doc| doc.browsing_context());
|
||||||
|
if let Some(proxy) = auxiliary {
|
||||||
|
if name.to_lowercase() != "_blank" {
|
||||||
|
proxy.set_name(name);
|
||||||
|
}
|
||||||
|
if noopener {
|
||||||
|
proxy.disown();
|
||||||
|
}
|
||||||
|
return Some(proxy)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://html.spec.whatwg.org/multipage/#disowned-its-opener
|
||||||
|
pub fn disown(&self) {
|
||||||
|
self.disowned.set(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unsafe_code)]
|
||||||
|
// https://html.spec.whatwg.org/multipage/#dom-opener
|
||||||
|
pub unsafe fn opener(&self, cx: *mut JSContext) -> JSVal {
|
||||||
|
if self.disowned.get() {
|
||||||
|
return NullValue()
|
||||||
|
}
|
||||||
|
let opener_id = match self.opener {
|
||||||
|
Some(opener_browsing_context_id) => opener_browsing_context_id,
|
||||||
|
None => return NullValue()
|
||||||
|
};
|
||||||
|
let opener_proxy = match ScriptThread::find_window_proxy(opener_id) {
|
||||||
|
Some(window_proxy) => window_proxy,
|
||||||
|
None => {
|
||||||
|
let sender_pipeline_id = self.currently_active().unwrap();
|
||||||
|
match ScriptThread::get_top_level_for_browsing_context(sender_pipeline_id, opener_id) {
|
||||||
|
Some(opener_top_id) => {
|
||||||
|
let global_to_clone_from = GlobalScope::from_context(cx);
|
||||||
|
WindowProxy::new_dissimilar_origin(
|
||||||
|
&*global_to_clone_from,
|
||||||
|
opener_id,
|
||||||
|
opener_top_id,
|
||||||
|
None,
|
||||||
|
None
|
||||||
|
)
|
||||||
|
},
|
||||||
|
None => return NullValue()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if opener_proxy.is_browsing_context_discarded() {
|
||||||
|
return NullValue()
|
||||||
|
}
|
||||||
|
rooted!(in(cx) let mut val = UndefinedValue());
|
||||||
|
opener_proxy.to_jsval(cx, val.handle_mut());
|
||||||
|
return val.get()
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://html.spec.whatwg.org/multipage/#window-open-steps
|
||||||
|
pub fn open(&self,
|
||||||
|
url: DOMString,
|
||||||
|
target: DOMString,
|
||||||
|
features: DOMString)
|
||||||
|
-> Option<DomRoot<WindowProxy>> {
|
||||||
|
// Step 3.
|
||||||
|
let non_empty_target = match target.as_ref() {
|
||||||
|
"" => DOMString::from("_blank"),
|
||||||
|
_ => target
|
||||||
|
};
|
||||||
|
// TODO Step 4, properly tokenize features.
|
||||||
|
// Step 5
|
||||||
|
let noopener = features.contains("noopener");
|
||||||
|
// Step 6, 7
|
||||||
|
let (chosen, new) = match self.choose_browsing_context(non_empty_target, noopener) {
|
||||||
|
(Some(chosen), new) => (chosen, new),
|
||||||
|
(None, _) => return None
|
||||||
|
};
|
||||||
|
// TODO Step 8, set up browsing context features.
|
||||||
|
let target_document = match chosen.document() {
|
||||||
|
Some(target_document) => target_document,
|
||||||
|
None => return None
|
||||||
|
};
|
||||||
|
let target_window = target_document.window();
|
||||||
|
// Step 9, and 10.2, will have happened elsewhere,
|
||||||
|
// since we've created a new browsing context and loaded it with about:blank.
|
||||||
|
if !url.is_empty() {
|
||||||
|
let existing_document = self.currently_active.get()
|
||||||
|
.and_then(|id| ScriptThread::find_document(id)).unwrap();
|
||||||
|
// Step 10.1
|
||||||
|
let url = match existing_document.url().join(&url) {
|
||||||
|
Ok(url) => url,
|
||||||
|
Err(_) => return None, // TODO: throw a "SyntaxError" DOMException.
|
||||||
|
};
|
||||||
|
// Step 10.3
|
||||||
|
target_window.load_url(url, new, false, target_document.get_referrer_policy());
|
||||||
|
}
|
||||||
|
if noopener {
|
||||||
|
// Step 11 (Dis-owning has been done in create_auxiliary_browsing_context).
|
||||||
|
return None
|
||||||
|
}
|
||||||
|
// Step 12.
|
||||||
|
return target_document.browsing_context()
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://html.spec.whatwg.org/multipage/#the-rules-for-choosing-a-browsing-context-given-a-browsing-context-name
|
||||||
|
pub fn choose_browsing_context(&self, name: DOMString, noopener: bool) -> (Option<DomRoot<WindowProxy>>, bool) {
|
||||||
|
match name.to_lowercase().as_ref() {
|
||||||
|
"" | "_self" => {
|
||||||
|
// Step 3.
|
||||||
|
(Some(DomRoot::from_ref(self)), false)
|
||||||
|
},
|
||||||
|
"_parent" => {
|
||||||
|
// Step 4
|
||||||
|
if let Some(parent) = self.parent() {
|
||||||
|
return (Some(DomRoot::from_ref(parent)), false)
|
||||||
|
}
|
||||||
|
(None, false)
|
||||||
|
|
||||||
|
},
|
||||||
|
"_top" => {
|
||||||
|
// Step 5
|
||||||
|
(Some(DomRoot::from_ref(self.top())), false)
|
||||||
|
},
|
||||||
|
"_blank" => {
|
||||||
|
(self.create_auxiliary_browsing_context(name, noopener), true)
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
// Step 6.
|
||||||
|
// TODO: expand the search to all 'familiar' bc,
|
||||||
|
// including auxiliaries familiar by way of their opener.
|
||||||
|
// See https://html.spec.whatwg.org/multipage/#familiar-with
|
||||||
|
match ScriptThread::find_window_proxy_by_name(&name) {
|
||||||
|
Some(proxy) => (Some(proxy), false),
|
||||||
|
None => (self.create_auxiliary_browsing_context(name, noopener), true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_auxiliary(&self) -> bool {
|
||||||
|
self.opener.is_some()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn discard_browsing_context(&self) {
|
pub fn discard_browsing_context(&self) {
|
||||||
self.discarded.set(true);
|
self.discarded.set(true);
|
||||||
}
|
}
|
||||||
|
@ -220,6 +425,11 @@ impl WindowProxy {
|
||||||
self.frame_element.r()
|
self.frame_element.r()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn document(&self) -> Option<DomRoot<Document>> {
|
||||||
|
self.currently_active.get()
|
||||||
|
.and_then(|id| ScriptThread::find_document(id))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn parent(&self) -> Option<&WindowProxy> {
|
pub fn parent(&self) -> Option<&WindowProxy> {
|
||||||
self.parent.r()
|
self.parent.r()
|
||||||
}
|
}
|
||||||
|
|
|
@ -157,6 +157,8 @@ struct InProgressLoad {
|
||||||
top_level_browsing_context_id: TopLevelBrowsingContextId,
|
top_level_browsing_context_id: TopLevelBrowsingContextId,
|
||||||
/// The parent pipeline and frame type associated with this load, if any.
|
/// The parent pipeline and frame type associated with this load, if any.
|
||||||
parent_info: Option<PipelineId>,
|
parent_info: Option<PipelineId>,
|
||||||
|
/// The opener, if this is an auxiliary.
|
||||||
|
opener: Option<BrowsingContextId>,
|
||||||
/// The current window size associated with this pipeline.
|
/// The current window size associated with this pipeline.
|
||||||
window_size: Option<WindowSizeData>,
|
window_size: Option<WindowSizeData>,
|
||||||
/// Channel to the layout thread associated with this pipeline.
|
/// Channel to the layout thread associated with this pipeline.
|
||||||
|
@ -183,6 +185,7 @@ impl InProgressLoad {
|
||||||
browsing_context_id: BrowsingContextId,
|
browsing_context_id: BrowsingContextId,
|
||||||
top_level_browsing_context_id: TopLevelBrowsingContextId,
|
top_level_browsing_context_id: TopLevelBrowsingContextId,
|
||||||
parent_info: Option<PipelineId>,
|
parent_info: Option<PipelineId>,
|
||||||
|
opener: Option<BrowsingContextId>,
|
||||||
layout_chan: Sender<message::Msg>,
|
layout_chan: Sender<message::Msg>,
|
||||||
window_size: Option<WindowSizeData>,
|
window_size: Option<WindowSizeData>,
|
||||||
url: ServoUrl,
|
url: ServoUrl,
|
||||||
|
@ -195,6 +198,7 @@ impl InProgressLoad {
|
||||||
browsing_context_id: browsing_context_id,
|
browsing_context_id: browsing_context_id,
|
||||||
top_level_browsing_context_id: top_level_browsing_context_id,
|
top_level_browsing_context_id: top_level_browsing_context_id,
|
||||||
parent_info: parent_info,
|
parent_info: parent_info,
|
||||||
|
opener: opener,
|
||||||
layout_chan: layout_chan,
|
layout_chan: layout_chan,
|
||||||
window_size: window_size,
|
window_size: window_size,
|
||||||
activity: DocumentActivity::FullyActive,
|
activity: DocumentActivity::FullyActive,
|
||||||
|
@ -569,6 +573,7 @@ impl ScriptThreadFactory for ScriptThread {
|
||||||
let browsing_context_id = state.browsing_context_id;
|
let browsing_context_id = state.browsing_context_id;
|
||||||
let top_level_browsing_context_id = state.top_level_browsing_context_id;
|
let top_level_browsing_context_id = state.top_level_browsing_context_id;
|
||||||
let parent_info = state.parent_info;
|
let parent_info = state.parent_info;
|
||||||
|
let opener = state.opener;
|
||||||
let mem_profiler_chan = state.mem_profiler_chan.clone();
|
let mem_profiler_chan = state.mem_profiler_chan.clone();
|
||||||
let window_size = state.window_size;
|
let window_size = state.window_size;
|
||||||
let script_thread = ScriptThread::new(state,
|
let script_thread = ScriptThread::new(state,
|
||||||
|
@ -583,7 +588,7 @@ impl ScriptThreadFactory for ScriptThread {
|
||||||
|
|
||||||
let origin = MutableOrigin::new(load_data.url.origin());
|
let origin = MutableOrigin::new(load_data.url.origin());
|
||||||
let new_load = InProgressLoad::new(id, browsing_context_id, top_level_browsing_context_id, parent_info,
|
let new_load = InProgressLoad::new(id, browsing_context_id, top_level_browsing_context_id, parent_info,
|
||||||
layout_chan, window_size, load_data.url.clone(), origin);
|
opener, layout_chan, window_size, load_data.url.clone(), origin);
|
||||||
script_thread.pre_page_load(new_load, load_data);
|
script_thread.pre_page_load(new_load, load_data);
|
||||||
|
|
||||||
let reporter_name = format!("script-reporter-{}", id);
|
let reporter_name = format!("script-reporter-{}", id);
|
||||||
|
@ -706,6 +711,15 @@ impl ScriptThread {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_top_level_for_browsing_context(sender_pipeline: PipelineId,
|
||||||
|
browsing_context_id: BrowsingContextId)
|
||||||
|
-> Option<TopLevelBrowsingContextId> {
|
||||||
|
SCRIPT_THREAD_ROOT.with(|root| root.get().and_then(|script_thread| {
|
||||||
|
let script_thread = unsafe { &*script_thread };
|
||||||
|
script_thread.ask_constellation_for_top_level_info(sender_pipeline, browsing_context_id)
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn find_document(id: PipelineId) -> Option<DomRoot<Document>> {
|
pub fn find_document(id: PipelineId) -> Option<DomRoot<Document>> {
|
||||||
SCRIPT_THREAD_ROOT.with(|root| root.get().and_then(|script_thread| {
|
SCRIPT_THREAD_ROOT.with(|root| root.get().and_then(|script_thread| {
|
||||||
let script_thread = unsafe { &*script_thread };
|
let script_thread = unsafe { &*script_thread };
|
||||||
|
@ -721,6 +735,18 @@ impl ScriptThread {
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn find_window_proxy_by_name(name: &DOMString) -> Option<DomRoot<WindowProxy>> {
|
||||||
|
SCRIPT_THREAD_ROOT.with(|root| root.get().and_then(|script_thread| {
|
||||||
|
let script_thread = unsafe { &*script_thread };
|
||||||
|
for (_, proxy) in script_thread.window_proxies.borrow().iter() {
|
||||||
|
if proxy.get_name() == *name {
|
||||||
|
return Some(DomRoot::from_ref(&**proxy))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn worklet_thread_pool() -> Rc<WorkletThreadPool> {
|
pub fn worklet_thread_pool() -> Rc<WorkletThreadPool> {
|
||||||
SCRIPT_THREAD_ROOT.with(|root| {
|
SCRIPT_THREAD_ROOT.with(|root| {
|
||||||
let script_thread = unsafe { &*root.get().unwrap() };
|
let script_thread = unsafe { &*root.get().unwrap() };
|
||||||
|
@ -1541,6 +1567,7 @@ impl ScriptThread {
|
||||||
new_pipeline_id,
|
new_pipeline_id,
|
||||||
browsing_context_id,
|
browsing_context_id,
|
||||||
top_level_browsing_context_id,
|
top_level_browsing_context_id,
|
||||||
|
opener,
|
||||||
load_data,
|
load_data,
|
||||||
window_size,
|
window_size,
|
||||||
pipeline_port,
|
pipeline_port,
|
||||||
|
@ -1585,6 +1612,7 @@ impl ScriptThread {
|
||||||
browsing_context_id,
|
browsing_context_id,
|
||||||
top_level_browsing_context_id,
|
top_level_browsing_context_id,
|
||||||
parent_info,
|
parent_info,
|
||||||
|
opener,
|
||||||
layout_chan,
|
layout_chan,
|
||||||
window_size,
|
window_size,
|
||||||
load_data.url.clone(),
|
load_data.url.clone(),
|
||||||
|
@ -2013,6 +2041,16 @@ impl ScriptThread {
|
||||||
result_receiver.recv().expect("Failed to get frame id from constellation.")
|
result_receiver.recv().expect("Failed to get frame id from constellation.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn ask_constellation_for_top_level_info(&self,
|
||||||
|
sender_pipeline: PipelineId,
|
||||||
|
browsing_context_id: BrowsingContextId)
|
||||||
|
-> Option<TopLevelBrowsingContextId> {
|
||||||
|
let (result_sender, result_receiver) = ipc::channel().unwrap();
|
||||||
|
let msg = ScriptMsg::GetTopForBrowsingContext(browsing_context_id, result_sender);
|
||||||
|
self.script_sender.send((sender_pipeline, msg)).expect("Failed to send to constellation.");
|
||||||
|
result_receiver.recv().expect("Failed to get top-level id from constellation.")
|
||||||
|
}
|
||||||
|
|
||||||
// Get the browsing context for a pipeline that may exist in another
|
// Get the browsing context for a pipeline that may exist in another
|
||||||
// script thread. If the browsing context already exists in the
|
// script thread. If the browsing context already exists in the
|
||||||
// `window_proxies` map, we return it, otherwise we recursively
|
// `window_proxies` map, we return it, otherwise we recursively
|
||||||
|
@ -2022,7 +2060,8 @@ impl ScriptThread {
|
||||||
fn remote_window_proxy(&self,
|
fn remote_window_proxy(&self,
|
||||||
global_to_clone: &GlobalScope,
|
global_to_clone: &GlobalScope,
|
||||||
top_level_browsing_context_id: TopLevelBrowsingContextId,
|
top_level_browsing_context_id: TopLevelBrowsingContextId,
|
||||||
pipeline_id: PipelineId)
|
pipeline_id: PipelineId,
|
||||||
|
opener: Option<BrowsingContextId>)
|
||||||
-> Option<DomRoot<WindowProxy>>
|
-> Option<DomRoot<WindowProxy>>
|
||||||
{
|
{
|
||||||
let browsing_context_id = self.ask_constellation_for_browsing_context_id(pipeline_id)?;
|
let browsing_context_id = self.ask_constellation_for_browsing_context_id(pipeline_id)?;
|
||||||
|
@ -2030,12 +2069,13 @@ impl ScriptThread {
|
||||||
return Some(DomRoot::from_ref(window_proxy));
|
return Some(DomRoot::from_ref(window_proxy));
|
||||||
}
|
}
|
||||||
let parent = self.ask_constellation_for_parent_info(pipeline_id).and_then(|parent_id| {
|
let parent = self.ask_constellation_for_parent_info(pipeline_id).and_then(|parent_id| {
|
||||||
self.remote_window_proxy(global_to_clone, top_level_browsing_context_id, parent_id)
|
self.remote_window_proxy(global_to_clone, top_level_browsing_context_id, parent_id, opener)
|
||||||
});
|
});
|
||||||
let window_proxy = WindowProxy::new_dissimilar_origin(global_to_clone,
|
let window_proxy = WindowProxy::new_dissimilar_origin(global_to_clone,
|
||||||
browsing_context_id,
|
browsing_context_id,
|
||||||
top_level_browsing_context_id,
|
top_level_browsing_context_id,
|
||||||
parent.r());
|
parent.r(),
|
||||||
|
opener);
|
||||||
self.window_proxies.borrow_mut().insert(browsing_context_id, Dom::from_ref(&*window_proxy));
|
self.window_proxies.borrow_mut().insert(browsing_context_id, Dom::from_ref(&*window_proxy));
|
||||||
Some(window_proxy)
|
Some(window_proxy)
|
||||||
}
|
}
|
||||||
|
@ -2050,7 +2090,8 @@ impl ScriptThread {
|
||||||
window: &Window,
|
window: &Window,
|
||||||
browsing_context_id: BrowsingContextId,
|
browsing_context_id: BrowsingContextId,
|
||||||
top_level_browsing_context_id: TopLevelBrowsingContextId,
|
top_level_browsing_context_id: TopLevelBrowsingContextId,
|
||||||
parent_info: Option<PipelineId>)
|
parent_info: Option<PipelineId>,
|
||||||
|
opener: Option<BrowsingContextId>)
|
||||||
-> DomRoot<WindowProxy>
|
-> DomRoot<WindowProxy>
|
||||||
{
|
{
|
||||||
if let Some(window_proxy) = self.window_proxies.borrow().get(&browsing_context_id) {
|
if let Some(window_proxy) = self.window_proxies.borrow().get(&browsing_context_id) {
|
||||||
|
@ -2063,15 +2104,17 @@ impl ScriptThread {
|
||||||
let parent = match (parent_info, iframe.as_ref()) {
|
let parent = match (parent_info, iframe.as_ref()) {
|
||||||
(_, Some(iframe)) => Some(window_from_node(&**iframe).window_proxy()),
|
(_, Some(iframe)) => Some(window_from_node(&**iframe).window_proxy()),
|
||||||
(Some(parent_id), _) => self.remote_window_proxy(window.upcast(),
|
(Some(parent_id), _) => self.remote_window_proxy(window.upcast(),
|
||||||
top_level_browsing_context_id,
|
top_level_browsing_context_id,
|
||||||
parent_id),
|
parent_id,
|
||||||
|
opener),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
let window_proxy = WindowProxy::new(&window,
|
let window_proxy = WindowProxy::new(&window,
|
||||||
browsing_context_id,
|
browsing_context_id,
|
||||||
top_level_browsing_context_id,
|
top_level_browsing_context_id,
|
||||||
iframe.r().map(Castable::upcast),
|
iframe.r().map(Castable::upcast),
|
||||||
parent.r());
|
parent.r(),
|
||||||
|
opener);
|
||||||
self.window_proxies.borrow_mut().insert(browsing_context_id, Dom::from_ref(&*window_proxy));
|
self.window_proxies.borrow_mut().insert(browsing_context_id, Dom::from_ref(&*window_proxy));
|
||||||
window_proxy
|
window_proxy
|
||||||
}
|
}
|
||||||
|
@ -2150,7 +2193,8 @@ impl ScriptThread {
|
||||||
let window_proxy = self.local_window_proxy(&window,
|
let window_proxy = self.local_window_proxy(&window,
|
||||||
incomplete.browsing_context_id,
|
incomplete.browsing_context_id,
|
||||||
incomplete.top_level_browsing_context_id,
|
incomplete.top_level_browsing_context_id,
|
||||||
incomplete.parent_info);
|
incomplete.parent_info,
|
||||||
|
incomplete.opener);
|
||||||
window.init_window_proxy(&window_proxy);
|
window.init_window_proxy(&window_proxy);
|
||||||
|
|
||||||
let last_modified = metadata.headers.as_ref().and_then(|headers| {
|
let last_modified = metadata.headers.as_ref().and_then(|headers| {
|
||||||
|
|
|
@ -193,6 +193,8 @@ pub struct NewLayoutInfo {
|
||||||
pub browsing_context_id: BrowsingContextId,
|
pub browsing_context_id: BrowsingContextId,
|
||||||
/// Id of the top-level browsing context associated with this pipeline.
|
/// Id of the top-level browsing context associated with this pipeline.
|
||||||
pub top_level_browsing_context_id: TopLevelBrowsingContextId,
|
pub top_level_browsing_context_id: TopLevelBrowsingContextId,
|
||||||
|
/// Id of the opener, if any
|
||||||
|
pub opener: Option<BrowsingContextId>,
|
||||||
/// Network request data which will be initiated by the script thread.
|
/// Network request data which will be initiated by the script thread.
|
||||||
pub load_data: LoadData,
|
pub load_data: LoadData,
|
||||||
/// Information about the initial window size.
|
/// Information about the initial window size.
|
||||||
|
@ -521,6 +523,8 @@ pub struct InitialScriptState {
|
||||||
pub browsing_context_id: BrowsingContextId,
|
pub browsing_context_id: BrowsingContextId,
|
||||||
/// The ID of the top-level browsing context this script is part of.
|
/// The ID of the top-level browsing context this script is part of.
|
||||||
pub top_level_browsing_context_id: TopLevelBrowsingContextId,
|
pub top_level_browsing_context_id: TopLevelBrowsingContextId,
|
||||||
|
/// The ID of the opener, if any.
|
||||||
|
pub opener: Option<BrowsingContextId>,
|
||||||
/// A channel with which messages can be sent to us (the script thread).
|
/// A channel with which messages can be sent to us (the script thread).
|
||||||
pub control_chan: IpcSender<ConstellationControlMsg>,
|
pub control_chan: IpcSender<ConstellationControlMsg>,
|
||||||
/// A port on which messages sent by the constellation to script can be received.
|
/// A port on which messages sent by the constellation to script can be received.
|
||||||
|
@ -576,6 +580,19 @@ pub enum IFrameSandboxState {
|
||||||
IFrameUnsandboxed,
|
IFrameUnsandboxed,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Specifies the information required to load an auxiliary browsing context.
|
||||||
|
#[derive(Deserialize, Serialize)]
|
||||||
|
pub struct AuxiliaryBrowsingContextLoadInfo {
|
||||||
|
/// The pipeline opener browsing context.
|
||||||
|
pub opener_pipeline_id: PipelineId,
|
||||||
|
/// The new top-level ID for the auxiliary.
|
||||||
|
pub new_top_level_browsing_context_id: TopLevelBrowsingContextId,
|
||||||
|
/// The new browsing context ID.
|
||||||
|
pub new_browsing_context_id: BrowsingContextId,
|
||||||
|
/// The new pipeline ID for the auxiliary.
|
||||||
|
pub new_pipeline_id: PipelineId,
|
||||||
|
}
|
||||||
|
|
||||||
/// Specifies the information required to load an iframe.
|
/// Specifies the information required to load an iframe.
|
||||||
#[derive(Deserialize, Serialize)]
|
#[derive(Deserialize, Serialize)]
|
||||||
pub struct IFrameLoadInfo {
|
pub struct IFrameLoadInfo {
|
||||||
|
@ -700,7 +717,7 @@ pub enum ConstellationMsg {
|
||||||
/// Dispatch WebVR events to the subscribed script threads.
|
/// Dispatch WebVR events to the subscribed script threads.
|
||||||
WebVREvents(Vec<PipelineId>, Vec<WebVREvent>),
|
WebVREvents(Vec<PipelineId>, Vec<WebVREvent>),
|
||||||
/// Create a new top level browsing context.
|
/// Create a new top level browsing context.
|
||||||
NewBrowser(ServoUrl, IpcSender<TopLevelBrowsingContextId>),
|
NewBrowser(ServoUrl, TopLevelBrowsingContextId),
|
||||||
/// Close a top level browsing context.
|
/// Close a top level browsing context.
|
||||||
CloseBrowser(TopLevelBrowsingContextId),
|
CloseBrowser(TopLevelBrowsingContextId),
|
||||||
/// Panic a top level browsing context.
|
/// Panic a top level browsing context.
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use AnimationState;
|
use AnimationState;
|
||||||
|
use AuxiliaryBrowsingContextLoadInfo;
|
||||||
use DocumentState;
|
use DocumentState;
|
||||||
use IFrameLoadInfo;
|
use IFrameLoadInfo;
|
||||||
use IFrameLoadInfoWithData;
|
use IFrameLoadInfoWithData;
|
||||||
|
@ -16,7 +17,8 @@ use embedder_traits::EmbedderMsg;
|
||||||
use euclid::{Size2D, TypedSize2D};
|
use euclid::{Size2D, TypedSize2D};
|
||||||
use gfx_traits::Epoch;
|
use gfx_traits::Epoch;
|
||||||
use ipc_channel::ipc::{IpcReceiver, IpcSender};
|
use ipc_channel::ipc::{IpcReceiver, IpcSender};
|
||||||
use msg::constellation_msg::{BrowsingContextId, HistoryStateId, PipelineId, TraversalDirection};
|
use msg::constellation_msg::{BrowsingContextId, PipelineId, TopLevelBrowsingContextId};
|
||||||
|
use msg::constellation_msg::{HistoryStateId, TraversalDirection};
|
||||||
use net_traits::CoreResourceMsg;
|
use net_traits::CoreResourceMsg;
|
||||||
use net_traits::request::RequestInit;
|
use net_traits::request::RequestInit;
|
||||||
use net_traits::storage_thread::StorageType;
|
use net_traits::storage_thread::StorageType;
|
||||||
|
@ -104,6 +106,8 @@ pub enum ScriptMsg {
|
||||||
GetBrowsingContextId(PipelineId, IpcSender<Option<BrowsingContextId>>),
|
GetBrowsingContextId(PipelineId, IpcSender<Option<BrowsingContextId>>),
|
||||||
/// Get the parent info for a given pipeline.
|
/// Get the parent info for a given pipeline.
|
||||||
GetParentInfo(PipelineId, IpcSender<Option<PipelineId>>),
|
GetParentInfo(PipelineId, IpcSender<Option<PipelineId>>),
|
||||||
|
/// Get the top-level browsing context info for a given browsing context.
|
||||||
|
GetTopForBrowsingContext(BrowsingContextId, IpcSender<Option<TopLevelBrowsingContextId>>),
|
||||||
/// Get the nth child browsing context ID for a given browsing context, sorted in tree order.
|
/// Get the nth child browsing context ID for a given browsing context, sorted in tree order.
|
||||||
GetChildBrowsingContextId(BrowsingContextId, usize, IpcSender<Option<BrowsingContextId>>),
|
GetChildBrowsingContextId(BrowsingContextId, usize, IpcSender<Option<BrowsingContextId>>),
|
||||||
/// All pending loads are complete, and the `load` event for this pipeline
|
/// All pending loads are complete, and the `load` event for this pipeline
|
||||||
|
@ -137,6 +141,8 @@ pub enum ScriptMsg {
|
||||||
ScriptLoadedURLInIFrame(IFrameLoadInfoWithData),
|
ScriptLoadedURLInIFrame(IFrameLoadInfoWithData),
|
||||||
/// A load of the initial `about:blank` has been completed in an IFrame.
|
/// A load of the initial `about:blank` has been completed in an IFrame.
|
||||||
ScriptNewIFrame(IFrameLoadInfo, IpcSender<LayoutControlMsg>),
|
ScriptNewIFrame(IFrameLoadInfo, IpcSender<LayoutControlMsg>),
|
||||||
|
/// Script has opened a new auxiliary browsing context.
|
||||||
|
ScriptNewAuxiliary(AuxiliaryBrowsingContextLoadInfo, IpcSender<LayoutControlMsg>),
|
||||||
/// Requests that the constellation set the contents of the clipboard
|
/// Requests that the constellation set the contents of the clipboard
|
||||||
SetClipboardContents(String),
|
SetClipboardContents(String),
|
||||||
/// Mark a new document as active
|
/// Mark a new document as active
|
||||||
|
@ -181,6 +187,7 @@ impl fmt::Debug for ScriptMsg {
|
||||||
GetClipboardContents(..) => "GetClipboardContents",
|
GetClipboardContents(..) => "GetClipboardContents",
|
||||||
GetBrowsingContextId(..) => "GetBrowsingContextId",
|
GetBrowsingContextId(..) => "GetBrowsingContextId",
|
||||||
GetParentInfo(..) => "GetParentInfo",
|
GetParentInfo(..) => "GetParentInfo",
|
||||||
|
GetTopForBrowsingContext(..) => "GetParentBrowsingContext",
|
||||||
GetChildBrowsingContextId(..) => "GetChildBrowsingContextId",
|
GetChildBrowsingContextId(..) => "GetChildBrowsingContextId",
|
||||||
LoadComplete => "LoadComplete",
|
LoadComplete => "LoadComplete",
|
||||||
LoadUrl(..) => "LoadUrl",
|
LoadUrl(..) => "LoadUrl",
|
||||||
|
@ -196,6 +203,7 @@ impl fmt::Debug for ScriptMsg {
|
||||||
VisibilityChangeComplete(..) => "VisibilityChangeComplete",
|
VisibilityChangeComplete(..) => "VisibilityChangeComplete",
|
||||||
ScriptLoadedURLInIFrame(..) => "ScriptLoadedURLInIFrame",
|
ScriptLoadedURLInIFrame(..) => "ScriptLoadedURLInIFrame",
|
||||||
ScriptNewIFrame(..) => "ScriptNewIFrame",
|
ScriptNewIFrame(..) => "ScriptNewIFrame",
|
||||||
|
ScriptNewAuxiliary(..) => "ScriptNewAuxiliary",
|
||||||
SetClipboardContents(..) => "SetClipboardContents",
|
SetClipboardContents(..) => "SetClipboardContents",
|
||||||
ActivateDocument => "ActivateDocument",
|
ActivateDocument => "ActivateDocument",
|
||||||
SetDocumentState(..) => "SetDocumentState",
|
SetDocumentState(..) => "SetDocumentState",
|
||||||
|
|
|
@ -87,6 +87,7 @@ use gaol::sandbox::{ChildSandbox, ChildSandboxMethods};
|
||||||
use gfx::font_cache_thread::FontCacheThread;
|
use gfx::font_cache_thread::FontCacheThread;
|
||||||
use ipc_channel::ipc::{self, IpcSender};
|
use ipc_channel::ipc::{self, IpcSender};
|
||||||
use log::{Log, Metadata, Record};
|
use log::{Log, Metadata, Record};
|
||||||
|
use msg::constellation_msg::{PipelineNamespace, PipelineNamespaceId};
|
||||||
use net::resource_thread::new_resource_threads;
|
use net::resource_thread::new_resource_threads;
|
||||||
use net_traits::IpcSend;
|
use net_traits::IpcSend;
|
||||||
use profile::mem as profile_mem;
|
use profile::mem as profile_mem;
|
||||||
|
@ -135,6 +136,9 @@ impl<Window> Servo<Window> where Window: WindowMethods + 'static {
|
||||||
// Make sure the gl context is made current.
|
// Make sure the gl context is made current.
|
||||||
window.prepare_for_composite(Length::new(0), Length::new(0));
|
window.prepare_for_composite(Length::new(0), Length::new(0));
|
||||||
|
|
||||||
|
// Reserving a namespace to create TopLevelBrowserContextId.
|
||||||
|
PipelineNamespace::install(PipelineNamespaceId(0));
|
||||||
|
|
||||||
// Get both endpoints of a special channel for communication between
|
// Get both endpoints of a special channel for communication between
|
||||||
// the client window and the compositor. This channel is unique because
|
// the client window and the compositor. This channel is unique because
|
||||||
// messages to client may need to pump a platform-specific event loop
|
// messages to client may need to pump a platform-specific event loop
|
||||||
|
@ -326,8 +330,8 @@ impl<Window> Servo<Window> where Window: WindowMethods + 'static {
|
||||||
self.compositor.capture_webrender();
|
self.compositor.capture_webrender();
|
||||||
}
|
}
|
||||||
|
|
||||||
WindowEvent::NewBrowser(url, response_chan) => {
|
WindowEvent::NewBrowser(url, browser_id) => {
|
||||||
let msg = ConstellationMsg::NewBrowser(url, response_chan);
|
let msg = ConstellationMsg::NewBrowser(url, browser_id);
|
||||||
if let Err(e) = self.constellation_chan.send(msg) {
|
if let Err(e) = self.constellation_chan.send(msg) {
|
||||||
warn!("Sending NewBrowser message to constellation failed ({}).", e);
|
warn!("Sending NewBrowser message to constellation failed ({}).", e);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,6 @@ use servo::compositing::windowing::{AnimationState, EmbedderCoordinates, MouseWi
|
||||||
use servo::embedder_traits::EmbedderMsg;
|
use servo::embedder_traits::EmbedderMsg;
|
||||||
use servo::embedder_traits::resources::{self, Resource};
|
use servo::embedder_traits::resources::{self, Resource};
|
||||||
use servo::euclid::{Length, TypedPoint2D, TypedScale, TypedSize2D, TypedVector2D};
|
use servo::euclid::{Length, TypedPoint2D, TypedScale, TypedSize2D, TypedVector2D};
|
||||||
use servo::ipc_channel::ipc;
|
|
||||||
use servo::msg::constellation_msg::TraversalDirection;
|
use servo::msg::constellation_msg::TraversalDirection;
|
||||||
use servo::script_traits::{MouseButton, TouchEventType};
|
use servo::script_traits::{MouseButton, TouchEventType};
|
||||||
use servo::servo_config::opts;
|
use servo::servo_config::opts;
|
||||||
|
@ -75,7 +74,14 @@ pub struct ServoGlue {
|
||||||
servo: Servo<ServoCallbacks>,
|
servo: Servo<ServoCallbacks>,
|
||||||
batch_mode: bool,
|
batch_mode: bool,
|
||||||
callbacks: Rc<ServoCallbacks>,
|
callbacks: Rc<ServoCallbacks>,
|
||||||
browser_id: BrowserId,
|
/// id of the top level browsing context. It is unique as tabs
|
||||||
|
/// are not supported yet. None until created.
|
||||||
|
browser_id: Option<BrowserId>,
|
||||||
|
// A rudimentary stack of "tabs".
|
||||||
|
// EmbedderMsg::BrowserCreated will push onto it.
|
||||||
|
// EmbedderMsg::CloseBrowser will pop from it,
|
||||||
|
// and exit if it is empty afterwards.
|
||||||
|
browsers: Vec<BrowserId>,
|
||||||
events: Vec<WindowEvent>,
|
events: Vec<WindowEvent>,
|
||||||
current_url: Option<ServoUrl>,
|
current_url: Option<ServoUrl>,
|
||||||
}
|
}
|
||||||
|
@ -133,28 +139,34 @@ pub fn init(
|
||||||
waker,
|
waker,
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut servo = Servo::new(callbacks.clone());
|
let servo = Servo::new(callbacks.clone());
|
||||||
|
|
||||||
let (sender, receiver) = ipc::channel().map_err(|_| "Can't create ipc::channel")?;
|
|
||||||
servo.handle_events(vec![WindowEvent::NewBrowser(url.clone(), sender)]);
|
|
||||||
let browser_id = receiver.recv().map_err(|_| "Can't receive browser_id")?;
|
|
||||||
servo.handle_events(vec![WindowEvent::SelectBrowser(browser_id)]);
|
|
||||||
|
|
||||||
SERVO.with(|s| {
|
SERVO.with(|s| {
|
||||||
*s.borrow_mut() = Some(ServoGlue {
|
let mut servo_glue = ServoGlue {
|
||||||
servo,
|
servo,
|
||||||
batch_mode: false,
|
batch_mode: false,
|
||||||
callbacks,
|
callbacks,
|
||||||
browser_id,
|
browser_id: None,
|
||||||
|
browsers: vec![],
|
||||||
events: vec![],
|
events: vec![],
|
||||||
current_url: Some(url),
|
current_url: Some(url.clone()),
|
||||||
});
|
};
|
||||||
|
let browser_id = BrowserId::new();
|
||||||
|
let _ = servo_glue.process_event(WindowEvent::NewBrowser(url, browser_id));
|
||||||
|
*s.borrow_mut() = Some(servo_glue);
|
||||||
});
|
});
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ServoGlue {
|
impl ServoGlue {
|
||||||
|
fn get_browser_id(&self) -> Result<BrowserId, &'static str> {
|
||||||
|
let browser_id = match self.browser_id {
|
||||||
|
Some(id) => id,
|
||||||
|
None => return Err("No BrowserId set yet.")
|
||||||
|
};
|
||||||
|
Ok(browser_id)
|
||||||
|
}
|
||||||
/// This is the Servo heartbeat. This needs to be called
|
/// This is the Servo heartbeat. This needs to be called
|
||||||
/// everytime wakeup is called or when embedder wants Servo
|
/// everytime wakeup is called or when embedder wants Servo
|
||||||
/// to act on its pending events.
|
/// to act on its pending events.
|
||||||
|
@ -182,7 +194,8 @@ impl ServoGlue {
|
||||||
ServoUrl::parse(url)
|
ServoUrl::parse(url)
|
||||||
.map_err(|_| "Can't parse URL")
|
.map_err(|_| "Can't parse URL")
|
||||||
.and_then(|url| {
|
.and_then(|url| {
|
||||||
let event = WindowEvent::LoadUrl(self.browser_id, url);
|
let browser_id = self.get_browser_id()?;
|
||||||
|
let event = WindowEvent::LoadUrl(browser_id, url);
|
||||||
self.process_event(event)
|
self.process_event(event)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -190,7 +203,8 @@ impl ServoGlue {
|
||||||
/// Reload the page.
|
/// Reload the page.
|
||||||
pub fn reload(&mut self) -> Result<(), &'static str> {
|
pub fn reload(&mut self) -> Result<(), &'static str> {
|
||||||
debug!("reload");
|
debug!("reload");
|
||||||
let event = WindowEvent::Reload(self.browser_id);
|
let browser_id = self.get_browser_id()?;
|
||||||
|
let event = WindowEvent::Reload(browser_id);
|
||||||
self.process_event(event)
|
self.process_event(event)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -203,14 +217,16 @@ impl ServoGlue {
|
||||||
/// Go back in history.
|
/// Go back in history.
|
||||||
pub fn go_back(&mut self) -> Result<(), &'static str> {
|
pub fn go_back(&mut self) -> Result<(), &'static str> {
|
||||||
debug!("go_back");
|
debug!("go_back");
|
||||||
let event = WindowEvent::Navigation(self.browser_id, TraversalDirection::Back(1));
|
let browser_id = self.get_browser_id()?;
|
||||||
|
let event = WindowEvent::Navigation(browser_id, TraversalDirection::Back(1));
|
||||||
self.process_event(event)
|
self.process_event(event)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Go forward in history.
|
/// Go forward in history.
|
||||||
pub fn go_forward(&mut self) -> Result<(), &'static str> {
|
pub fn go_forward(&mut self) -> Result<(), &'static str> {
|
||||||
debug!("go_forward");
|
debug!("go_forward");
|
||||||
let event = WindowEvent::Navigation(self.browser_id, TraversalDirection::Forward(1));
|
let browser_id = self.get_browser_id()?;
|
||||||
|
let event = WindowEvent::Navigation(browser_id, TraversalDirection::Forward(1));
|
||||||
self.process_event(event)
|
self.process_event(event)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -329,7 +345,31 @@ impl ServoGlue {
|
||||||
info!("Alert: {}", message);
|
info!("Alert: {}", message);
|
||||||
let _ = sender.send(());
|
let _ = sender.send(());
|
||||||
},
|
},
|
||||||
EmbedderMsg::CloseBrowser |
|
EmbedderMsg::AllowOpeningBrowser(response_chan) => {
|
||||||
|
// Note: would be a place to handle pop-ups config.
|
||||||
|
// see Step 7 of #the-rules-for-choosing-a-browsing-context-given-a-browsing-context-name
|
||||||
|
if let Err(e) = response_chan.send(true) {
|
||||||
|
warn!("Failed to send AllowOpeningBrowser response: {}", e);
|
||||||
|
};
|
||||||
|
},
|
||||||
|
EmbedderMsg::BrowserCreated(new_browser_id) => {
|
||||||
|
// TODO: properly handle a new "tab"
|
||||||
|
self.browsers.push(new_browser_id);
|
||||||
|
if self.browser_id.is_none() {
|
||||||
|
self.browser_id = Some(new_browser_id);
|
||||||
|
}
|
||||||
|
self.events.push(WindowEvent::SelectBrowser(new_browser_id));
|
||||||
|
},
|
||||||
|
EmbedderMsg::CloseBrowser => {
|
||||||
|
// TODO: close the appropriate "tab".
|
||||||
|
let _ = self.browsers.pop();
|
||||||
|
if let Some(prev_browser_id) = self.browsers.last() {
|
||||||
|
self.browser_id = Some(*prev_browser_id);
|
||||||
|
self.events.push(WindowEvent::SelectBrowser(*prev_browser_id));
|
||||||
|
} else {
|
||||||
|
self.events.push(WindowEvent::Quit);
|
||||||
|
}
|
||||||
|
},
|
||||||
EmbedderMsg::Status(..) |
|
EmbedderMsg::Status(..) |
|
||||||
EmbedderMsg::SelectFiles(..) |
|
EmbedderMsg::SelectFiles(..) |
|
||||||
EmbedderMsg::MoveTo(..) |
|
EmbedderMsg::MoveTo(..) |
|
||||||
|
|
|
@ -26,6 +26,12 @@ pub struct Browser {
|
||||||
/// are not supported yet. None until created.
|
/// are not supported yet. None until created.
|
||||||
browser_id: Option<BrowserId>,
|
browser_id: Option<BrowserId>,
|
||||||
|
|
||||||
|
// A rudimentary stack of "tabs".
|
||||||
|
// EmbedderMsg::BrowserCreated will push onto it.
|
||||||
|
// EmbedderMsg::CloseBrowser will pop from it,
|
||||||
|
// and exit if it is empty afterwards.
|
||||||
|
browsers: Vec<BrowserId>,
|
||||||
|
|
||||||
title: Option<String>,
|
title: Option<String>,
|
||||||
status: Option<String>,
|
status: Option<String>,
|
||||||
favicon: Option<ServoUrl>,
|
favicon: Option<ServoUrl>,
|
||||||
|
@ -47,6 +53,7 @@ impl Browser {
|
||||||
title: None,
|
title: None,
|
||||||
current_url: None,
|
current_url: None,
|
||||||
browser_id: None,
|
browser_id: None,
|
||||||
|
browsers: Vec::new(),
|
||||||
status: None,
|
status: None,
|
||||||
favicon: None,
|
favicon: None,
|
||||||
loading_state: None,
|
loading_state: None,
|
||||||
|
@ -60,10 +67,6 @@ impl Browser {
|
||||||
mem::replace(&mut self.event_queue, Vec::new())
|
mem::replace(&mut self.event_queue, Vec::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_browser_id(&mut self, browser_id: BrowserId) {
|
|
||||||
self.browser_id = Some(browser_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn handle_window_events(&mut self, events: Vec<WindowEvent>) {
|
pub fn handle_window_events(&mut self, events: Vec<WindowEvent>) {
|
||||||
for event in events {
|
for event in events {
|
||||||
match event {
|
match event {
|
||||||
|
@ -284,6 +287,21 @@ impl Browser {
|
||||||
warn!("Failed to send AllowNavigation response: {}", e);
|
warn!("Failed to send AllowNavigation response: {}", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
EmbedderMsg::AllowOpeningBrowser(response_chan) => {
|
||||||
|
// Note: would be a place to handle pop-ups config.
|
||||||
|
// see Step 7 of #the-rules-for-choosing-a-browsing-context-given-a-browsing-context-name
|
||||||
|
if let Err(e) = response_chan.send(true) {
|
||||||
|
warn!("Failed to send AllowOpeningBrowser response: {}", e);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
EmbedderMsg::BrowserCreated(new_browser_id) => {
|
||||||
|
// TODO: properly handle a new "tab"
|
||||||
|
self.browsers.push(new_browser_id);
|
||||||
|
if self.browser_id.is_none() {
|
||||||
|
self.browser_id = Some(new_browser_id);
|
||||||
|
}
|
||||||
|
self.event_queue.push(WindowEvent::SelectBrowser(new_browser_id));
|
||||||
|
}
|
||||||
EmbedderMsg::KeyEvent(ch, key, state, modified) => {
|
EmbedderMsg::KeyEvent(ch, key, state, modified) => {
|
||||||
self.handle_key_from_servo(browser_id, ch, key, state, modified);
|
self.handle_key_from_servo(browser_id, ch, key, state, modified);
|
||||||
}
|
}
|
||||||
|
@ -309,10 +327,14 @@ impl Browser {
|
||||||
self.loading_state = Some(LoadingState::Loaded);
|
self.loading_state = Some(LoadingState::Loaded);
|
||||||
}
|
}
|
||||||
EmbedderMsg::CloseBrowser => {
|
EmbedderMsg::CloseBrowser => {
|
||||||
self.browser_id = None;
|
// TODO: close the appropriate "tab".
|
||||||
// Nothing left to do for now,
|
let _ = self.browsers.pop();
|
||||||
// but could hide a tab, and show another one, instead of quitting.
|
if let Some(prev_browser_id) = self.browsers.last() {
|
||||||
self.event_queue.push(WindowEvent::Quit);
|
self.browser_id = Some(*prev_browser_id);
|
||||||
|
self.event_queue.push(WindowEvent::SelectBrowser(*prev_browser_id));
|
||||||
|
} else {
|
||||||
|
self.event_queue.push(WindowEvent::Quit);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
EmbedderMsg::Shutdown => {
|
EmbedderMsg::Shutdown => {
|
||||||
self.shutdown_requested = true;
|
self.shutdown_requested = true;
|
||||||
|
|
|
@ -27,11 +27,10 @@ mod resources;
|
||||||
mod browser;
|
mod browser;
|
||||||
|
|
||||||
use backtrace::Backtrace;
|
use backtrace::Backtrace;
|
||||||
use servo::Servo;
|
use servo::{Servo, BrowserId};
|
||||||
use servo::compositing::windowing::WindowEvent;
|
use servo::compositing::windowing::WindowEvent;
|
||||||
use servo::config::opts::{self, ArgumentParsingResult, parse_url_or_filename};
|
use servo::config::opts::{self, ArgumentParsingResult, parse_url_or_filename};
|
||||||
use servo::config::servo_version;
|
use servo::config::servo_version;
|
||||||
use servo::ipc_channel::ipc;
|
|
||||||
use servo::servo_config::prefs::PREFS;
|
use servo::servo_config::prefs::PREFS;
|
||||||
use servo::servo_url::ServoUrl;
|
use servo::servo_url::ServoUrl;
|
||||||
use std::env;
|
use std::env;
|
||||||
|
@ -150,12 +149,8 @@ pub fn main() {
|
||||||
let target_url = cmdline_url.or(pref_url).or(blank_url).unwrap();
|
let target_url = cmdline_url.or(pref_url).or(blank_url).unwrap();
|
||||||
|
|
||||||
let mut servo = Servo::new(window.clone());
|
let mut servo = Servo::new(window.clone());
|
||||||
|
let browser_id = BrowserId::new();
|
||||||
let (sender, receiver) = ipc::channel().unwrap();
|
servo.handle_events(vec![WindowEvent::NewBrowser(target_url, browser_id)]);
|
||||||
servo.handle_events(vec![WindowEvent::NewBrowser(target_url, sender)]);
|
|
||||||
let browser_id = receiver.recv().unwrap();
|
|
||||||
browser.set_browser_id(browser_id);
|
|
||||||
servo.handle_events(vec![WindowEvent::SelectBrowser(browser_id)]);
|
|
||||||
|
|
||||||
servo.setup_logging();
|
servo.setup_logging();
|
||||||
|
|
||||||
|
|
|
@ -279733,6 +279733,11 @@
|
||||||
{}
|
{}
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
|
"html/browsers/windows/auxiliary-browsing-contexts/resources/opener-setter.html": [
|
||||||
|
[
|
||||||
|
{}
|
||||||
|
]
|
||||||
|
],
|
||||||
"html/browsers/windows/browsing-context-names/resources/choose-_parent-001-iframe-1.html": [
|
"html/browsers/windows/browsing-context-names/resources/choose-_parent-001-iframe-1.html": [
|
||||||
[
|
[
|
||||||
{}
|
{}
|
||||||
|
@ -352032,6 +352037,12 @@
|
||||||
{}
|
{}
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
|
"html/browsers/windows/auxiliary-browsing-contexts/opener-setter.html": [
|
||||||
|
[
|
||||||
|
"/html/browsers/windows/auxiliary-browsing-contexts/opener-setter.html",
|
||||||
|
{}
|
||||||
|
]
|
||||||
|
],
|
||||||
"html/browsers/windows/auxiliary-browsing-contexts/opener-setter.window.js": [
|
"html/browsers/windows/auxiliary-browsing-contexts/opener-setter.window.js": [
|
||||||
[
|
[
|
||||||
"/html/browsers/windows/auxiliary-browsing-contexts/opener-setter.window.html",
|
"/html/browsers/windows/auxiliary-browsing-contexts/opener-setter.window.html",
|
||||||
|
@ -587647,6 +587658,10 @@
|
||||||
"f82aa6f0abe0d16a8b132e531d165988af0af99f",
|
"f82aa6f0abe0d16a8b132e531d165988af0af99f",
|
||||||
"testharness"
|
"testharness"
|
||||||
],
|
],
|
||||||
|
"html/browsers/windows/auxiliary-browsing-contexts/opener-setter.html": [
|
||||||
|
"85c52e0b42e19bdd78dda120320d66ddbb2103b4",
|
||||||
|
"testharness"
|
||||||
|
],
|
||||||
"html/browsers/windows/auxiliary-browsing-contexts/opener-setter.window.js": [
|
"html/browsers/windows/auxiliary-browsing-contexts/opener-setter.window.js": [
|
||||||
"6d540ce97c94bff5845023098d0960d51dad62b4",
|
"6d540ce97c94bff5845023098d0960d51dad62b4",
|
||||||
"testharness"
|
"testharness"
|
||||||
|
@ -587675,6 +587690,10 @@
|
||||||
"6f43a5188c790577c4a1a03da270317eedba0fb0",
|
"6f43a5188c790577c4a1a03da270317eedba0fb0",
|
||||||
"support"
|
"support"
|
||||||
],
|
],
|
||||||
|
"html/browsers/windows/auxiliary-browsing-contexts/resources/opener-setter.html": [
|
||||||
|
"4112dae0cee66138a309b202a8d09d6b256c6d4d",
|
||||||
|
"support"
|
||||||
|
],
|
||||||
"html/browsers/windows/browsing-context-names/choose-_blank-001.html": [
|
"html/browsers/windows/browsing-context-names/choose-_blank-001.html": [
|
||||||
"a1416f2eb8437a8824a26a0e2e6aa6fdede37ffa",
|
"a1416f2eb8437a8824a26a0e2e6aa6fdede37ffa",
|
||||||
"testharness"
|
"testharness"
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
[embedded-credentials.tentative.sub.html]
|
[embedded-credentials.tentative.sub.html]
|
||||||
type: testharness
|
type: testharness
|
||||||
|
expected: TIMEOUT
|
||||||
[Embedded credentials are treated as network errors.]
|
[Embedded credentials are treated as network errors.]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
@ -7,14 +8,14 @@
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[Embedded credentials are treated as network errors in new windows.]
|
[Embedded credentials are treated as network errors in new windows.]
|
||||||
expected: FAIL
|
expected: TIMEOUT
|
||||||
|
|
||||||
[Embedded credentials matching the top-level are not treated as network errors for relative URLs.]
|
[Embedded credentials matching the top-level are not treated as network errors for relative URLs.]
|
||||||
expected: FAIL
|
expected: TIMEOUT
|
||||||
|
|
||||||
[Embedded credentials matching the top-level are not treated as network errors for same-origin URLs.]
|
[Embedded credentials matching the top-level are not treated as network errors for same-origin URLs.]
|
||||||
expected: FAIL
|
expected: TIMEOUT
|
||||||
|
|
||||||
[Embedded credentials matching the top-level are treated as network errors for cross-origin URLs.]
|
[Embedded credentials matching the top-level are treated as network errors for cross-origin URLs.]
|
||||||
expected: FAIL
|
expected: TIMEOUT
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
[resume-timer-on-history-back.html]
|
[resume-timer-on-history-back.html]
|
||||||
type: testharness
|
type: testharness
|
||||||
|
expected: TIMEOUT
|
||||||
[history.back() handles top level page timer correctly]
|
[history.back() handles top level page timer correctly]
|
||||||
expected: FAIL
|
expected: TIMEOUT
|
||||||
|
|
||||||
[history.back() handles nested iframe timer correctly]
|
[history.back() handles nested iframe timer correctly]
|
||||||
expected: FAIL
|
expected: NOTRUN
|
||||||
|
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
[window-name-after-cross-origin-aux-frame-navigation.sub.html]
|
|
||||||
type: testharness
|
|
||||||
expected: ERROR
|
|
||||||
[Test that the window name is correct]
|
|
||||||
expected: NOTRUN
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
[window-name-after-cross-origin-main-frame-navigation.sub.html]
|
[window-name-after-cross-origin-main-frame-navigation.sub.html]
|
||||||
type: testharness
|
type: testharness
|
||||||
expected: ERROR
|
|
||||||
[window.name should equal "" after a cross-origin main frame navigation]
|
[window.name should equal "" after a cross-origin main frame navigation]
|
||||||
expected: TIMEOUT
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
[window-name-after-same-origin-aux-frame-navigation.sub.html]
|
|
||||||
type: testharness
|
|
||||||
expected: ERROR
|
|
||||||
[Test that the window name is correct]
|
|
||||||
expected: NOTRUN
|
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
[005.html]
|
[005.html]
|
||||||
type: testharness
|
type: testharness
|
||||||
expected: TIMEOUT
|
expected: ERROR
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
[006.html]
|
|
||||||
type: testharness
|
|
||||||
expected: TIMEOUT
|
|
|
@ -2,4 +2,3 @@
|
||||||
type: testharness
|
type: testharness
|
||||||
[Link with onclick javascript url and href navigation ]
|
[Link with onclick javascript url and href navigation ]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
[008.html]
|
[008.html]
|
||||||
type: testharness
|
type: testharness
|
||||||
expected: TIMEOUT
|
[Link with onclick form submit to javascript url and href navigation ]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
[009.html]
|
[009.html]
|
||||||
type: testharness
|
type: testharness
|
||||||
expected: TIMEOUT
|
[Link with onclick form submit to javascript url with document.write and href navigation ]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
[010.html]
|
|
||||||
type: testharness
|
|
||||||
[Link with onclick form submit to javascript url with delayed document.write and href navigation ]
|
|
||||||
expected: FAIL
|
|
|
@ -1,3 +0,0 @@
|
||||||
[011.html]
|
|
||||||
type: testharness
|
|
||||||
expected: TIMEOUT
|
|
|
@ -1,6 +0,0 @@
|
||||||
[child_navigates_parent_submit.html]
|
|
||||||
type: testharness
|
|
||||||
expected: TIMEOUT
|
|
||||||
[Child document navigating parent via submit ]
|
|
||||||
expected: TIMEOUT
|
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
[javascript-url-abort-return-value-string.tentative.html]
|
|
||||||
[Aborting fetch for javascript:string navigation]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
[pageload-image-in-popup.html]
|
|
||||||
expected: ERROR
|
|
||||||
[The document for a standalone media file should have one child in the body.]
|
|
||||||
expected: NOTRUN
|
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
[history_back_1.html]
|
|
||||||
[history.back() with session history]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
[history_forward_1.html]
|
|
||||||
[history.forward() with session history]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
[history_go_no_argument.html]
|
|
||||||
[history.go()]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
[history_go_to_uri.html]
|
|
||||||
[history.go() negative tests]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
[history_go_zero.html]
|
|
||||||
[history.go(0)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -1,24 +1,5 @@
|
||||||
[001.html]
|
[001.html]
|
||||||
type: testharness
|
expected: TIMEOUT
|
||||||
expected: ERROR
|
|
||||||
[Session history length on initial load]
|
|
||||||
expected: NOTRUN
|
|
||||||
|
|
||||||
[Session history length on adding new iframe]
|
|
||||||
expected: NOTRUN
|
|
||||||
|
|
||||||
[Navigating second iframe]
|
|
||||||
expected: NOTRUN
|
|
||||||
|
|
||||||
[Traversing history back (1)]
|
|
||||||
expected: NOTRUN
|
|
||||||
|
|
||||||
[Navigating first iframe]
|
|
||||||
expected: NOTRUN
|
|
||||||
|
|
||||||
[Traversing history back (2)]
|
|
||||||
expected: NOTRUN
|
|
||||||
|
|
||||||
[Traversing history forward]
|
[Traversing history forward]
|
||||||
expected: NOTRUN
|
expected: NOTRUN
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,5 @@
|
||||||
[002.html]
|
[002.html]
|
||||||
type: testharness
|
expected: TIMEOUT
|
||||||
expected: ERROR
|
|
||||||
[Session history length on initial load]
|
|
||||||
expected: NOTRUN
|
|
||||||
|
|
||||||
[Session history length on adding new iframe]
|
|
||||||
expected: NOTRUN
|
|
||||||
|
|
||||||
[Navigating second iframe]
|
[Navigating second iframe]
|
||||||
expected: NOTRUN
|
expected: TIMEOUT
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
[traverse_the_history_1.html]
|
[traverse_the_history_1.html]
|
||||||
|
type: testharness
|
||||||
[Multiple history traversals from the same task]
|
[Multiple history traversals from the same task]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
[traverse_the_history_2.html]
|
[traverse_the_history_2.html]
|
||||||
[Multiple history traversals, last would be aborted]
|
[Multiple history traversals, last would be aborted]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
[traverse_the_history_4.html]
|
[traverse_the_history_4.html]
|
||||||
[Multiple history traversals, last would be aborted]
|
[Multiple history traversals, last would be aborted]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
[traverse_the_history_unload_1.html]
|
|
||||||
[Traversing the history, unload event is fired on doucment]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
[traverse_the_history_write_after_load_1.html]
|
[traverse_the_history_write_after_load_1.html]
|
||||||
|
type: testharness
|
||||||
|
expected: TIMEOUT
|
||||||
[Traverse the history after document.write after the load event]
|
[Traverse the history after document.write after the load event]
|
||||||
expected: FAIL
|
expected: TIMEOUT
|
||||||
|
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
[traverse_the_history_write_after_load_2.html]
|
|
||||||
[Traverse the history back and forward when a history entry is written after the load event]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
[traverse_the_history_write_onload_1.html]
|
|
||||||
[Traverse the history when a history entry is written in the load event]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
[traverse_the_history_write_onload_2.html]
|
|
||||||
[Traverse the history back and forward when a history entry is written in the load event]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
[reload_document_write.html]
|
|
||||||
type: testharness
|
|
||||||
[Reload document with document.written content]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
[scripted_click_assign_during_load.html]
|
[scripted_click_assign_during_load.html]
|
||||||
type: testharness
|
type: testharness
|
||||||
expected: ERROR
|
|
||||||
[Assignment to location with click during load]
|
[Assignment to location with click during load]
|
||||||
expected: NOTRUN
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
[scripted_click_location_assign_during_load.html]
|
|
||||||
type: testharness
|
|
||||||
expected: ERROR
|
|
||||||
[location.assign with click during load]
|
|
||||||
expected: NOTRUN
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
[scripted_form_submit_assign_during_load.html]
|
[scripted_form_submit_assign_during_load.html]
|
||||||
type: testharness
|
type: testharness
|
||||||
expected: ERROR
|
|
||||||
[Assignment to location with form submit during load]
|
[Assignment to location with form submit during load]
|
||||||
expected: NOTRUN
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
[navigation-in-onload.tentative.html]
|
[navigation-in-onload.tentative.html]
|
||||||
expected: ERROR
|
|
||||||
[Navigation in onload handler]
|
[Navigation in onload handler]
|
||||||
expected: NOTRUN
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
[cross-origin-objects-on-new-window.html]
|
[cross-origin-objects-on-new-window.html]
|
||||||
type: testharness
|
type: testharness
|
||||||
[Cross-origin behavior of Window and Location on new Window]
|
expected: TIMEOUT
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
[window_length.html]
|
|
||||||
type: testharness
|
|
||||||
[Opened window]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Iframe in opened window]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
[close_beforeunload.html]
|
|
||||||
type: testharness
|
|
||||||
expected: ERROR
|
|
||||||
[Running beforeunload handler in window.close()]
|
|
||||||
expected: NOTRUN
|
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
[close_unload.html]
|
|
||||||
type: testharness
|
|
||||||
expected: ERROR
|
|
||||||
[Running unload handler in window.close()]
|
|
||||||
expected: NOTRUN
|
|
||||||
|
|
|
@ -3,12 +3,3 @@
|
||||||
[first argument: absolute url]
|
[first argument: absolute url]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[first argument: empty url]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[second argument: passing a non-empty name]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[second argument: setting name after opening]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
[open-features-negative-innerwidth-innerheight.html]
|
[open-features-negative-innerwidth-innerheight.html]
|
||||||
type: testharness
|
type: testharness
|
||||||
expected: ERROR
|
[HTML: window.open `features`: negative values for legacy `innerwidth`, `innerheight`]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
[open-features-negative-screenx-screeny.html]
|
[open-features-negative-screenx-screeny.html]
|
||||||
type: testharness
|
type: testharness
|
||||||
expected: ERROR
|
[HTML: window.open `features`: negative values for legacy `screenx`, `screeny`]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
[open-features-negative-top-left.html]
|
[open-features-negative-top-left.html]
|
||||||
type: testharness
|
type: testharness
|
||||||
expected: ERROR
|
[HTML: window.open `features`: negative values for `top`, `left`]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
[open-features-negative-width-height.html]
|
[open-features-negative-width-height.html]
|
||||||
type: testharness
|
type: testharness
|
||||||
expected: ERROR
|
[HTML: window.open `features`: negative values for `width`, `height`]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
[open-features-non-integer-height.html]
|
[open-features-non-integer-height.html]
|
||||||
type: testharness
|
type: testharness
|
||||||
expected: ERROR
|
[HTML: window.open `features`: non-integer values for feature `height`]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
[open-features-non-integer-innerheight.html]
|
[open-features-non-integer-innerheight.html]
|
||||||
type: testharness
|
type: testharness
|
||||||
expected: ERROR
|
[HTML: window.open `features`: non-integer values for legacy feature `innerheight`]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
[open-features-non-integer-innerwidth.html]
|
[open-features-non-integer-innerwidth.html]
|
||||||
type: testharness
|
type: testharness
|
||||||
expected: ERROR
|
[HTML: window.open `features`: non-integer values for legacy feature `innerwidth`]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
[open-features-non-integer-left.html]
|
[open-features-non-integer-left.html]
|
||||||
type: testharness
|
type: testharness
|
||||||
expected: ERROR
|
[HTML: window.open `features`: non-integer values for feature `left`]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
[open-features-non-integer-screenx.html]
|
[open-features-non-integer-screenx.html]
|
||||||
type: testharness
|
type: testharness
|
||||||
expected: ERROR
|
[HTML: window.open `features`: non-integer values for legacy feature `screenx`]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
[open-features-non-integer-screeny.html]
|
[open-features-non-integer-screeny.html]
|
||||||
type: testharness
|
type: testharness
|
||||||
expected: ERROR
|
[HTML: window.open `features`: non-integer values for legacy feature `screeny`]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
[open-features-non-integer-top.html]
|
[open-features-non-integer-top.html]
|
||||||
type: testharness
|
type: testharness
|
||||||
expected: ERROR
|
[HTML: window.open `features`: non-integer values for feature `top`]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
[open-features-non-integer-width.html]
|
[open-features-non-integer-width.html]
|
||||||
type: testharness
|
type: testharness
|
||||||
expected: ERROR
|
[HTML: window.open `features`: non-integer values for feature `width`]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -1,23 +1,7 @@
|
||||||
[open-features-tokenization-noopener.html]
|
[open-features-tokenization-noopener.html]
|
||||||
type: testharness
|
|
||||||
[tokenization should skip window features separators before `name`]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[feature `name` should be converted to ASCII lowercase]
|
[feature `name` should be converted to ASCII lowercase]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[after `name`, tokenization should skip window features separators that are not "=" or ","]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Tokenizing should ignore window feature separators except "," after initial "=" and before value]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Tokenizing should read characters until first window feature separator as `value`]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
["noopener" should be based on name (key), not value]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[invalid feature names should not tokenize as "noopener"]
|
[invalid feature names should not tokenize as "noopener"]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
[discard_iframe_history_1.html]
|
[discard_iframe_history_1.html]
|
||||||
type: testharness
|
type: testharness
|
||||||
expected: ERROR
|
|
||||||
[Removing iframe from document removes it from history]
|
[Removing iframe from document removes it from history]
|
||||||
expected: NOTRUN
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
[discard_iframe_history_2.html]
|
[discard_iframe_history_2.html]
|
||||||
type: testharness
|
type: testharness
|
||||||
expected: ERROR
|
|
||||||
[Removing iframe from document via innerHTML removes it from history]
|
[Removing iframe from document via innerHTML removes it from history]
|
||||||
expected: NOTRUN
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
[discard_iframe_history_3.html]
|
|
||||||
type: testharness
|
|
||||||
expected: ERROR
|
|
||||||
[Removing iframe from document removes it from history]
|
|
||||||
expected: NOTRUN
|
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
[discard_iframe_history_4.html]
|
|
||||||
type: testharness
|
|
||||||
expected: ERROR
|
|
||||||
[Removing iframe from document removes it from history]
|
|
||||||
expected: NOTRUN
|
|
||||||
|
|
|
@ -335,9 +335,6 @@
|
||||||
[A SecurityError exception must be thrown when window.stop is accessed from a different origin.]
|
[A SecurityError exception must be thrown when window.stop is accessed from a different origin.]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[A SecurityError exception should not be thrown when window.opener is accessed from a different origin.]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[A SecurityError exception should not be thrown when window.blur is accessed from a different origin.]
|
[A SecurityError exception should not be thrown when window.blur is accessed from a different origin.]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
[window-open-noopener.html]
|
[window-open-noopener.html]
|
||||||
type: testharness
|
type: testharness
|
||||||
expected: ERROR
|
|
||||||
[window.open() with 'noopener' should not reuse existing target]
|
[window.open() with 'noopener' should not reuse existing target]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
@ -27,15 +26,13 @@
|
||||||
|
|
||||||
|
|
||||||
[window-open-noopener.html?_parent]
|
[window-open-noopener.html?_parent]
|
||||||
expected: ERROR
|
|
||||||
[noopener window.open targeting _parent]
|
[noopener window.open targeting _parent]
|
||||||
expected: NOTRUN
|
expected: FAIL
|
||||||
|
|
||||||
|
|
||||||
[window-open-noopener.html?_top]
|
[window-open-noopener.html?_top]
|
||||||
expected: ERROR
|
|
||||||
[noopener window.open targeting _top]
|
[noopener window.open targeting _top]
|
||||||
expected: NOTRUN
|
expected: FAIL
|
||||||
|
|
||||||
|
|
||||||
[window-open-noopener.html?indexed]
|
[window-open-noopener.html?indexed]
|
||||||
|
@ -63,7 +60,12 @@
|
||||||
|
|
||||||
|
|
||||||
[window-open-noopener.html?_self]
|
[window-open-noopener.html?_self]
|
||||||
expected: ERROR
|
|
||||||
[noopener window.open targeting _self]
|
[noopener window.open targeting _self]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[noopener window.open targeting _parent]
|
||||||
|
expected: NOTRUN
|
||||||
|
|
||||||
|
[noopener window.open targeting _top]
|
||||||
expected: NOTRUN
|
expected: NOTRUN
|
||||||
|
|
||||||
|
|
|
@ -5,9 +5,6 @@
|
||||||
[Window method: blur]
|
[Window method: blur]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[Window method: open]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Window method: confirm]
|
[Window method: confirm]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
@ -23,9 +20,6 @@
|
||||||
[Window readonly attribute: applicationCache]
|
[Window readonly attribute: applicationCache]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[Window attribute: opener]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Window attribute: onmousewheel]
|
[Window attribute: onmousewheel]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
[opener-closed.html]
|
|
||||||
type: testharness
|
|
||||||
expected: TIMEOUT
|
|
|
@ -1,3 +0,0 @@
|
||||||
[opener-multiple.html]
|
|
||||||
type: testharness
|
|
||||||
expected: TIMEOUT
|
|
|
@ -1,5 +0,0 @@
|
||||||
[opener-noopener.html]
|
|
||||||
type: testharness
|
|
||||||
[Auxiliary browsing context created via `window.open` setting `noopener` should report `window.opener` `null`]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
[opener-noreferrer.html]
|
|
||||||
type: testharness
|
|
||||||
[Auxiliary browsing context created with `rel="noreferrer"` should report `window.opener` `null`]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -1,22 +0,0 @@
|
||||||
[opener-setter.window.html]
|
|
||||||
[Setting window.opener to undefined]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Setting window.opener to 42]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Setting window.opener to function () { return "hi" }]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Setting window.opener to hi]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Setting window.opener to [object Object\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Setting window.opener to ]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Setting window.opener to Symbol()]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
[opener.html]
|
|
||||||
type: testharness
|
|
||||||
expected: TIMEOUT
|
|
|
@ -1,8 +0,0 @@
|
||||||
[choose-_blank-001.html]
|
|
||||||
type: testharness
|
|
||||||
[window.open into `_blank` should create a new browsing context each time]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[`_blank` should be ASCII case-insensitive]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
[choose-_blank-002.html]
|
|
||||||
type: testharness
|
|
||||||
[Context for opened noreferrer link targeted to "_blank" should not have opener reference]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
[choose-_parent-001.html]
|
|
||||||
type: testharness
|
|
||||||
expected: TIMEOUT
|
|
||||||
[The parent browsing context must be chosen if the given name is `_parent`]
|
|
||||||
expected: TIMEOUT
|
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
[choose-_parent-002.html]
|
|
||||||
type: testharness
|
|
||||||
expected: ERROR
|
|
||||||
[choosing _parent context: multiple nested contexts]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
[choose-_parent-003.html]
|
|
||||||
type: testharness
|
|
||||||
expected: ERROR
|
|
||||||
[_parent should reuse window.parent context]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
[choose-_parent-004.html]
|
|
||||||
type: testharness
|
|
||||||
expected: TIMEOUT
|
|
||||||
[choosing _parent context should be case-insensitive]
|
|
||||||
expected: TIMEOUT
|
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
[choose-_self-001.html]
|
|
||||||
type: testharness
|
|
||||||
expected: TIMEOUT
|
|
||||||
[The current browsing context must be chosen if the given name is "_self"]
|
|
||||||
expected: TIMEOUT
|
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
[choose-_self-002.html]
|
|
||||||
type: testharness
|
|
||||||
expected: TIMEOUT
|
|
||||||
[choosing _self context should be case-insensitive]
|
|
||||||
expected: TIMEOUT
|
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
[choose-_top-001.html]
|
|
||||||
type: testharness
|
|
||||||
[Should choose current browsing context for "_top" if current is top]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
[choose-_top-002.html]
|
|
||||||
type: testharness
|
|
||||||
[Should choose top browsing context for "_top" if current is not top]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
[choose-_top-003.html]
|
|
||||||
type: testharness
|
|
||||||
[choosing _top context should be case-insensitive]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -2,7 +2,3 @@
|
||||||
type: testharness
|
type: testharness
|
||||||
[A embedded browsing context has empty-string default name]
|
[A embedded browsing context has empty-string default name]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[A browsing context which is opened by window.open() method with '_blank' parameter has empty-string default name]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
[choose-existing-001.html]
|
|
||||||
type: testharness
|
|
||||||
expected: TIMEOUT
|
|
||||||
[An existing browsing context must be chosen if the given name is the same as its name]
|
|
||||||
expected: TIMEOUT
|
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
[noreferrer-null-opener.html]
|
|
||||||
type: testharness
|
|
||||||
[rel=noreferrer nullifies window.opener]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -1,6 +1,13 @@
|
||||||
[noreferrer-window-name.html]
|
[noreferrer-window-name.html]
|
||||||
type: testharness
|
type: testharness
|
||||||
expected: TIMEOUT
|
expected: TIMEOUT
|
||||||
[rel=noreferrer and reuse of names]
|
|
||||||
|
[Following a noreferrer link with a named target should not cause creation of a window that can be targeted by another noreferrer link with the same named target]
|
||||||
expected: TIMEOUT
|
expected: TIMEOUT
|
||||||
|
|
||||||
|
[Targeting a rel=noreferrer link at an existing named subframe should work]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[Targeting a rel=noreferrer link at an existing named window should work]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
[targeting-cross-origin-nested-browsing-contexts.html]
|
[targeting-cross-origin-nested-browsing-contexts.html]
|
||||||
type: testharness
|
type: testharness
|
||||||
expected: TIMEOUT
|
[Targeting nested browsing contexts]
|
||||||
|
expected: FAIL
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue