mirror of
https://github.com/servo/servo.git
synced 2025-07-29 10:10:34 +01:00
Auto merge of #26029 - paulrouget:uitask, r=jdm
Set user interactions for tasks fix #26026 I need help here. Retrieving the interaction flag from the promise handle crashes. ```rust let interaction = GetPromiseUserInputEventHandlingState(promise); ``` ``` Stack trace for thread "ScriptThread PipelineId { namespace_id: PipelineNamespaceId(1), index: PipelineIndex(1) }" stack backtrace: 0: backtrace::backtrace::libunwind::trace at /Users/paul/.cargo/git/checkouts/backtrace-rs-96ebaf1bcb788384/91a0aa4/src/backtrace/libunwind.rs:86 backtrace::backtrace::trace_unsynchronized at /Users/paul/.cargo/git/checkouts/backtrace-rs-96ebaf1bcb788384/91a0aa4/src/backtrace/mod.rs:66 1: <servo::backtrace::Print as core::fmt::Debug>::fmt at ports/glutin/backtrace.rs:49 2: <&mut W as core::fmt::Write>::write_fmt 3: std::io::Write::write_fmt at /rustc/45ebd5808afd3df7ba842797c0fcd4447ddf30fb/src/libstd/io/mod.rs:1427 4: servo::backtrace::print at ports/glutin/backtrace.rs:17 5: servo::install_crash_handler::handler at ports/glutin/main2.rs:68 6: <unknown> 7: _ZN2JS37GetPromiseUserInputEventHandlingStateENS_6HandleIP8JSObjectEE at /Users/paul/.cargo/git/checkouts/mozjs-fa11ffc7d4f1cc2d/2392ebc/mozjs/js/src/vm/JSObject.h:106 ```
This commit is contained in:
commit
0ed0c0d9f0
4 changed files with 32 additions and 5 deletions
|
@ -19,19 +19,21 @@ use crate::dom::globalscope::GlobalScope;
|
||||||
use crate::dom::promisenativehandler::PromiseNativeHandler;
|
use crate::dom::promisenativehandler::PromiseNativeHandler;
|
||||||
use crate::realms::{enter_realm, InRealm};
|
use crate::realms::{enter_realm, InRealm};
|
||||||
use crate::script_runtime::JSContext as SafeJSContext;
|
use crate::script_runtime::JSContext as SafeJSContext;
|
||||||
|
use crate::script_thread::ScriptThread;
|
||||||
use dom_struct::dom_struct;
|
use dom_struct::dom_struct;
|
||||||
use js::conversions::ToJSValConvertible;
|
use js::conversions::ToJSValConvertible;
|
||||||
use js::jsapi::{AddRawValueRoot, CallArgs, GetFunctionNativeReserved};
|
use js::jsapi::{AddRawValueRoot, CallArgs, GetFunctionNativeReserved};
|
||||||
use js::jsapi::{Heap, JS_ClearPendingException};
|
use js::jsapi::{Heap, JS_ClearPendingException};
|
||||||
use js::jsapi::{JSAutoRealm, JSContext, JSObject, JS_GetFunctionObject};
|
use js::jsapi::{JSAutoRealm, JSContext, JSObject, JS_GetFunctionObject};
|
||||||
use js::jsapi::{JS_NewFunction, NewFunctionWithReserved, PromiseState};
|
use js::jsapi::{JS_NewFunction, NewFunctionWithReserved};
|
||||||
|
use js::jsapi::{PromiseState, PromiseUserInputEventHandlingState};
|
||||||
use js::jsapi::{RemoveRawValueRoot, SetFunctionNativeReserved};
|
use js::jsapi::{RemoveRawValueRoot, SetFunctionNativeReserved};
|
||||||
use js::jsval::{Int32Value, JSVal, ObjectValue, UndefinedValue};
|
use js::jsval::{Int32Value, JSVal, ObjectValue, UndefinedValue};
|
||||||
use js::rust::wrappers::{
|
use js::rust::wrappers::{
|
||||||
AddPromiseReactions, CallOriginalPromiseReject, CallOriginalPromiseResolve,
|
AddPromiseReactions, CallOriginalPromiseReject, CallOriginalPromiseResolve,
|
||||||
};
|
};
|
||||||
use js::rust::wrappers::{GetPromiseState, IsPromiseObject};
|
use js::rust::wrappers::{GetPromiseState, IsPromiseObject, NewPromiseObject, RejectPromise};
|
||||||
use js::rust::wrappers::{NewPromiseObject, RejectPromise, ResolvePromise};
|
use js::rust::wrappers::{ResolvePromise, SetPromiseUserInputEventHandlingState};
|
||||||
use js::rust::{HandleObject, HandleValue, MutableHandleObject, Runtime};
|
use js::rust::{HandleObject, HandleValue, MutableHandleObject, Runtime};
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
@ -131,6 +133,12 @@ impl Promise {
|
||||||
assert!(!do_nothing_obj.is_null());
|
assert!(!do_nothing_obj.is_null());
|
||||||
obj.set(NewPromiseObject(*cx, do_nothing_obj.handle()));
|
obj.set(NewPromiseObject(*cx, do_nothing_obj.handle()));
|
||||||
assert!(!obj.is_null());
|
assert!(!obj.is_null());
|
||||||
|
let is_user_interacting = if ScriptThread::is_user_interacting() {
|
||||||
|
PromiseUserInputEventHandlingState::HadUserInteractionAtCreation
|
||||||
|
} else {
|
||||||
|
PromiseUserInputEventHandlingState::DidntHaveUserInteractionAtCreation
|
||||||
|
};
|
||||||
|
SetPromiseUserInputEventHandlingState(obj.handle(), is_user_interacting);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -52,6 +52,7 @@ pub struct EnqueuedPromiseCallback {
|
||||||
#[ignore_malloc_size_of = "Rc has unclear ownership"]
|
#[ignore_malloc_size_of = "Rc has unclear ownership"]
|
||||||
pub callback: Rc<PromiseJobCallback>,
|
pub callback: Rc<PromiseJobCallback>,
|
||||||
pub pipeline: PipelineId,
|
pub pipeline: PipelineId,
|
||||||
|
pub is_user_interacting: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A microtask that comes from a queueMicrotask() Javascript call,
|
/// A microtask that comes from a queueMicrotask() Javascript call,
|
||||||
|
@ -105,7 +106,10 @@ impl MicrotaskQueue {
|
||||||
match *job {
|
match *job {
|
||||||
Microtask::Promise(ref job) => {
|
Microtask::Promise(ref job) => {
|
||||||
if let Some(target) = target_provider(job.pipeline) {
|
if let Some(target) = target_provider(job.pipeline) {
|
||||||
|
let was_interacting = ScriptThread::is_user_interacting();
|
||||||
|
ScriptThread::set_user_interacting(job.is_user_interacting);
|
||||||
let _ = job.callback.Call_(&*target, ExceptionHandling::Report);
|
let _ = job.callback.Call_(&*target, ExceptionHandling::Report);
|
||||||
|
ScriptThread::set_user_interacting(was_interacting);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Microtask::User(ref job) => {
|
Microtask::User(ref job) => {
|
||||||
|
|
|
@ -42,9 +42,11 @@ use js::glue::{
|
||||||
StreamConsumerNoteResponseURLs, StreamConsumerStreamEnd, StreamConsumerStreamError,
|
StreamConsumerNoteResponseURLs, StreamConsumerStreamEnd, StreamConsumerStreamError,
|
||||||
};
|
};
|
||||||
use js::jsapi::ContextOptionsRef;
|
use js::jsapi::ContextOptionsRef;
|
||||||
|
use js::jsapi::GetPromiseUserInputEventHandlingState;
|
||||||
use js::jsapi::InitConsumeStreamCallback;
|
use js::jsapi::InitConsumeStreamCallback;
|
||||||
use js::jsapi::InitDispatchToEventLoop;
|
use js::jsapi::InitDispatchToEventLoop;
|
||||||
use js::jsapi::MimeType;
|
use js::jsapi::MimeType;
|
||||||
|
use js::jsapi::PromiseUserInputEventHandlingState;
|
||||||
use js::jsapi::StreamConsumer as JSStreamConsumer;
|
use js::jsapi::StreamConsumer as JSStreamConsumer;
|
||||||
use js::jsapi::{BuildIdCharVector, DisableIncrementalGC, GCDescription, GCProgress};
|
use js::jsapi::{BuildIdCharVector, DisableIncrementalGC, GCDescription, GCProgress};
|
||||||
use js::jsapi::{Dispatchable as JSRunnable, Dispatchable_MaybeShuttingDown};
|
use js::jsapi::{Dispatchable as JSRunnable, Dispatchable_MaybeShuttingDown};
|
||||||
|
@ -197,7 +199,7 @@ unsafe extern "C" fn empty(extra: *const c_void) -> bool {
|
||||||
unsafe extern "C" fn enqueue_promise_job(
|
unsafe extern "C" fn enqueue_promise_job(
|
||||||
extra: *const c_void,
|
extra: *const c_void,
|
||||||
cx: *mut RawJSContext,
|
cx: *mut RawJSContext,
|
||||||
_promise: HandleObject,
|
promise: HandleObject,
|
||||||
job: HandleObject,
|
job: HandleObject,
|
||||||
_allocation_site: HandleObject,
|
_allocation_site: HandleObject,
|
||||||
incumbent_global: HandleObject,
|
incumbent_global: HandleObject,
|
||||||
|
@ -208,10 +210,18 @@ unsafe extern "C" fn enqueue_promise_job(
|
||||||
let microtask_queue = &*(extra as *const MicrotaskQueue);
|
let microtask_queue = &*(extra as *const MicrotaskQueue);
|
||||||
let global = GlobalScope::from_object(incumbent_global.get());
|
let global = GlobalScope::from_object(incumbent_global.get());
|
||||||
let pipeline = global.pipeline_id();
|
let pipeline = global.pipeline_id();
|
||||||
|
let interaction = if promise.get().is_null() {
|
||||||
|
PromiseUserInputEventHandlingState::DontCare
|
||||||
|
} else {
|
||||||
|
GetPromiseUserInputEventHandlingState(promise)
|
||||||
|
};
|
||||||
|
let is_user_interacting =
|
||||||
|
interaction == PromiseUserInputEventHandlingState::HadUserInteractionAtCreation;
|
||||||
microtask_queue.enqueue(
|
microtask_queue.enqueue(
|
||||||
Microtask::Promise(EnqueuedPromiseCallback {
|
Microtask::Promise(EnqueuedPromiseCallback {
|
||||||
callback: PromiseJobCallback::new(cx, job.get()),
|
callback: PromiseJobCallback::new(cx, job.get()),
|
||||||
pipeline,
|
pipeline,
|
||||||
|
is_user_interacting,
|
||||||
}),
|
}),
|
||||||
cx,
|
cx,
|
||||||
);
|
);
|
||||||
|
|
|
@ -12,6 +12,7 @@ use crate::dom::eventsource::EventSourceTimeoutCallback;
|
||||||
use crate::dom::globalscope::GlobalScope;
|
use crate::dom::globalscope::GlobalScope;
|
||||||
use crate::dom::testbinding::TestBindingCallback;
|
use crate::dom::testbinding::TestBindingCallback;
|
||||||
use crate::dom::xmlhttprequest::XHRTimeoutCallback;
|
use crate::dom::xmlhttprequest::XHRTimeoutCallback;
|
||||||
|
use crate::script_thread::ScriptThread;
|
||||||
use euclid::Length;
|
use euclid::Length;
|
||||||
use ipc_channel::ipc::IpcSender;
|
use ipc_channel::ipc::IpcSender;
|
||||||
use js::jsapi::Heap;
|
use js::jsapi::Heap;
|
||||||
|
@ -367,6 +368,7 @@ pub struct JsTimerTask {
|
||||||
is_interval: IsInterval,
|
is_interval: IsInterval,
|
||||||
nesting_level: u32,
|
nesting_level: u32,
|
||||||
duration: MsDuration,
|
duration: MsDuration,
|
||||||
|
is_user_interacting: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enum allowing more descriptive values for the is_interval field
|
// Enum allowing more descriptive values for the is_interval field
|
||||||
|
@ -444,6 +446,7 @@ impl JsTimers {
|
||||||
source: source,
|
source: source,
|
||||||
callback: callback,
|
callback: callback,
|
||||||
is_interval: is_interval,
|
is_interval: is_interval,
|
||||||
|
is_user_interacting: ScriptThread::is_user_interacting(),
|
||||||
nesting_level: 0,
|
nesting_level: 0,
|
||||||
duration: Length::new(0),
|
duration: Length::new(0),
|
||||||
};
|
};
|
||||||
|
@ -524,12 +527,13 @@ impl JsTimerTask {
|
||||||
timers.nesting_level.set(self.nesting_level);
|
timers.nesting_level.set(self.nesting_level);
|
||||||
|
|
||||||
// step 4.2
|
// step 4.2
|
||||||
|
let was_user_interacting = ScriptThread::is_user_interacting();
|
||||||
|
ScriptThread::set_user_interacting(self.is_user_interacting);
|
||||||
match self.callback {
|
match self.callback {
|
||||||
InternalTimerCallback::StringTimerCallback(ref code_str) => {
|
InternalTimerCallback::StringTimerCallback(ref code_str) => {
|
||||||
let global = this.global();
|
let global = this.global();
|
||||||
let cx = global.get_cx();
|
let cx = global.get_cx();
|
||||||
rooted!(in(*cx) let mut rval = UndefinedValue());
|
rooted!(in(*cx) let mut rval = UndefinedValue());
|
||||||
|
|
||||||
global.evaluate_js_on_global_with_result(code_str, rval.handle_mut());
|
global.evaluate_js_on_global_with_result(code_str, rval.handle_mut());
|
||||||
},
|
},
|
||||||
InternalTimerCallback::FunctionTimerCallback(ref function, ref arguments) => {
|
InternalTimerCallback::FunctionTimerCallback(ref function, ref arguments) => {
|
||||||
|
@ -537,6 +541,7 @@ impl JsTimerTask {
|
||||||
let _ = function.Call_(this, arguments, Report);
|
let _ = function.Call_(this, arguments, Report);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
ScriptThread::set_user_interacting(was_user_interacting);
|
||||||
|
|
||||||
// reset nesting level (see above)
|
// reset nesting level (see above)
|
||||||
timers.nesting_level.set(0);
|
timers.nesting_level.set(0);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue