mirror of
https://github.com/servo/servo.git
synced 2025-07-23 23:33:43 +01:00
Improve inter-document focus handling (#36649)
*Describe the changes that this pull request makes here. This will be the commit message.* rewritten the PR #28571 Implement [Window#focus](https://html.spec.whatwg.org/multipage/#dom-window-focus), [Window#blur](https://html.spec.whatwg.org/multipage/#dom-window-blur) Testing: WPT Fixes: #8981 #9421 --------- Signed-off-by: kongbai1996 <1782765876@qq.com> Co-authored-by: yvt <i@yvt.jp>
This commit is contained in:
parent
27570987fd
commit
0c0ee04b8e
33 changed files with 1123 additions and 242 deletions
|
@ -15,7 +15,8 @@ use base::id::{
|
|||
use canvas_traits::canvas::{CanvasId, CanvasMsg};
|
||||
use devtools_traits::{DevtoolScriptControlMsg, ScriptToDevtoolsControlMsg, WorkerId};
|
||||
use embedder_traits::{
|
||||
AnimationState, EmbedderMsg, MediaSessionEvent, TouchEventResult, ViewportDetails,
|
||||
AnimationState, EmbedderMsg, FocusSequenceNumber, MediaSessionEvent, TouchEventResult,
|
||||
ViewportDetails,
|
||||
};
|
||||
use euclid::default::Size2D as UntypedSize2D;
|
||||
use http::{HeaderMap, Method};
|
||||
|
@ -519,8 +520,21 @@ pub enum ScriptToConstellationMessage {
|
|||
UntypedSize2D<u64>,
|
||||
IpcSender<(IpcSender<CanvasMsg>, CanvasId, ImageKey)>,
|
||||
),
|
||||
/// Notifies the constellation that this frame has received focus.
|
||||
Focus,
|
||||
/// Notifies the constellation that this pipeline is requesting focus.
|
||||
///
|
||||
/// When this message is sent, the sender pipeline has already its local
|
||||
/// focus state updated. The constellation, after receiving this message,
|
||||
/// will broadcast messages to other pipelines that are affected by this
|
||||
/// focus operation.
|
||||
///
|
||||
/// The first field contains the browsing context ID of the container
|
||||
/// element if one was focused.
|
||||
///
|
||||
/// The second field is a sequence number that the constellation should use
|
||||
/// when sending a focus-related message to the sender pipeline next time.
|
||||
Focus(Option<BrowsingContextId>, FocusSequenceNumber),
|
||||
/// Requests the constellation to focus the specified browsing context.
|
||||
FocusRemoteDocument(BrowsingContextId),
|
||||
/// Get the top-level browsing context info for a given browsing context.
|
||||
GetTopForBrowsingContext(BrowsingContextId, IpcSender<Option<WebViewId>>),
|
||||
/// Get the browsing context id of the browsing context in which pipeline is
|
||||
|
|
|
@ -14,7 +14,7 @@ pub mod user_content_manager;
|
|||
mod webdriver;
|
||||
|
||||
use std::ffi::c_void;
|
||||
use std::fmt::{Debug, Error, Formatter};
|
||||
use std::fmt::{Debug, Display, Error, Formatter};
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
|
||||
|
@ -784,3 +784,76 @@ pub enum AnimationState {
|
|||
/// No animations are active but callbacks are queued
|
||||
NoAnimationCallbacksPresent,
|
||||
}
|
||||
|
||||
/// A sequence number generated by a script thread for its pipelines. The
|
||||
/// constellation attaches the target pipeline's last seen `FocusSequenceNumber`
|
||||
/// to every focus-related message it sends.
|
||||
///
|
||||
/// This is used to resolve the inconsistency that occurs due to bidirectional
|
||||
/// focus state synchronization and provide eventual consistency. Example:
|
||||
///
|
||||
/// ```text
|
||||
/// script constellation
|
||||
/// -----------------------------------------------------------------------
|
||||
/// send ActivateDocument ----------> receive ActivateDocument
|
||||
/// ,---- send FocusDocument
|
||||
/// |
|
||||
/// focus an iframe |
|
||||
/// send Focus -----------------|---> receive Focus
|
||||
/// | focus the iframe's content document
|
||||
/// receive FocusDocument <-----' send FocusDocument to the content pipeline --> ...
|
||||
/// unfocus the iframe
|
||||
/// focus the document
|
||||
///
|
||||
/// Final state: Final state:
|
||||
/// the iframe is not focused the iframe is focused
|
||||
/// ```
|
||||
///
|
||||
/// When the above sequence completes, from the script thread's point of view,
|
||||
/// the iframe is unfocused, but from the constellation's point of view, the
|
||||
/// iframe is still focused.
|
||||
///
|
||||
/// This inconsistency can be resolved by associating a sequence number to each
|
||||
/// message. Whenever a script thread initiates a focus operation, it generates
|
||||
/// and sends a brand new sequence number. The constellation attaches the
|
||||
/// last-received sequence number to each message it sends. This way, the script
|
||||
/// thread can discard out-dated incoming focus messages, and eventually, all
|
||||
/// actors converge to the consistent state which is determined based on the
|
||||
/// last focus message received by the constellation.
|
||||
///
|
||||
/// ```text
|
||||
/// script constellation
|
||||
/// -----------------------------------------------------------------------
|
||||
/// send ActivateDocument ----------> receive ActivateDocument
|
||||
/// ,---- send FocusDocument (0)
|
||||
/// |
|
||||
/// seq_number += 1 |
|
||||
/// focus an iframe |
|
||||
/// send Focus (1) -------------|---> receive Focus (1)
|
||||
/// | focus the iframe's content document
|
||||
/// receive FocusDocument (0) <-' send FocusDocument to the content pipeline --> ...
|
||||
/// ignore it because 0 < 1
|
||||
///
|
||||
/// Final state: Final state:
|
||||
/// the iframe is focused the iframe is focused
|
||||
/// ```
|
||||
#[derive(
|
||||
Clone,
|
||||
Copy,
|
||||
Debug,
|
||||
Default,
|
||||
Deserialize,
|
||||
Eq,
|
||||
Hash,
|
||||
MallocSizeOf,
|
||||
PartialEq,
|
||||
Serialize,
|
||||
PartialOrd,
|
||||
)]
|
||||
pub struct FocusSequenceNumber(pub u64);
|
||||
|
||||
impl Display for FocusSequenceNumber {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
|
||||
Display::fmt(&self.0, f)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,8 +27,8 @@ use crossbeam_channel::{RecvTimeoutError, Sender};
|
|||
use devtools_traits::ScriptToDevtoolsControlMsg;
|
||||
use embedder_traits::user_content_manager::UserContentManager;
|
||||
use embedder_traits::{
|
||||
CompositorHitTestResult, InputEvent, MediaSessionActionType, Theme, ViewportDetails,
|
||||
WebDriverScriptCommand,
|
||||
CompositorHitTestResult, FocusSequenceNumber, InputEvent, MediaSessionActionType, Theme,
|
||||
ViewportDetails, WebDriverScriptCommand,
|
||||
};
|
||||
use euclid::{Rect, Scale, Size2D, UnknownUnit};
|
||||
use ipc_channel::ipc::{IpcReceiver, IpcSender};
|
||||
|
@ -191,7 +191,15 @@ pub enum ScriptThreadMessage {
|
|||
RemoveHistoryStates(PipelineId, Vec<HistoryStateId>),
|
||||
/// Set an iframe to be focused. Used when an element in an iframe gains focus.
|
||||
/// PipelineId is for the parent, BrowsingContextId is for the nested browsing context
|
||||
FocusIFrame(PipelineId, BrowsingContextId),
|
||||
FocusIFrame(PipelineId, BrowsingContextId, FocusSequenceNumber),
|
||||
/// Focus the document. Used when the container gains focus.
|
||||
FocusDocument(PipelineId, FocusSequenceNumber),
|
||||
/// Notifies that the document's container (e.g., an iframe) is not included
|
||||
/// in the top-level browsing context's focus chain (not considering system
|
||||
/// focus) anymore.
|
||||
///
|
||||
/// Obviously, this message is invalid for a top-level document.
|
||||
Unfocus(PipelineId, FocusSequenceNumber),
|
||||
/// Passes a webdriver command to the script thread for execution
|
||||
WebDriverScriptCommand(PipelineId, WebDriverScriptCommand),
|
||||
/// Notifies script thread that all animations are done
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue