mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
This change exposes a single `InputEvent` type and now there is only a single delegate method for this `WebViewDelegate::notify_input_event`. - Clipboard events are now handled as `EditingAction` inpute events. In the future this can include things like "Select All", etc. In addition, many parts of the dance to pass these events can now be simplified due to this abstraction. - All forwarded events are handled the same way in the `Constellation`, though they may carry an optional hit test (for events that have a `point`) which affects which `Pipeline` they are sent to. - In the `ScriptThread` we now accept these `InputEvents` and use them everywhere. Now all "compositor events" are "input events". - This allows removing several data structures which are no longer necessary. - We no longer inform the embedder when an event was handled by a WebView as that was only important for a MDI feature that will no longer be so important the full-featured `WebView` API. Signed-off-by: Martin Robinson <mrobinson@igalia.com> Co-authored-by: Mukilan Thiyagarajan <mukilan@igalia.com>
211 lines
6.4 KiB
Rust
211 lines
6.4 KiB
Rust
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
|
|
|
#![deny(unsafe_code)]
|
|
|
|
//! An API interface to the BackgroundHangMonitor.
|
|
|
|
use std::time::Duration;
|
|
use std::{fmt, mem};
|
|
|
|
use base::id::PipelineId;
|
|
use ipc_channel::ipc::IpcSender;
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
|
|
/// The equivalent of script::script_runtime::ScriptEventCategory
|
|
pub enum ScriptHangAnnotation {
|
|
AttachLayout,
|
|
ConstellationMsg,
|
|
DevtoolsMsg,
|
|
DocumentEvent,
|
|
FileRead,
|
|
FormPlannedNavigation,
|
|
ImageCacheMsg,
|
|
InputEvent,
|
|
HistoryEvent,
|
|
NetworkEvent,
|
|
Rendering,
|
|
Resize,
|
|
ScriptEvent,
|
|
SetScrollState,
|
|
SetViewport,
|
|
StylesheetLoad,
|
|
TimerEvent,
|
|
UpdateReplacedElement,
|
|
WebSocketEvent,
|
|
WorkerEvent,
|
|
WorkletEvent,
|
|
ServiceWorkerEvent,
|
|
EnterFullscreen,
|
|
ExitFullscreen,
|
|
WebVREvent,
|
|
PerformanceTimelineTask,
|
|
PortMessage,
|
|
WebGPUMsg,
|
|
}
|
|
|
|
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
|
|
pub enum HangAnnotation {
|
|
Script(ScriptHangAnnotation),
|
|
}
|
|
|
|
/// Hang-alerts are sent by the monitor to the constellation.
|
|
#[derive(Deserialize, Serialize)]
|
|
pub enum HangMonitorAlert {
|
|
/// A component hang has been detected.
|
|
Hang(HangAlert),
|
|
/// Report a completed sampled profile.
|
|
Profile(Vec<u8>),
|
|
}
|
|
|
|
impl fmt::Debug for HangMonitorAlert {
|
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
|
match *self {
|
|
HangMonitorAlert::Hang(..) => write!(fmt, "Hang"),
|
|
HangMonitorAlert::Profile(..) => write!(fmt, "Profile"),
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Hang-alerts are sent by the monitor to the constellation.
|
|
#[derive(Deserialize, Serialize)]
|
|
pub enum HangAlert {
|
|
/// Report a transient hang.
|
|
Transient(MonitoredComponentId, HangAnnotation),
|
|
/// Report a permanent hang.
|
|
Permanent(MonitoredComponentId, HangAnnotation, Option<HangProfile>),
|
|
}
|
|
|
|
impl fmt::Debug for HangAlert {
|
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
|
let (annotation, profile) = match self {
|
|
HangAlert::Transient(component_id, annotation) => {
|
|
write!(
|
|
fmt,
|
|
"\n The following component is experiencing a transient hang: \n {:?}",
|
|
component_id
|
|
)?;
|
|
(*annotation, None)
|
|
},
|
|
HangAlert::Permanent(component_id, annotation, profile) => {
|
|
write!(
|
|
fmt,
|
|
"\n The following component is experiencing a permanent hang: \n {:?}",
|
|
component_id
|
|
)?;
|
|
(*annotation, profile.clone())
|
|
},
|
|
};
|
|
|
|
write!(fmt, "\n Annotation for the hang:\n{:?}", annotation)?;
|
|
if let Some(profile) = profile {
|
|
write!(fmt, "\n {:?}", profile)?;
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Deserialize, Serialize)]
|
|
pub struct HangProfileSymbol {
|
|
pub name: Option<String>,
|
|
pub filename: Option<String>,
|
|
pub lineno: Option<u32>,
|
|
}
|
|
|
|
#[derive(Clone, Deserialize, Serialize)]
|
|
/// Info related to the activity of an hanging component.
|
|
pub struct HangProfile {
|
|
pub backtrace: Vec<HangProfileSymbol>,
|
|
}
|
|
|
|
impl fmt::Debug for HangProfile {
|
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
|
let hex_width = mem::size_of::<usize>() * 2 + 2;
|
|
|
|
write!(fmt, "HangProfile backtrace:")?;
|
|
|
|
if self.backtrace.is_empty() {
|
|
write!(fmt, "backtrace failed to resolve")?;
|
|
return Ok(());
|
|
}
|
|
|
|
for symbol in self.backtrace.iter() {
|
|
write!(fmt, "\n {:1$}", "", hex_width)?;
|
|
|
|
if let Some(ref name) = symbol.name {
|
|
write!(fmt, " - {}", name)?;
|
|
} else {
|
|
write!(fmt, " - <unknown>")?;
|
|
}
|
|
|
|
if let (Some(ref file), Some(ref line)) = (symbol.filename.as_ref(), symbol.lineno) {
|
|
write!(fmt, "\n {:3$}at {}:{}", "", file, line, hex_width)?;
|
|
}
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
|
|
pub enum MonitoredComponentType {
|
|
Script,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
|
|
pub struct MonitoredComponentId(pub PipelineId, pub MonitoredComponentType);
|
|
|
|
/// A handle to register components for hang monitoring,
|
|
/// and to receive a means to communicate with the underlying hang monitor worker.
|
|
pub trait BackgroundHangMonitorRegister: BackgroundHangMonitorClone + Send {
|
|
/// Register a component for hang monitoring:
|
|
/// to be called from within the thread to be monitored for hangs.
|
|
fn register_component(
|
|
&self,
|
|
component: MonitoredComponentId,
|
|
transient_hang_timeout: Duration,
|
|
permanent_hang_timeout: Duration,
|
|
exit_signal: Option<Box<dyn BackgroundHangMonitorExitSignal>>,
|
|
) -> Box<dyn BackgroundHangMonitor>;
|
|
}
|
|
|
|
impl Clone for Box<dyn BackgroundHangMonitorRegister> {
|
|
fn clone(&self) -> Box<dyn BackgroundHangMonitorRegister> {
|
|
self.clone_box()
|
|
}
|
|
}
|
|
|
|
pub trait BackgroundHangMonitorClone {
|
|
fn clone_box(&self) -> Box<dyn BackgroundHangMonitorRegister>;
|
|
}
|
|
|
|
/// Proxy methods to communicate with the background hang monitor
|
|
pub trait BackgroundHangMonitor {
|
|
/// Notify the start of handling an event.
|
|
fn notify_activity(&self, annotation: HangAnnotation);
|
|
/// Notify the start of waiting for a new event to come in.
|
|
fn notify_wait(&self);
|
|
/// Unregister the component from monitor.
|
|
fn unregister(&self);
|
|
}
|
|
|
|
/// A means for the BHM to signal a monitored component to exit.
|
|
/// Useful when the component is hanging, and cannot be notified via the usual way.
|
|
/// The component should implement this in a way allowing for the signal to be received when hanging,
|
|
/// if at all.
|
|
pub trait BackgroundHangMonitorExitSignal: Send {
|
|
/// Called by the BHM, to notify the monitored component to exit.
|
|
fn signal_to_exit(&self);
|
|
}
|
|
|
|
/// Messages to control the sampling profiler.
|
|
#[derive(Deserialize, Serialize)]
|
|
pub enum BackgroundHangMonitorControlMsg {
|
|
/// Toggle the sampler, with a given sampling rate and max total sampling duration.
|
|
ToggleSampler(Duration, Duration),
|
|
/// Exit, and propagate the signal to monitored components.
|
|
Exit(IpcSender<()>),
|
|
}
|