mirror of
https://github.com/servo/servo.git
synced 2025-08-03 12:40:06 +01:00
Auto merge of #25869 - iulianR:issue-23057-tinifiledialogs, r=jdm
Move tinyfiledialog call from script to embedder <!-- Please describe your changes on the following line: --> PR is based on work started in #23651. I rebased on top of master and addressed review comments. Handling the `PromptPermission` message in `libsimpleservo` is probably not ideal. Looking forward to make more changes, just let me know how I should proceed. --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `___` with appropriate data: --> - [x] `./mach build -d` does not report any errors - [x] `./mach test-tidy` does not report any errors - [x] These changes fix #23057 (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. -->
This commit is contained in:
commit
d42835b238
9 changed files with 178 additions and 68 deletions
|
@ -5,6 +5,7 @@
|
|||
use crate::dom::bindings::cell::DomRefCell;
|
||||
use crate::dom::bindings::codegen::Bindings::BroadcastChannelBinding::BroadcastChannelMethods;
|
||||
use crate::dom::bindings::codegen::Bindings::EventSourceBinding::EventSourceBinding::EventSourceMethods;
|
||||
use crate::dom::bindings::codegen::Bindings::PermissionStatusBinding::PermissionState;
|
||||
use crate::dom::bindings::codegen::Bindings::VoidFunctionBinding::VoidFunction;
|
||||
use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
|
||||
use crate::dom::bindings::codegen::Bindings::WorkerGlobalScopeBinding::WorkerGlobalScopeMethods;
|
||||
|
@ -60,6 +61,7 @@ use crate::timers::{OneshotTimers, TimerCallback};
|
|||
use content_security_policy::CspList;
|
||||
use devtools_traits::{PageError, ScriptToDevtoolsControlMsg};
|
||||
use dom_struct::dom_struct;
|
||||
use embedder_traits::EmbedderMsg;
|
||||
use ipc_channel::ipc::{self, IpcSender};
|
||||
use ipc_channel::router::ROUTER;
|
||||
use js::glue::{IsWrapper, UnwrapObjectDynamic};
|
||||
|
@ -181,6 +183,9 @@ pub struct GlobalScope {
|
|||
/// The origin of the globalscope
|
||||
origin: MutableOrigin,
|
||||
|
||||
/// A map for storing the previous permission state read results.
|
||||
permission_state_invocation_results: DomRefCell<HashMap<String, PermissionState>>,
|
||||
|
||||
/// The microtask queue associated with this global.
|
||||
///
|
||||
/// It is refcounted because windows in the same script thread share the
|
||||
|
@ -567,6 +572,7 @@ impl GlobalScope {
|
|||
timers: OneshotTimers::new(scheduler_chan),
|
||||
init_timers: Default::default(),
|
||||
origin,
|
||||
permission_state_invocation_results: Default::default(),
|
||||
microtask_queue,
|
||||
list_auto_close_worker: Default::default(),
|
||||
event_source_tracker: DOMTracker::new(),
|
||||
|
@ -1693,6 +1699,12 @@ impl GlobalScope {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn permission_state_invocation_results(
|
||||
&self,
|
||||
) -> &DomRefCell<HashMap<String, PermissionState>> {
|
||||
&self.permission_state_invocation_results
|
||||
}
|
||||
|
||||
pub fn track_worker(&self, closing_worker: Arc<AtomicBool>) {
|
||||
self.list_auto_close_worker
|
||||
.borrow_mut()
|
||||
|
@ -1898,6 +1910,14 @@ impl GlobalScope {
|
|||
&self.script_to_constellation_chan
|
||||
}
|
||||
|
||||
pub fn send_to_embedder(&self, msg: EmbedderMsg) {
|
||||
self.send_to_constellation(ScriptMsg::ForwardToEmbedder(msg));
|
||||
}
|
||||
|
||||
pub fn send_to_constellation(&self, msg: ScriptMsg) {
|
||||
self.script_to_constellation_chan().send(msg).unwrap();
|
||||
}
|
||||
|
||||
pub fn scheduler_chan(&self) -> &IpcSender<TimerSchedulerMsg> {
|
||||
&self.scheduler_chan
|
||||
}
|
||||
|
|
|
@ -19,19 +19,13 @@ use crate::dom::promise::Promise;
|
|||
use crate::realms::{AlreadyInRealm, InRealm};
|
||||
use crate::script_runtime::JSContext;
|
||||
use dom_struct::dom_struct;
|
||||
use embedder_traits::{self, EmbedderMsg, PermissionPrompt, PermissionRequest};
|
||||
use ipc_channel::ipc;
|
||||
use js::conversions::ConversionResult;
|
||||
use js::jsapi::JSObject;
|
||||
use js::jsval::{ObjectValue, UndefinedValue};
|
||||
use servo_config::pref;
|
||||
use std::rc::Rc;
|
||||
#[cfg(target_os = "linux")]
|
||||
use tinyfiledialogs::{self, MessageBoxIcon, YesNo};
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
const DIALOG_TITLE: &'static str = "Permission request dialog";
|
||||
const NONSECURE_DIALOG_MESSAGE: &'static str = "feature is only safe to use in secure context,\
|
||||
but servo can't guarantee\n that the current context is secure. Do you want to proceed and grant permission?";
|
||||
const REQUEST_DIALOG_MESSAGE: &'static str = "Do you want to grant permission for";
|
||||
|
||||
pub trait PermissionAlgorithm {
|
||||
type Descriptor;
|
||||
|
@ -143,7 +137,6 @@ impl Permissions {
|
|||
// (Revoke) Step 3.
|
||||
let globalscope = self.global();
|
||||
globalscope
|
||||
.as_window()
|
||||
.permission_state_invocation_results()
|
||||
.borrow_mut()
|
||||
.remove(&root_desc.name.to_string());
|
||||
|
@ -176,7 +169,6 @@ impl Permissions {
|
|||
// (Revoke) Step 3.
|
||||
let globalscope = self.global();
|
||||
globalscope
|
||||
.as_window()
|
||||
.permission_state_invocation_results()
|
||||
.borrow_mut()
|
||||
.remove(&root_desc.name.to_string());
|
||||
|
@ -259,17 +251,13 @@ impl PermissionAlgorithm for Permissions {
|
|||
// Step 3.
|
||||
PermissionState::Prompt => {
|
||||
let perm_name = status.get_query();
|
||||
|
||||
let globalscope = GlobalScope::current().expect("No current global object");
|
||||
let prompt =
|
||||
PermissionPrompt::Request(embedder_traits::PermissionName::from(perm_name));
|
||||
|
||||
// https://w3c.github.io/permissions/#request-permission-to-use (Step 3 - 4)
|
||||
let state = prompt_user(
|
||||
&format!("{} {} ?", REQUEST_DIALOG_MESSAGE, perm_name.clone()),
|
||||
globalscope.is_headless(),
|
||||
);
|
||||
|
||||
let globalscope = GlobalScope::current().expect("No current global object");
|
||||
let state = prompt_user_from_embedder(prompt, &globalscope);
|
||||
globalscope
|
||||
.as_window()
|
||||
.permission_state_invocation_results()
|
||||
.borrow_mut()
|
||||
.insert(perm_name.to_string(), state);
|
||||
|
@ -292,7 +280,7 @@ pub fn get_descriptor_permission_state(
|
|||
env_settings_obj: Option<&GlobalScope>,
|
||||
) -> PermissionState {
|
||||
// Step 1.
|
||||
let settings = match env_settings_obj {
|
||||
let globalscope = match env_settings_obj {
|
||||
Some(env_settings_obj) => DomRoot::from_ref(env_settings_obj),
|
||||
None => GlobalScope::current().expect("No current global object"),
|
||||
};
|
||||
|
@ -308,22 +296,20 @@ pub fn get_descriptor_permission_state(
|
|||
if pref!(dom.permissions.testing.allowed_in_nonsecure_contexts) {
|
||||
PermissionState::Granted
|
||||
} else {
|
||||
settings
|
||||
.as_window()
|
||||
globalscope
|
||||
.permission_state_invocation_results()
|
||||
.borrow_mut()
|
||||
.remove(&permission_name.to_string());
|
||||
|
||||
prompt_user(
|
||||
&format!("The {} {}", permission_name, NONSECURE_DIALOG_MESSAGE),
|
||||
settings.is_headless(),
|
||||
prompt_user_from_embedder(
|
||||
PermissionPrompt::Insecure(embedder_traits::PermissionName::from(permission_name)),
|
||||
&globalscope,
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
// Step 3.
|
||||
if let Some(prev_result) = settings
|
||||
.as_window()
|
||||
if let Some(prev_result) = globalscope
|
||||
.permission_state_invocation_results()
|
||||
.borrow()
|
||||
.get(&permission_name.to_string())
|
||||
|
@ -332,8 +318,7 @@ pub fn get_descriptor_permission_state(
|
|||
}
|
||||
|
||||
// Store the invocation result
|
||||
settings
|
||||
.as_window()
|
||||
globalscope
|
||||
.permission_state_invocation_results()
|
||||
.borrow_mut()
|
||||
.insert(permission_name.to_string(), state);
|
||||
|
@ -342,28 +327,6 @@ pub fn get_descriptor_permission_state(
|
|||
state
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn prompt_user(message: &str, headless: bool) -> PermissionState {
|
||||
if headless {
|
||||
return PermissionState::Denied;
|
||||
}
|
||||
match tinyfiledialogs::message_box_yes_no(
|
||||
DIALOG_TITLE,
|
||||
message,
|
||||
MessageBoxIcon::Question,
|
||||
YesNo::No,
|
||||
) {
|
||||
YesNo::Yes => PermissionState::Granted,
|
||||
YesNo::No => PermissionState::Denied,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
fn prompt_user(_message: &str, _headless: bool) -> PermissionState {
|
||||
// TODO popup only supported on linux
|
||||
PermissionState::Denied
|
||||
}
|
||||
|
||||
// https://w3c.github.io/permissions/#allowed-in-non-secure-contexts
|
||||
fn allowed_in_nonsecure_contexts(permission_name: &PermissionName) -> bool {
|
||||
match *permission_name {
|
||||
|
@ -391,3 +354,40 @@ fn allowed_in_nonsecure_contexts(permission_name: &PermissionName) -> bool {
|
|||
PermissionName::Persistent_storage => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn prompt_user_from_embedder(prompt: PermissionPrompt, gs: &GlobalScope) -> PermissionState {
|
||||
let (sender, receiver) = ipc::channel().expect("Failed to create IPC channel!");
|
||||
gs.send_to_embedder(EmbedderMsg::PromptPermission(prompt, sender));
|
||||
|
||||
match receiver.recv() {
|
||||
Ok(PermissionRequest::Granted) => PermissionState::Granted,
|
||||
Ok(PermissionRequest::Denied) => PermissionState::Denied,
|
||||
Err(e) => {
|
||||
warn!(
|
||||
"Failed to receive permission state from embedder ({:?}).",
|
||||
e
|
||||
);
|
||||
PermissionState::Denied
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PermissionName> for embedder_traits::PermissionName {
|
||||
fn from(permission_name: PermissionName) -> Self {
|
||||
match permission_name {
|
||||
PermissionName::Geolocation => embedder_traits::PermissionName::Geolocation,
|
||||
PermissionName::Notifications => embedder_traits::PermissionName::Notifications,
|
||||
PermissionName::Push => embedder_traits::PermissionName::Push,
|
||||
PermissionName::Midi => embedder_traits::PermissionName::Midi,
|
||||
PermissionName::Camera => embedder_traits::PermissionName::Camera,
|
||||
PermissionName::Microphone => embedder_traits::PermissionName::Microphone,
|
||||
PermissionName::Speaker => embedder_traits::PermissionName::Speaker,
|
||||
PermissionName::Device_info => embedder_traits::PermissionName::DeviceInfo,
|
||||
PermissionName::Background_sync => embedder_traits::PermissionName::BackgroundSync,
|
||||
PermissionName::Bluetooth => embedder_traits::PermissionName::Bluetooth,
|
||||
PermissionName::Persistent_storage => {
|
||||
embedder_traits::PermissionName::PersistentStorage
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,6 @@ use crate::dom::bindings::codegen::Bindings::DocumentBinding::{
|
|||
};
|
||||
use crate::dom::bindings::codegen::Bindings::HistoryBinding::HistoryBinding::HistoryMethods;
|
||||
use crate::dom::bindings::codegen::Bindings::MediaQueryListBinding::MediaQueryListBinding::MediaQueryListMethods;
|
||||
use crate::dom::bindings::codegen::Bindings::PermissionStatusBinding::PermissionState;
|
||||
use crate::dom::bindings::codegen::Bindings::RequestBinding::RequestInit;
|
||||
use crate::dom::bindings::codegen::Bindings::VoidFunctionBinding::VoidFunction;
|
||||
use crate::dom::bindings::codegen::Bindings::WindowBinding::{
|
||||
|
@ -275,9 +274,6 @@ pub struct Window {
|
|||
#[ignore_malloc_size_of = "defined in webxr"]
|
||||
webxr_registry: webxr_api::Registry,
|
||||
|
||||
/// A map for storing the previous permission state read results.
|
||||
permission_state_invocation_results: DomRefCell<HashMap<String, PermissionState>>,
|
||||
|
||||
/// All of the elements that have an outstanding image request that was
|
||||
/// initiated by layout during a reflow. They are stored in the script thread
|
||||
/// to ensure that the element can be marked dirty when the image data becomes
|
||||
|
@ -476,12 +472,6 @@ impl Window {
|
|||
Worklet::new(self, WorkletGlobalScopeType::Paint)
|
||||
}
|
||||
|
||||
pub fn permission_state_invocation_results(
|
||||
&self,
|
||||
) -> &DomRefCell<HashMap<String, PermissionState>> {
|
||||
&self.permission_state_invocation_results
|
||||
}
|
||||
|
||||
pub fn pending_image_notification(&self, response: PendingImageResponse) {
|
||||
//XXXjdm could be more efficient to send the responses to the layout thread,
|
||||
// rather than making the layout thread talk to the image cache to
|
||||
|
@ -2333,7 +2323,6 @@ impl Window {
|
|||
webgl_chan,
|
||||
webvr_chan,
|
||||
webxr_registry,
|
||||
permission_state_invocation_results: Default::default(),
|
||||
pending_layout_images: Default::default(),
|
||||
unminified_js_dir: Default::default(),
|
||||
test_worklet: Default::default(),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue