mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
Initial internal support for multiple webviews (#31417)
* Add multiple concurrent top-level browsing contexts Co-authored-by: Delan Azabani <dazabani@igalia.com> * Rename variables and comments There are some variable and comments still use browser as names. This commit renames them to webview. * Update log message from web view to webview * Revert offscreen_framebuffer_id rename * Rename all web view to webview * Cargo fmt * Fix viewport/event/clear coordinates when multiview is disabled * Only deprecate things when multiview is enabled * Update WebViewManger with shown and invisible sets Replace visible_webviews and native_window_is_visible with shown_webviews and invisible_webviews. Add 4 more methods to set them accordingly. The behavior of is_effectively_visible will return true if the wbview is in shown_webviews set but not in invisible_webviews. * Update variant behaviors * Rename WebViewVisibilityChanged to MarkWebViewInvisible * Fix unit test by marking id 3 visible again * Update MarkWebViewInvisible and add UnmarkWebViewInvisible * Update format and doc comments * Clean up doc comments * Address style and naming changes * Rename UpdateWebView to UpdateFrameTreeForWebView * constellation: send frame tree unconditionally over focus and feature * Clarify shown and invisible sets in constellation WebViewManager * Eliminate forward_to_constellation!() * Actually remove the unused macro * Don’t gate compositor changes on multiview feature flag * Update todo in mouse event dispatch * Pass all visible webview ids in a single ReadyToPresent message * Fix compile and lint errors * servoshell: fix gap between minibrowser toolbar and webview * Fix failure in /_mozilla/mozilla/window_resizeTo.html * Fix compile warnings * Remove stray dbg!() * Remove confusing “effectively visible” logic (see #31815, #31816) * Allow embedder to show/hide/raise webviews without ipc * Update root pipeline only when painting order actually changes * Stop gating old focus and SetFrameTree behaviour behind Cargo feature * Use webview_id and WebViewId in webview-related code * Improve logging of webview-related embedder events * Allow webview Show and Raise events to optionally hide all others * Don’t do anything in response to WebViewPaintingOrder * Remove WebViewPaintingOrder, since its payload is unreliable * On MoveResizeWebView, only update root pipeline if rect changed * Rename IOCompositor methods for clarity * compositor: add event tracing; log webview ops even without ipc * Add temporary debug logging * Add more temporary debug logging * Remove temporary logging in compositor * Remove temporary debug logging * Add temporary debug logging, but defer I/O until panic * Capture a backtrace with each crash log entry * Proper error handling without panicking in WebViewManager * Clean up imports in constellation --------- Co-authored-by: Delan Azabani <dazabani@igalia.com> Co-authored-by: Martin Robinson <mrobinson@igalia.com>
This commit is contained in:
parent
18b37e676b
commit
66878fb834
21 changed files with 1142 additions and 434 deletions
|
@ -7,6 +7,7 @@ use std::collections::HashMap;
|
|||
use std::env;
|
||||
use std::fs::{create_dir_all, File};
|
||||
use std::io::Write;
|
||||
use std::iter::once;
|
||||
use std::num::NonZeroU32;
|
||||
use std::rc::Rc;
|
||||
use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
|
||||
|
@ -27,7 +28,7 @@ use ipc_channel::ipc;
|
|||
use libc::c_void;
|
||||
use log::{debug, error, info, trace, warn};
|
||||
use msg::constellation_msg::{
|
||||
PipelineId, PipelineIndex, PipelineNamespaceId, TopLevelBrowsingContextId,
|
||||
PipelineId, PipelineIndex, PipelineNamespaceId, TopLevelBrowsingContextId, WebViewId,
|
||||
};
|
||||
use net_traits::image::base::Image;
|
||||
use net_traits::image_cache::CorsStatus;
|
||||
|
@ -44,7 +45,7 @@ use servo_geometry::{DeviceIndependentPixel, FramebufferUintLength};
|
|||
use style_traits::{CSSPixel, DevicePixel, PinchZoomFactor};
|
||||
use webrender::{CaptureBits, RenderApi, Transaction};
|
||||
use webrender_api::units::{
|
||||
DeviceIntPoint, DeviceIntSize, DevicePoint, LayoutPoint, LayoutRect, LayoutSize,
|
||||
DeviceIntPoint, DeviceIntSize, DevicePoint, DeviceRect, LayoutPoint, LayoutRect, LayoutSize,
|
||||
LayoutVector2D, WorldPoint,
|
||||
};
|
||||
use webrender_api::{
|
||||
|
@ -56,6 +57,7 @@ use webrender_api::{
|
|||
|
||||
use crate::gl::RenderTargetInfo;
|
||||
use crate::touch::{TouchAction, TouchHandler};
|
||||
use crate::webview::{UnknownWebView, WebView, WebViewAlreadyExists, WebViewManager};
|
||||
use crate::windowing::{
|
||||
self, EmbedderCoordinates, MouseWindowEvent, WebRenderDebugOption, WindowMethods,
|
||||
};
|
||||
|
@ -109,11 +111,6 @@ impl FrameTreeId {
|
|||
}
|
||||
}
|
||||
|
||||
struct RootPipeline {
|
||||
top_level_browsing_context_id: TopLevelBrowsingContextId,
|
||||
id: Option<PipelineId>,
|
||||
}
|
||||
|
||||
/// NB: Never block on the constellation, because sometimes the constellation blocks on us.
|
||||
pub struct IOCompositor<Window: WindowMethods + ?Sized> {
|
||||
/// The application window.
|
||||
|
@ -122,10 +119,8 @@ pub struct IOCompositor<Window: WindowMethods + ?Sized> {
|
|||
/// The port on which we receive messages.
|
||||
port: CompositorReceiver,
|
||||
|
||||
/// The root content pipeline ie the pipeline which contains the main frame
|
||||
/// to display. In the WebRender scene, this will be the only child of another
|
||||
/// pipeline which applies a pinch zoom transformation.
|
||||
root_content_pipeline: RootPipeline,
|
||||
/// Our top-level browsing contexts.
|
||||
webviews: WebViewManager<WebView>,
|
||||
|
||||
/// Tracks details about each active pipeline that the compositor knows about.
|
||||
pipeline_details: HashMap<PipelineId, PipelineDetails>,
|
||||
|
@ -292,6 +287,9 @@ struct PipelineDetails {
|
|||
/// The pipeline associated with this PipelineDetails object.
|
||||
pipeline: Option<CompositionPipeline>,
|
||||
|
||||
/// The id of the parent pipeline, if any.
|
||||
parent_pipeline_id: Option<PipelineId>,
|
||||
|
||||
/// The epoch of the most recent display list for this pipeline. Note that this display
|
||||
/// list might not be displayed, as WebRender processes display lists asynchronously.
|
||||
most_recent_display_list_epoch: Option<WebRenderEpoch>,
|
||||
|
@ -318,6 +316,7 @@ impl PipelineDetails {
|
|||
fn new() -> PipelineDetails {
|
||||
PipelineDetails {
|
||||
pipeline: None,
|
||||
parent_pipeline_id: None,
|
||||
most_recent_display_list_epoch: None,
|
||||
animations_running: false,
|
||||
animation_callbacks_running: false,
|
||||
|
@ -376,14 +375,26 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
|
|||
convert_mouse_to_touch: bool,
|
||||
top_level_browsing_context_id: TopLevelBrowsingContextId,
|
||||
) -> Self {
|
||||
let embedder_coordinates = window.get_coordinates();
|
||||
let mut webviews = WebViewManager::default();
|
||||
webviews
|
||||
.add(
|
||||
top_level_browsing_context_id,
|
||||
WebView {
|
||||
pipeline_id: None,
|
||||
rect: embedder_coordinates.get_viewport().to_f32(),
|
||||
},
|
||||
)
|
||||
.expect("Infallible with a new WebViewManager");
|
||||
webviews
|
||||
.show(top_level_browsing_context_id)
|
||||
.expect("Infallible due to add");
|
||||
|
||||
IOCompositor {
|
||||
embedder_coordinates: window.get_coordinates(),
|
||||
window,
|
||||
port: state.receiver,
|
||||
root_content_pipeline: RootPipeline {
|
||||
top_level_browsing_context_id,
|
||||
id: None,
|
||||
},
|
||||
webviews,
|
||||
pipeline_details: HashMap::new(),
|
||||
composition_request: CompositionRequest::NoCompositingNecessary,
|
||||
touch_handler: TouchHandler::new(),
|
||||
|
@ -524,6 +535,8 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
|
|||
}
|
||||
|
||||
fn handle_browser_message(&mut self, msg: CompositorMsg) -> bool {
|
||||
trace_msg_from_constellation!(msg, "{msg:?}");
|
||||
|
||||
match self.shutdown_state {
|
||||
ShutdownState::NotShuttingDown => {},
|
||||
ShutdownState::ShuttingDown => {
|
||||
|
@ -546,11 +559,40 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
|
|||
self.change_running_animations_state(pipeline_id, animation_state);
|
||||
},
|
||||
|
||||
CompositorMsg::SetFrameTree(frame_tree) => {
|
||||
self.set_frame_tree(&frame_tree);
|
||||
CompositorMsg::CreateOrUpdateWebView(frame_tree) => {
|
||||
self.set_frame_tree_for_webview(&frame_tree);
|
||||
self.send_scroll_positions_to_layout_for_pipeline(&frame_tree.pipeline.id);
|
||||
},
|
||||
|
||||
CompositorMsg::RemoveWebView(top_level_browsing_context_id) => {
|
||||
self.remove_webview(top_level_browsing_context_id);
|
||||
},
|
||||
|
||||
CompositorMsg::MoveResizeWebView(webview_id, rect) => {
|
||||
self.move_resize_webview(webview_id, rect);
|
||||
},
|
||||
|
||||
CompositorMsg::ShowWebView(webview_id, hide_others) => {
|
||||
if let Err(UnknownWebView(webview_id)) = self.show_webview(webview_id, hide_others)
|
||||
{
|
||||
warn!("{webview_id}: ShowWebView on unknown webview id");
|
||||
}
|
||||
},
|
||||
|
||||
CompositorMsg::HideWebView(webview_id) => {
|
||||
if let Err(UnknownWebView(webview_id)) = self.hide_webview(webview_id) {
|
||||
warn!("{webview_id}: HideWebView on unknown webview id");
|
||||
}
|
||||
},
|
||||
|
||||
CompositorMsg::RaiseWebViewToTop(webview_id, hide_others) => {
|
||||
if let Err(UnknownWebView(webview_id)) =
|
||||
self.raise_webview_to_top(webview_id, hide_others)
|
||||
{
|
||||
warn!("{webview_id}: RaiseWebViewToTop on unknown webview id");
|
||||
}
|
||||
},
|
||||
|
||||
CompositorMsg::TouchEventProcessed(result) => {
|
||||
self.touch_handler.on_event_processed(result);
|
||||
},
|
||||
|
@ -1016,16 +1058,21 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Set the root pipeline for our WebRender scene. If there is no pinch zoom applied,
|
||||
/// the root pipeline is the root content pipeline. If there is pinch zoom, the root
|
||||
/// content pipeline is wrapped in a display list that applies a pinch zoom
|
||||
/// transformation to it.
|
||||
fn set_root_content_pipeline_handling_device_scaling(&self, transaction: &mut Transaction) {
|
||||
let root_content_pipeline = match self.root_content_pipeline.id {
|
||||
Some(id) => id.to_webrender(),
|
||||
None => return,
|
||||
};
|
||||
/// Set the root pipeline for our WebRender scene to a display list that consists of an iframe
|
||||
/// for each visible top-level browsing context, applying a transformation on the root for
|
||||
/// pinch zoom, page zoom, and HiDPI scaling.
|
||||
fn send_root_pipeline_display_list(&mut self) {
|
||||
let mut transaction = Transaction::new();
|
||||
self.send_root_pipeline_display_list_in_transaction(&mut transaction);
|
||||
self.generate_frame(&mut transaction, RenderReasons::SCENE);
|
||||
self.webrender_api
|
||||
.send_transaction(self.webrender_document, transaction);
|
||||
}
|
||||
|
||||
/// Set the root pipeline for our WebRender scene to a display list that consists of an iframe
|
||||
/// for each visible top-level browsing context, applying a transformation on the root for
|
||||
/// pinch zoom, page zoom, and HiDPI scaling.
|
||||
fn send_root_pipeline_display_list_in_transaction(&self, transaction: &mut Transaction) {
|
||||
// Every display list needs a pipeline, but we'd like to choose one that is unlikely
|
||||
// to conflict with our content pipelines, which start at (1, 1). (0, 0) is WebRender's
|
||||
// dummy pipeline, so we choose (0, 1).
|
||||
|
@ -1034,10 +1081,6 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
|
|||
|
||||
let mut builder = webrender_api::DisplayListBuilder::new(root_pipeline);
|
||||
builder.begin();
|
||||
let viewport_size = LayoutSize::new(
|
||||
self.embedder_coordinates.get_viewport().width() as f32,
|
||||
self.embedder_coordinates.get_viewport().height() as f32,
|
||||
);
|
||||
|
||||
let zoom_factor = self.device_pixels_per_page_pixel().0;
|
||||
let zoom_reference_frame = builder.push_reference_frame(
|
||||
|
@ -1053,26 +1096,30 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
|
|||
SpatialTreeItemKey::new(0, 0),
|
||||
);
|
||||
|
||||
let scaled_viewport_rect = LayoutRect::from_origin_and_size(
|
||||
LayoutPoint::zero(),
|
||||
LayoutSize::new(
|
||||
viewport_size.width / zoom_factor,
|
||||
viewport_size.height / zoom_factor,
|
||||
),
|
||||
);
|
||||
let scaled_viewport_size =
|
||||
self.embedder_coordinates.get_viewport().size().to_f32() / zoom_factor;
|
||||
let scaled_viewport_size = LayoutSize::from_untyped(scaled_viewport_size.to_untyped());
|
||||
let scaled_viewport_rect =
|
||||
LayoutRect::from_origin_and_size(LayoutPoint::zero(), scaled_viewport_size);
|
||||
|
||||
let root_clip_id = builder.define_clip_rect(zoom_reference_frame, scaled_viewport_rect);
|
||||
let clip_chain_id = builder.define_clip_chain(None, [root_clip_id]);
|
||||
builder.push_iframe(
|
||||
scaled_viewport_rect,
|
||||
scaled_viewport_rect,
|
||||
&SpaceAndClipInfo {
|
||||
spatial_id: zoom_reference_frame,
|
||||
clip_chain_id,
|
||||
},
|
||||
root_content_pipeline,
|
||||
true,
|
||||
);
|
||||
for (_, webview) in self.webviews.painting_order() {
|
||||
if let Some(pipeline_id) = webview.pipeline_id {
|
||||
let scaled_webview_rect = webview.rect / zoom_factor;
|
||||
builder.push_iframe(
|
||||
LayoutRect::from_untyped(&scaled_webview_rect.to_untyped()),
|
||||
LayoutRect::from_untyped(&scaled_webview_rect.to_untyped()),
|
||||
&SpaceAndClipInfo {
|
||||
spatial_id: zoom_reference_frame,
|
||||
clip_chain_id,
|
||||
},
|
||||
pipeline_id.to_webrender(),
|
||||
true,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
let built_display_list = builder.end();
|
||||
|
||||
// NB: We are always passing 0 as the epoch here, but this doesn't seem to
|
||||
|
@ -1109,29 +1156,163 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
|
|||
}
|
||||
}
|
||||
|
||||
fn set_frame_tree(&mut self, frame_tree: &SendableFrameTree) {
|
||||
debug!(
|
||||
"Setting the frame tree for pipeline {:?}",
|
||||
frame_tree.pipeline.id
|
||||
);
|
||||
fn set_frame_tree_for_webview(&mut self, frame_tree: &SendableFrameTree) {
|
||||
debug!("{}: Setting frame tree for webview", frame_tree.pipeline.id);
|
||||
|
||||
self.root_content_pipeline = RootPipeline {
|
||||
top_level_browsing_context_id: frame_tree.pipeline.top_level_browsing_context_id,
|
||||
id: Some(frame_tree.pipeline.id),
|
||||
};
|
||||
let top_level_browsing_context_id = frame_tree.pipeline.top_level_browsing_context_id;
|
||||
if let Some(webview) = self.webviews.get_mut(top_level_browsing_context_id) {
|
||||
let new_pipeline_id = Some(frame_tree.pipeline.id);
|
||||
if new_pipeline_id != webview.pipeline_id {
|
||||
debug!(
|
||||
"{:?}: Updating webview from pipeline {:?} to {:?}",
|
||||
top_level_browsing_context_id, webview.pipeline_id, new_pipeline_id
|
||||
);
|
||||
}
|
||||
webview.pipeline_id = new_pipeline_id;
|
||||
} else {
|
||||
let top_level_browsing_context_id = frame_tree.pipeline.top_level_browsing_context_id;
|
||||
let pipeline_id = Some(frame_tree.pipeline.id);
|
||||
debug!(
|
||||
"{:?}: Creating new webview with pipeline {:?}",
|
||||
top_level_browsing_context_id, pipeline_id
|
||||
);
|
||||
if let Err(WebViewAlreadyExists(webview_id)) = self.webviews.add(
|
||||
top_level_browsing_context_id,
|
||||
WebView {
|
||||
pipeline_id,
|
||||
rect: self.embedder_coordinates.get_viewport().to_f32(),
|
||||
},
|
||||
) {
|
||||
error!("{webview_id}: Creating webview that already exists");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let mut txn = Transaction::new();
|
||||
self.set_root_content_pipeline_handling_device_scaling(&mut txn);
|
||||
self.generate_frame(&mut txn, RenderReasons::SCENE);
|
||||
self.webrender_api
|
||||
.send_transaction(self.webrender_document, txn);
|
||||
|
||||
self.create_pipeline_details_for_frame_tree(frame_tree);
|
||||
self.reset_scroll_tree_for_unattached_pipelines(frame_tree);
|
||||
self.send_root_pipeline_display_list();
|
||||
self.create_or_update_pipeline_details_with_frame_tree(&frame_tree, None);
|
||||
self.reset_scroll_tree_for_unattached_pipelines(&frame_tree);
|
||||
|
||||
self.frame_tree_id.next();
|
||||
}
|
||||
|
||||
fn remove_webview(&mut self, top_level_browsing_context_id: TopLevelBrowsingContextId) {
|
||||
debug!("{}: Removing", top_level_browsing_context_id);
|
||||
let Ok(webview) = self.webviews.remove(top_level_browsing_context_id) else {
|
||||
warn!("{top_level_browsing_context_id}: Removing unknown webview");
|
||||
return;
|
||||
};
|
||||
|
||||
self.send_root_pipeline_display_list();
|
||||
if let Some(pipeline_id) = webview.pipeline_id {
|
||||
self.remove_pipeline_details_recursively(pipeline_id);
|
||||
}
|
||||
|
||||
self.frame_tree_id.next();
|
||||
}
|
||||
|
||||
pub fn move_resize_webview(&mut self, webview_id: TopLevelBrowsingContextId, rect: DeviceRect) {
|
||||
debug!("{webview_id}: Moving and/or resizing webview; rect={rect:?}");
|
||||
let rect_changed;
|
||||
let size_changed;
|
||||
match self.webviews.get_mut(webview_id) {
|
||||
Some(webview) => {
|
||||
rect_changed = rect != webview.rect;
|
||||
size_changed = rect.size() != webview.rect.size();
|
||||
webview.rect = rect;
|
||||
},
|
||||
None => {
|
||||
warn!("{webview_id}: MoveResizeWebView on unknown webview id");
|
||||
return;
|
||||
},
|
||||
};
|
||||
|
||||
if rect_changed {
|
||||
if size_changed {
|
||||
self.send_window_size_message_for_top_level_browser_context(rect, webview_id);
|
||||
}
|
||||
|
||||
self.send_root_pipeline_display_list();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn show_webview(
|
||||
&mut self,
|
||||
webview_id: WebViewId,
|
||||
hide_others: bool,
|
||||
) -> Result<(), UnknownWebView> {
|
||||
debug!("{webview_id}: Showing webview; hide_others={hide_others}");
|
||||
let painting_order_changed = if hide_others {
|
||||
let result = self
|
||||
.webviews
|
||||
.painting_order()
|
||||
.map(|(&id, _)| id)
|
||||
.ne(once(webview_id));
|
||||
self.webviews.hide_all();
|
||||
self.webviews.show(webview_id)?;
|
||||
result
|
||||
} else {
|
||||
self.webviews.show(webview_id)?
|
||||
};
|
||||
if painting_order_changed {
|
||||
self.send_root_pipeline_display_list();
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn hide_webview(&mut self, webview_id: WebViewId) -> Result<(), UnknownWebView> {
|
||||
debug!("{webview_id}: Hiding webview");
|
||||
if self.webviews.hide(webview_id)? {
|
||||
self.send_root_pipeline_display_list();
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn raise_webview_to_top(
|
||||
&mut self,
|
||||
webview_id: WebViewId,
|
||||
hide_others: bool,
|
||||
) -> Result<(), UnknownWebView> {
|
||||
debug!("{webview_id}: Raising webview to top; hide_others={hide_others}");
|
||||
let painting_order_changed = if hide_others {
|
||||
let result = self
|
||||
.webviews
|
||||
.painting_order()
|
||||
.map(|(&id, _)| id)
|
||||
.ne(once(webview_id));
|
||||
self.webviews.hide_all();
|
||||
self.webviews.raise_to_top(webview_id)?;
|
||||
result
|
||||
} else {
|
||||
self.webviews.raise_to_top(webview_id)?
|
||||
};
|
||||
if painting_order_changed {
|
||||
self.send_root_pipeline_display_list();
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn send_window_size_message_for_top_level_browser_context(
|
||||
&self,
|
||||
rect: DeviceRect,
|
||||
top_level_browsing_context_id: TopLevelBrowsingContextId,
|
||||
) {
|
||||
// The device pixel ratio used by the style system should include the scale from page pixels
|
||||
// to device pixels, but not including any pinch zoom.
|
||||
let device_pixel_ratio = self.device_pixels_per_page_pixel_not_including_page_zoom();
|
||||
let initial_viewport = rect.size().to_f32() / device_pixel_ratio;
|
||||
let msg = ConstellationMsg::WindowSize(
|
||||
top_level_browsing_context_id,
|
||||
WindowSizeData {
|
||||
device_pixel_ratio,
|
||||
initial_viewport,
|
||||
},
|
||||
WindowSizeType::Resize,
|
||||
);
|
||||
if let Err(e) = self.constellation_chan.send(msg) {
|
||||
warn!("Sending window resize to constellation failed ({:?}).", e);
|
||||
}
|
||||
}
|
||||
|
||||
fn reset_scroll_tree_for_unattached_pipelines(&mut self, frame_tree: &SendableFrameTree) {
|
||||
// TODO(mrobinson): Eventually this can selectively preserve the scroll trees
|
||||
// state for some unattached pipelines in order to preserve scroll position when
|
||||
|
@ -1159,11 +1340,35 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
|
|||
})
|
||||
}
|
||||
|
||||
fn create_pipeline_details_for_frame_tree(&mut self, frame_tree: &SendableFrameTree) {
|
||||
self.pipeline_details(frame_tree.pipeline.id).pipeline = Some(frame_tree.pipeline.clone());
|
||||
fn create_or_update_pipeline_details_with_frame_tree(
|
||||
&mut self,
|
||||
frame_tree: &SendableFrameTree,
|
||||
parent_pipeline_id: Option<PipelineId>,
|
||||
) {
|
||||
let pipeline_id = frame_tree.pipeline.id;
|
||||
let pipeline_details = self.pipeline_details(pipeline_id);
|
||||
pipeline_details.pipeline = Some(frame_tree.pipeline.clone());
|
||||
pipeline_details.parent_pipeline_id = parent_pipeline_id;
|
||||
|
||||
for kid in &frame_tree.children {
|
||||
self.create_pipeline_details_for_frame_tree(kid);
|
||||
self.create_or_update_pipeline_details_with_frame_tree(kid, Some(pipeline_id));
|
||||
}
|
||||
}
|
||||
|
||||
fn remove_pipeline_details_recursively(&mut self, pipeline_id: PipelineId) {
|
||||
self.pipeline_details.remove(&pipeline_id);
|
||||
|
||||
let children = self
|
||||
.pipeline_details
|
||||
.iter()
|
||||
.filter(|(_, pipeline_details)| {
|
||||
pipeline_details.parent_pipeline_id == Some(pipeline_id)
|
||||
})
|
||||
.map(|(&pipeline_id, _)| pipeline_id)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
for kid in children {
|
||||
self.remove_pipeline_details_recursively(kid);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1225,9 +1430,10 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
|
|||
MouseWindowEvent::MouseUp(_, p) => p,
|
||||
};
|
||||
|
||||
let result = match self.hit_test_at_point(point) {
|
||||
Some(result) => result,
|
||||
None => return,
|
||||
let Some(result) = self.hit_test_at_point(point) else {
|
||||
// TODO: Notify embedder that the event failed to hit test to any webview.
|
||||
// TODO: Also notify embedder if an event hits a webview but isn’t consumed?
|
||||
return;
|
||||
};
|
||||
|
||||
let (button, event_type) = match mouse_window_event {
|
||||
|
@ -1264,13 +1470,6 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
|
|||
flags: HitTestFlags,
|
||||
pipeline_id: Option<WebRenderPipelineId>,
|
||||
) -> Vec<CompositorHitTestResult> {
|
||||
let root_pipeline_id = match self.root_content_pipeline.id {
|
||||
Some(root_pipeline_id) => root_pipeline_id,
|
||||
None => return vec![],
|
||||
};
|
||||
if self.pipeline(root_pipeline_id).is_none() {
|
||||
return vec![];
|
||||
}
|
||||
// DevicePoint and WorldPoint are the same for us.
|
||||
let world_point = WorldPoint::from_untyped(point.to_untyped());
|
||||
let results =
|
||||
|
@ -1526,7 +1725,7 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
|
|||
|
||||
let mut transaction = Transaction::new();
|
||||
if zoom_changed {
|
||||
self.set_root_content_pipeline_handling_device_scaling(&mut transaction);
|
||||
self.send_root_pipeline_display_list_in_transaction(&mut transaction);
|
||||
}
|
||||
|
||||
if let Some((pipeline_id, external_id, offset)) = scroll_result {
|
||||
|
@ -1670,33 +1869,15 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
|
|||
}
|
||||
|
||||
fn update_after_zoom_or_hidpi_change(&mut self) {
|
||||
// The device pixel ratio used by the style system should include the scale from page pixels
|
||||
// to device pixels, but not including any pinch zoom.
|
||||
let device_pixel_ratio = self.device_pixels_per_page_pixel_not_including_page_zoom();
|
||||
let initial_viewport =
|
||||
self.embedder_coordinates.viewport.size().to_f32() / device_pixel_ratio;
|
||||
let data = WindowSizeData {
|
||||
device_pixel_ratio,
|
||||
initial_viewport,
|
||||
};
|
||||
|
||||
let top_level_browsing_context_id =
|
||||
self.root_content_pipeline.top_level_browsing_context_id;
|
||||
|
||||
let msg = ConstellationMsg::WindowSize(
|
||||
top_level_browsing_context_id,
|
||||
data,
|
||||
WindowSizeType::Resize,
|
||||
);
|
||||
if let Err(e) = self.constellation_chan.send(msg) {
|
||||
warn!("Sending window resize to constellation failed ({:?}).", e);
|
||||
for (top_level_browsing_context_id, webview) in self.webviews.painting_order() {
|
||||
self.send_window_size_message_for_top_level_browser_context(
|
||||
webview.rect,
|
||||
*top_level_browsing_context_id,
|
||||
);
|
||||
}
|
||||
|
||||
// Update the root transform in WebRender to reflect the new zoom.
|
||||
let mut transaction = webrender::Transaction::new();
|
||||
self.set_root_content_pipeline_handling_device_scaling(&mut transaction);
|
||||
self.webrender_api
|
||||
.send_transaction(self.webrender_document, transaction);
|
||||
self.send_root_pipeline_display_list();
|
||||
}
|
||||
|
||||
/// Simulate a pinch zoom
|
||||
|
@ -1928,6 +2109,10 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
|
|||
// and check if it is the one layout is expecting,
|
||||
let epoch = Epoch(epoch);
|
||||
if *pending_epoch != epoch {
|
||||
warn!(
|
||||
"{}: paint metrics: pending {:?} should be {:?}",
|
||||
id, pending_epoch, epoch
|
||||
);
|
||||
continue;
|
||||
}
|
||||
// in which case, we remove it from the list of pending metrics,
|
||||
|
@ -2032,12 +2217,11 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
|
|||
},
|
||||
};
|
||||
|
||||
// Nottify embedder that servo is ready to present.
|
||||
// Notify embedder that servo is ready to present.
|
||||
// Embedder should call `present` to tell compositor to continue rendering.
|
||||
self.waiting_on_present = true;
|
||||
let msg = ConstellationMsg::ReadyToPresent(
|
||||
self.root_content_pipeline.top_level_browsing_context_id,
|
||||
);
|
||||
let webview_ids = self.webviews.painting_order().map(|(&id, _)| id);
|
||||
let msg = ConstellationMsg::ReadyToPresent(webview_ids.collect());
|
||||
if let Err(e) = self.constellation_chan.send(msg) {
|
||||
warn!("Sending event to constellation failed ({:?}).", e);
|
||||
}
|
||||
|
@ -2077,14 +2261,6 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
|
|||
self.assert_gl_framebuffer_complete();
|
||||
|
||||
// Set the viewport background based on prefs.
|
||||
let viewport = self.embedder_coordinates.get_flipped_viewport();
|
||||
gl.scissor(
|
||||
viewport.min.x,
|
||||
viewport.min.y,
|
||||
viewport.size().width,
|
||||
viewport.size().height,
|
||||
);
|
||||
|
||||
let color = servo_config::pref!(shell.background_color.rgba);
|
||||
gl.clear_color(
|
||||
color[0] as f32,
|
||||
|
@ -2092,9 +2268,21 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
|
|||
color[2] as f32,
|
||||
color[3] as f32,
|
||||
);
|
||||
gl.enable(gleam::gl::SCISSOR_TEST);
|
||||
gl.clear(gleam::gl::COLOR_BUFFER_BIT);
|
||||
gl.disable(gleam::gl::SCISSOR_TEST);
|
||||
|
||||
// Clear the viewport rect of each top-level browsing context.
|
||||
for (_, webview) in self.webviews.painting_order() {
|
||||
let rect = self.embedder_coordinates.flip_rect(&webview.rect.to_i32());
|
||||
gl.scissor(
|
||||
rect.min.x,
|
||||
rect.min.y,
|
||||
rect.size().width,
|
||||
rect.size().height,
|
||||
);
|
||||
gl.enable(gleam::gl::SCISSOR_TEST);
|
||||
gl.clear(gleam::gl::COLOR_BUFFER_BIT);
|
||||
gl.disable(gleam::gl::SCISSOR_TEST);
|
||||
}
|
||||
|
||||
self.assert_gl_framebuffer_complete();
|
||||
}
|
||||
|
||||
|
|
|
@ -15,9 +15,13 @@ use webrender_api::DocumentId;
|
|||
|
||||
pub use crate::compositor::{CompositeTarget, IOCompositor, ShutdownState};
|
||||
|
||||
#[macro_use]
|
||||
mod tracing;
|
||||
|
||||
mod compositor;
|
||||
mod gl;
|
||||
mod touch;
|
||||
pub mod webview;
|
||||
pub mod windowing;
|
||||
|
||||
/// Data used to construct a compositor.
|
||||
|
|
58
components/compositing/tracing.rs
Normal file
58
components/compositing/tracing.rs
Normal file
|
@ -0,0 +1,58 @@
|
|||
/* 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/. */
|
||||
|
||||
/// Log an event from constellation at trace level.
|
||||
/// - To disable tracing: RUST_LOG='compositor<constellation@=off'
|
||||
/// - To enable tracing: RUST_LOG='compositor<constellation@'
|
||||
macro_rules! trace_msg_from_constellation {
|
||||
// This macro only exists to put the docs in the same file as the target prefix,
|
||||
// so the macro definition is always the same.
|
||||
($event:expr, $($rest:tt)+) => {
|
||||
::log::trace!(target: $crate::tracing::LogTarget::log_target(&$event), $($rest)+)
|
||||
};
|
||||
}
|
||||
|
||||
/// Get the log target for an event, as a static string.
|
||||
pub(crate) trait LogTarget {
|
||||
fn log_target(&self) -> &'static str;
|
||||
}
|
||||
|
||||
mod from_constellation {
|
||||
use super::LogTarget;
|
||||
|
||||
macro_rules! target {
|
||||
($($name:literal)+) => {
|
||||
concat!("compositor<constellation@", $($name),+)
|
||||
};
|
||||
}
|
||||
|
||||
impl LogTarget for compositing_traits::CompositorMsg {
|
||||
fn log_target(&self) -> &'static str {
|
||||
match self {
|
||||
Self::ShutdownComplete => target!("ShutdownComplete"),
|
||||
Self::ChangeRunningAnimationsState(..) => target!("ChangeRunningAnimationsState"),
|
||||
Self::CreateOrUpdateWebView(..) => target!("CreateOrUpdateWebView"),
|
||||
Self::RemoveWebView(..) => target!("RemoveWebView"),
|
||||
Self::MoveResizeWebView(..) => target!("MoveResizeWebView"),
|
||||
Self::ShowWebView(..) => target!("ShowWebView"),
|
||||
Self::HideWebView(..) => target!("HideWebView"),
|
||||
Self::RaiseWebViewToTop(..) => target!("RaiseWebViewToTop"),
|
||||
Self::TouchEventProcessed(..) => target!("TouchEventProcessed"),
|
||||
Self::CreatePng(..) => target!("CreatePng"),
|
||||
Self::IsReadyToSaveImageReply(..) => target!("IsReadyToSaveImageReply"),
|
||||
Self::SetThrottled(..) => target!("SetThrottled"),
|
||||
Self::NewWebRenderFrameReady(..) => target!("NewWebRenderFrameReady"),
|
||||
Self::PipelineExited(..) => target!("PipelineExited"),
|
||||
Self::PendingPaintMetric(..) => target!("PendingPaintMetric"),
|
||||
Self::LoadComplete(..) => target!("LoadComplete"),
|
||||
Self::WebDriverMouseButtonEvent(..) => target!("WebDriverMouseButtonEvent"),
|
||||
Self::WebDriverMouseMoveEvent(..) => target!("WebDriverMouseMoveEvent"),
|
||||
Self::GetClientWindow(..) => target!("GetClientWindow"),
|
||||
Self::GetScreenSize(..) => target!("GetScreenSize"),
|
||||
Self::GetScreenAvailSize(..) => target!("GetScreenAvailSize"),
|
||||
Self::Forwarded(..) => target!("Forwarded"),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
245
components/compositing/webview.rs
Normal file
245
components/compositing/webview.rs
Normal file
|
@ -0,0 +1,245 @@
|
|||
/* 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/. */
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use msg::constellation_msg::{PipelineId, WebViewId};
|
||||
use webrender_api::units::DeviceRect;
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct WebView {
|
||||
pub pipeline_id: Option<PipelineId>,
|
||||
pub rect: DeviceRect,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct WebViewManager<WebView> {
|
||||
/// Our top-level browsing contexts. In the WebRender scene, their pipelines are the children of
|
||||
/// a single root pipeline that also applies any pinch zoom transformation.
|
||||
webviews: HashMap<WebViewId, WebView>,
|
||||
|
||||
/// The order to paint them in, topmost last.
|
||||
painting_order: Vec<WebViewId>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub struct WebViewAlreadyExists(pub WebViewId);
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub struct UnknownWebView(pub WebViewId);
|
||||
|
||||
impl<WebView> WebViewManager<WebView> {
|
||||
pub fn add(
|
||||
&mut self,
|
||||
webview_id: WebViewId,
|
||||
webview: WebView,
|
||||
) -> Result<&mut WebView, WebViewAlreadyExists> {
|
||||
if self.webviews.contains_key(&webview_id) {
|
||||
return Err(WebViewAlreadyExists(webview_id));
|
||||
}
|
||||
Ok(self.webviews.entry(webview_id).or_insert(webview))
|
||||
}
|
||||
|
||||
pub fn remove(&mut self, webview_id: WebViewId) -> Result<WebView, UnknownWebView> {
|
||||
self.painting_order.retain(|b| *b != webview_id);
|
||||
self.webviews
|
||||
.remove(&webview_id)
|
||||
.ok_or(UnknownWebView(webview_id))
|
||||
}
|
||||
|
||||
pub fn get(&self, webview_id: WebViewId) -> Option<&WebView> {
|
||||
self.webviews.get(&webview_id)
|
||||
}
|
||||
|
||||
pub fn get_mut(&mut self, webview_id: WebViewId) -> Option<&mut WebView> {
|
||||
self.webviews.get_mut(&webview_id)
|
||||
}
|
||||
|
||||
/// Returns true iff the painting order actually changed.
|
||||
pub fn show(&mut self, webview_id: WebViewId) -> Result<bool, UnknownWebView> {
|
||||
if !self.webviews.contains_key(&webview_id) {
|
||||
return Err(UnknownWebView(webview_id));
|
||||
}
|
||||
if !self.painting_order.contains(&webview_id) {
|
||||
self.painting_order.push(webview_id);
|
||||
return Ok(true);
|
||||
}
|
||||
Ok(false)
|
||||
}
|
||||
|
||||
/// Returns true iff the painting order actually changed.
|
||||
pub fn hide(&mut self, webview_id: WebViewId) -> Result<bool, UnknownWebView> {
|
||||
if !self.webviews.contains_key(&webview_id) {
|
||||
return Err(UnknownWebView(webview_id));
|
||||
}
|
||||
if self.painting_order.contains(&webview_id) {
|
||||
self.painting_order.retain(|b| *b != webview_id);
|
||||
return Ok(true);
|
||||
}
|
||||
Ok(false)
|
||||
}
|
||||
|
||||
/// Returns true iff the painting order actually changed.
|
||||
pub fn hide_all(&mut self) -> bool {
|
||||
if !self.painting_order.is_empty() {
|
||||
self.painting_order.clear();
|
||||
return true;
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
/// Returns true iff the painting order actually changed.
|
||||
pub fn raise_to_top(&mut self, webview_id: WebViewId) -> Result<bool, UnknownWebView> {
|
||||
if !self.webviews.contains_key(&webview_id) {
|
||||
return Err(UnknownWebView(webview_id));
|
||||
}
|
||||
if self.painting_order.last() != Some(&webview_id) {
|
||||
self.hide(webview_id)?;
|
||||
self.show(webview_id)?;
|
||||
return Ok(true);
|
||||
}
|
||||
Ok(false)
|
||||
}
|
||||
|
||||
pub fn painting_order(&self) -> impl Iterator<Item = (&WebViewId, &WebView)> {
|
||||
self.painting_order
|
||||
.iter()
|
||||
.flat_map(move |webview_id| self.get(*webview_id).map(|b| (webview_id, b)))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use std::num::NonZeroU32;
|
||||
|
||||
use msg::constellation_msg::{
|
||||
BrowsingContextId, BrowsingContextIndex, PipelineNamespace, PipelineNamespaceId,
|
||||
TopLevelBrowsingContextId,
|
||||
};
|
||||
|
||||
use crate::webview::{UnknownWebView, WebViewAlreadyExists, WebViewManager};
|
||||
|
||||
fn top_level_id(namespace_id: u32, index: u32) -> TopLevelBrowsingContextId {
|
||||
TopLevelBrowsingContextId(BrowsingContextId {
|
||||
namespace_id: PipelineNamespaceId(namespace_id),
|
||||
index: BrowsingContextIndex(NonZeroU32::new(index).unwrap()),
|
||||
})
|
||||
}
|
||||
|
||||
fn webviews_sorted<WebView: Clone>(
|
||||
webviews: &WebViewManager<WebView>,
|
||||
) -> Vec<(TopLevelBrowsingContextId, WebView)> {
|
||||
let mut keys = webviews.webviews.keys().collect::<Vec<_>>();
|
||||
keys.sort();
|
||||
keys.iter()
|
||||
.map(|&id| (*id, webviews.webviews.get(id).cloned().unwrap()))
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test() {
|
||||
PipelineNamespace::install(PipelineNamespaceId(0));
|
||||
let mut webviews = WebViewManager::default();
|
||||
|
||||
// add() adds the webview to the map, but not the painting order.
|
||||
assert!(webviews.add(TopLevelBrowsingContextId::new(), 'a').is_ok());
|
||||
assert!(webviews.add(TopLevelBrowsingContextId::new(), 'b').is_ok());
|
||||
assert!(webviews.add(TopLevelBrowsingContextId::new(), 'c').is_ok());
|
||||
assert_eq!(
|
||||
webviews_sorted(&webviews),
|
||||
vec![
|
||||
(top_level_id(0, 1), 'a'),
|
||||
(top_level_id(0, 2), 'b'),
|
||||
(top_level_id(0, 3), 'c'),
|
||||
]
|
||||
);
|
||||
assert!(webviews.painting_order.is_empty());
|
||||
|
||||
// add() returns WebViewAlreadyExists if the webview id already exists.
|
||||
assert_eq!(
|
||||
webviews.add(top_level_id(0, 3), 'd'),
|
||||
Err(WebViewAlreadyExists(top_level_id(0, 3)))
|
||||
);
|
||||
|
||||
// Other methods return UnknownWebView or None if the webview id doesn’t exist.
|
||||
assert_eq!(
|
||||
webviews.remove(top_level_id(1, 1)),
|
||||
Err(UnknownWebView(top_level_id(1, 1)))
|
||||
);
|
||||
assert_eq!(webviews.get(top_level_id(1, 1)), None);
|
||||
assert_eq!(webviews.get_mut(top_level_id(1, 1)), None);
|
||||
assert_eq!(
|
||||
webviews.show(top_level_id(1, 1)),
|
||||
Err(UnknownWebView(top_level_id(1, 1)))
|
||||
);
|
||||
assert_eq!(
|
||||
webviews.hide(top_level_id(1, 1)),
|
||||
Err(UnknownWebView(top_level_id(1, 1)))
|
||||
);
|
||||
assert_eq!(
|
||||
webviews.raise_to_top(top_level_id(1, 1)),
|
||||
Err(UnknownWebView(top_level_id(1, 1)))
|
||||
);
|
||||
|
||||
// For webviews not yet visible, both show() and raise_to_top() add the given webview on top.
|
||||
assert_eq!(webviews.show(top_level_id(0, 2)), Ok(true));
|
||||
assert_eq!(webviews.show(top_level_id(0, 2)), Ok(false));
|
||||
assert_eq!(webviews.painting_order, vec![top_level_id(0, 2)]);
|
||||
assert_eq!(webviews.raise_to_top(top_level_id(0, 1)), Ok(true));
|
||||
assert_eq!(webviews.raise_to_top(top_level_id(0, 1)), Ok(false));
|
||||
assert_eq!(
|
||||
webviews.painting_order,
|
||||
vec![top_level_id(0, 2), top_level_id(0, 1)]
|
||||
);
|
||||
assert_eq!(webviews.show(top_level_id(0, 3)), Ok(true));
|
||||
assert_eq!(webviews.show(top_level_id(0, 3)), Ok(false));
|
||||
assert_eq!(
|
||||
webviews.painting_order,
|
||||
vec![top_level_id(0, 2), top_level_id(0, 1), top_level_id(0, 3)]
|
||||
);
|
||||
|
||||
// For webviews already visible, show() does nothing, while raise_to_top() makes it on top.
|
||||
assert_eq!(webviews.show(top_level_id(0, 1)), Ok(false));
|
||||
assert_eq!(
|
||||
webviews.painting_order,
|
||||
vec![top_level_id(0, 2), top_level_id(0, 1), top_level_id(0, 3)]
|
||||
);
|
||||
assert_eq!(webviews.raise_to_top(top_level_id(0, 1)), Ok(true));
|
||||
assert_eq!(webviews.raise_to_top(top_level_id(0, 1)), Ok(false));
|
||||
assert_eq!(
|
||||
webviews.painting_order,
|
||||
vec![top_level_id(0, 2), top_level_id(0, 3), top_level_id(0, 1)]
|
||||
);
|
||||
|
||||
// hide() removes the webview from the painting order, but not the map.
|
||||
assert_eq!(webviews.hide(top_level_id(0, 3)), Ok(true));
|
||||
assert_eq!(webviews.hide(top_level_id(0, 3)), Ok(false));
|
||||
assert_eq!(
|
||||
webviews.painting_order,
|
||||
vec![top_level_id(0, 2), top_level_id(0, 1)]
|
||||
);
|
||||
assert_eq!(
|
||||
webviews_sorted(&webviews),
|
||||
vec![
|
||||
(top_level_id(0, 1), 'a'),
|
||||
(top_level_id(0, 2), 'b'),
|
||||
(top_level_id(0, 3), 'c'),
|
||||
]
|
||||
);
|
||||
|
||||
// painting_order() returns only the visible webviews, in painting order.
|
||||
let mut painting_order = webviews.painting_order();
|
||||
assert_eq!(painting_order.next(), Some((&top_level_id(0, 2), &'b')));
|
||||
assert_eq!(painting_order.next(), Some((&top_level_id(0, 1), &'a')));
|
||||
assert_eq!(painting_order.next(), None);
|
||||
drop(painting_order);
|
||||
|
||||
// remove() removes the given webview from both the map and the painting order.
|
||||
assert!(webviews.remove(top_level_id(0, 1)).is_ok());
|
||||
assert!(webviews.remove(top_level_id(0, 2)).is_ok());
|
||||
assert!(webviews.remove(top_level_id(0, 3)).is_ok());
|
||||
assert!(webviews_sorted(&webviews).is_empty());
|
||||
assert!(webviews.painting_order.is_empty());
|
||||
}
|
||||
}
|
|
@ -19,7 +19,7 @@ use script_traits::{
|
|||
use servo_geometry::DeviceIndependentPixel;
|
||||
use servo_url::ServoUrl;
|
||||
use style_traits::DevicePixel;
|
||||
use webrender_api::units::{DeviceIntPoint, DeviceIntRect, DeviceIntSize, DevicePoint};
|
||||
use webrender_api::units::{DeviceIntPoint, DeviceIntRect, DeviceIntSize, DevicePoint, DeviceRect};
|
||||
use webrender_api::ScrollLocation;
|
||||
|
||||
#[derive(Clone)]
|
||||
|
@ -51,7 +51,7 @@ pub enum EmbedderEvent {
|
|||
/// message, the window must make the same GL context as in `PrepareRenderingEvent` current.
|
||||
Refresh,
|
||||
/// Sent when the window is resized.
|
||||
Resize,
|
||||
WindowResize,
|
||||
/// Sent when a navigation request from script is allowed/refused.
|
||||
AllowNavigationResponse(PipelineId, bool),
|
||||
/// Sent when a new URL is to be loaded.
|
||||
|
@ -83,15 +83,24 @@ pub enum EmbedderEvent {
|
|||
Keyboard(KeyboardEvent),
|
||||
/// Sent when Ctr+R/Apple+R is called to reload the current page.
|
||||
Reload(TopLevelBrowsingContextId),
|
||||
/// Create a new top level browsing context
|
||||
/// Create a new top-level browsing context.
|
||||
NewWebView(ServoUrl, TopLevelBrowsingContextId),
|
||||
/// Close a top level browsing context
|
||||
/// Close a top-level browsing context.
|
||||
CloseWebView(TopLevelBrowsingContextId),
|
||||
/// Panic a top level browsing context.
|
||||
/// Panic a top-level browsing context.
|
||||
SendError(Option<TopLevelBrowsingContextId>, String),
|
||||
/// Make a top level browsing context visible, hiding the previous
|
||||
/// visible one.
|
||||
/// Move and/or resize a webview to the given rect.
|
||||
MoveResizeWebView(TopLevelBrowsingContextId, DeviceRect),
|
||||
/// Start painting a webview, and optionally stop painting all others.
|
||||
ShowWebView(TopLevelBrowsingContextId, bool),
|
||||
/// Stop painting a webview.
|
||||
HideWebView(TopLevelBrowsingContextId),
|
||||
/// Start painting a webview on top of all others, and optionally stop painting all others.
|
||||
RaiseWebViewToTop(TopLevelBrowsingContextId, bool),
|
||||
/// Make a webview focused.
|
||||
FocusWebView(TopLevelBrowsingContextId),
|
||||
/// Make none of the webviews focused.
|
||||
BlurWebView,
|
||||
/// Toggles a debug flag in WebRender
|
||||
ToggleWebRenderDebug(WebRenderDebugOption),
|
||||
/// Capture current WebRender
|
||||
|
@ -124,7 +133,7 @@ impl Debug for EmbedderEvent {
|
|||
match *self {
|
||||
EmbedderEvent::Idle => write!(f, "Idle"),
|
||||
EmbedderEvent::Refresh => write!(f, "Refresh"),
|
||||
EmbedderEvent::Resize => write!(f, "Resize"),
|
||||
EmbedderEvent::WindowResize => write!(f, "Resize"),
|
||||
EmbedderEvent::Keyboard(..) => write!(f, "Keyboard"),
|
||||
EmbedderEvent::AllowNavigationResponse(..) => write!(f, "AllowNavigationResponse"),
|
||||
EmbedderEvent::LoadUrl(..) => write!(f, "LoadUrl"),
|
||||
|
@ -139,10 +148,32 @@ impl Debug for EmbedderEvent {
|
|||
EmbedderEvent::Navigation(..) => write!(f, "Navigation"),
|
||||
EmbedderEvent::Quit => write!(f, "Quit"),
|
||||
EmbedderEvent::Reload(..) => write!(f, "Reload"),
|
||||
EmbedderEvent::NewWebView(..) => write!(f, "NewWebView"),
|
||||
EmbedderEvent::NewWebView(_, TopLevelBrowsingContextId(webview_id)) => {
|
||||
write!(f, "NewWebView({webview_id:?})")
|
||||
},
|
||||
EmbedderEvent::SendError(..) => write!(f, "SendError"),
|
||||
EmbedderEvent::CloseWebView(..) => write!(f, "CloseWebView"),
|
||||
EmbedderEvent::FocusWebView(..) => write!(f, "FocusWebView"),
|
||||
EmbedderEvent::CloseWebView(TopLevelBrowsingContextId(webview_id)) => {
|
||||
write!(f, "CloseWebView({webview_id:?})")
|
||||
},
|
||||
EmbedderEvent::MoveResizeWebView(webview_id, _) => {
|
||||
write!(f, "MoveResizeWebView({webview_id:?})")
|
||||
},
|
||||
EmbedderEvent::ShowWebView(TopLevelBrowsingContextId(webview_id), hide_others) => {
|
||||
write!(f, "ShowWebView({webview_id:?}, {hide_others})")
|
||||
},
|
||||
EmbedderEvent::HideWebView(TopLevelBrowsingContextId(webview_id)) => {
|
||||
write!(f, "HideWebView({webview_id:?})")
|
||||
},
|
||||
EmbedderEvent::RaiseWebViewToTop(
|
||||
TopLevelBrowsingContextId(webview_id),
|
||||
hide_others,
|
||||
) => {
|
||||
write!(f, "RaiseWebViewToTop({webview_id:?}, {hide_others})")
|
||||
},
|
||||
EmbedderEvent::FocusWebView(TopLevelBrowsingContextId(webview_id)) => {
|
||||
write!(f, "FocusWebView({webview_id:?})")
|
||||
},
|
||||
EmbedderEvent::BlurWebView => write!(f, "BlurWebView"),
|
||||
EmbedderEvent::ToggleWebRenderDebug(..) => write!(f, "ToggleWebRenderDebug"),
|
||||
EmbedderEvent::CaptureWebRender => write!(f, "CaptureWebRender"),
|
||||
EmbedderEvent::ToggleSamplingProfiler(..) => write!(f, "ToggleSamplingProfiler"),
|
||||
|
@ -211,15 +242,20 @@ pub struct EmbedderCoordinates {
|
|||
impl EmbedderCoordinates {
|
||||
/// Get the unflipped viewport rectangle for use with the WebRender API.
|
||||
pub fn get_viewport(&self) -> DeviceIntRect {
|
||||
DeviceIntRect::from_untyped(&self.viewport.to_untyped())
|
||||
self.viewport.clone()
|
||||
}
|
||||
|
||||
/// Get the flipped viewport rectangle. This should be used when drawing directly
|
||||
/// to the framebuffer with OpenGL commands.
|
||||
/// Flip the given rect.
|
||||
/// This should be used when drawing directly to the framebuffer with OpenGL commands.
|
||||
pub fn flip_rect(&self, rect: &DeviceIntRect) -> DeviceIntRect {
|
||||
let mut result = rect.clone();
|
||||
result.min.y = self.framebuffer.height - result.min.y - result.size().height;
|
||||
result
|
||||
}
|
||||
|
||||
/// Get the flipped viewport rectangle.
|
||||
/// This should be used when drawing directly to the framebuffer with OpenGL commands.
|
||||
pub fn get_flipped_viewport(&self) -> DeviceIntRect {
|
||||
let fb_height = self.framebuffer.height;
|
||||
let mut view = self.viewport;
|
||||
view.min.y = fb_height - view.min.y - view.size().height;
|
||||
DeviceIntRect::from_untyped(&view.to_untyped())
|
||||
self.flip_rect(&self.get_viewport())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1471,6 +1471,48 @@ where
|
|||
}
|
||||
self.handle_panic(top_level_browsing_context_id, error, None);
|
||||
},
|
||||
FromCompositorMsg::MoveResizeWebView(top_level_browsing_context_id, rect) => {
|
||||
if self.webviews.get(top_level_browsing_context_id).is_none() {
|
||||
return warn!(
|
||||
"{}: MoveResizeWebView on unknown top-level browsing context",
|
||||
top_level_browsing_context_id
|
||||
);
|
||||
}
|
||||
self.compositor_proxy.send(CompositorMsg::MoveResizeWebView(
|
||||
top_level_browsing_context_id,
|
||||
rect,
|
||||
));
|
||||
},
|
||||
FromCompositorMsg::ShowWebView(webview_id, hide_others) => {
|
||||
if self.webviews.get(webview_id).is_none() {
|
||||
return warn!(
|
||||
"{}: ShowWebView on unknown top-level browsing context",
|
||||
webview_id
|
||||
);
|
||||
}
|
||||
self.compositor_proxy
|
||||
.send(CompositorMsg::ShowWebView(webview_id, hide_others));
|
||||
},
|
||||
FromCompositorMsg::HideWebView(webview_id) => {
|
||||
if self.webviews.get(webview_id).is_none() {
|
||||
return warn!(
|
||||
"{}: HideWebView on unknown top-level browsing context",
|
||||
webview_id
|
||||
);
|
||||
}
|
||||
self.compositor_proxy
|
||||
.send(CompositorMsg::HideWebView(webview_id));
|
||||
},
|
||||
FromCompositorMsg::RaiseWebViewToTop(webview_id, hide_others) => {
|
||||
if self.webviews.get(webview_id).is_none() {
|
||||
return warn!(
|
||||
"{}: RaiseWebViewToTop on unknown top-level browsing context",
|
||||
webview_id
|
||||
);
|
||||
}
|
||||
self.compositor_proxy
|
||||
.send(CompositorMsg::RaiseWebViewToTop(webview_id, hide_others));
|
||||
},
|
||||
FromCompositorMsg::FocusWebView(top_level_browsing_context_id) => {
|
||||
if self.webviews.get(top_level_browsing_context_id).is_none() {
|
||||
return warn!("{top_level_browsing_context_id}: FocusWebView on unknown top-level browsing context");
|
||||
|
@ -1480,9 +1522,6 @@ where
|
|||
Some(top_level_browsing_context_id),
|
||||
EmbedderMsg::WebViewFocused(top_level_browsing_context_id),
|
||||
));
|
||||
if !cfg!(feature = "multiview") {
|
||||
self.update_frame_tree_if_focused(top_level_browsing_context_id);
|
||||
}
|
||||
},
|
||||
FromCompositorMsg::BlurWebView => {
|
||||
self.webviews.unfocus();
|
||||
|
@ -1539,11 +1578,9 @@ where
|
|||
FromCompositorMsg::SetWebViewThrottled(webview_id, throttled) => {
|
||||
self.set_webview_throttled(webview_id, throttled);
|
||||
},
|
||||
FromCompositorMsg::ReadyToPresent(top_level_browsing_context_id) => {
|
||||
self.embedder_proxy.send((
|
||||
Some(top_level_browsing_context_id),
|
||||
EmbedderMsg::ReadyToPresent,
|
||||
));
|
||||
FromCompositorMsg::ReadyToPresent(webview_ids) => {
|
||||
self.embedder_proxy
|
||||
.send((None, EmbedderMsg::ReadyToPresent(webview_ids)));
|
||||
},
|
||||
FromCompositorMsg::Gamepad(gamepad_event) => {
|
||||
self.handle_gamepad_msg(gamepad_event);
|
||||
|
@ -3016,7 +3053,8 @@ where
|
|||
.send((None, EmbedderMsg::WebViewBlurred));
|
||||
}
|
||||
self.webviews.remove(top_level_browsing_context_id);
|
||||
// TODO Send the compositor a RemoveWebView event.
|
||||
self.compositor_proxy
|
||||
.send(CompositorMsg::RemoveWebView(top_level_browsing_context_id));
|
||||
self.embedder_proxy.send((
|
||||
Some(top_level_browsing_context_id),
|
||||
EmbedderMsg::WebViewClosed(top_level_browsing_context_id),
|
||||
|
@ -3804,7 +3842,7 @@ where
|
|||
self.notify_history_changed(top_level_browsing_context_id);
|
||||
|
||||
self.trim_history(top_level_browsing_context_id);
|
||||
self.update_frame_tree_if_focused(top_level_browsing_context_id);
|
||||
self.update_webview_in_compositor(top_level_browsing_context_id);
|
||||
}
|
||||
|
||||
fn update_browsing_context(
|
||||
|
@ -4763,7 +4801,7 @@ where
|
|||
}
|
||||
|
||||
self.notify_history_changed(change.top_level_browsing_context_id);
|
||||
self.update_frame_tree_if_focused(change.top_level_browsing_context_id);
|
||||
self.update_webview_in_compositor(change.top_level_browsing_context_id);
|
||||
}
|
||||
|
||||
fn focused_browsing_context_is_descendant_of(
|
||||
|
@ -5376,24 +5414,15 @@ where
|
|||
}
|
||||
|
||||
/// Send the frame tree for the given webview to the compositor.
|
||||
fn update_frame_tree_if_focused(
|
||||
&mut self,
|
||||
top_level_browsing_context_id: TopLevelBrowsingContextId,
|
||||
) {
|
||||
// Only send the frame tree if the given webview is focused.
|
||||
if let Some(focused_webview_id) = self.webviews.focused_webview().map(|(id, _)| id) {
|
||||
if top_level_browsing_context_id != focused_webview_id {
|
||||
return;
|
||||
}
|
||||
}
|
||||
fn update_webview_in_compositor(&mut self, webview_id: WebViewId) {
|
||||
// Note that this function can panic, due to ipc-channel creation failure.
|
||||
// avoiding this panic would require a mechanism for dealing
|
||||
// with low-resource scenarios.
|
||||
let browsing_context_id = BrowsingContextId::from(top_level_browsing_context_id);
|
||||
let browsing_context_id = BrowsingContextId::from(webview_id);
|
||||
if let Some(frame_tree) = self.browsing_context_to_sendable(browsing_context_id) {
|
||||
debug!("{}: Sending frame tree", browsing_context_id);
|
||||
self.compositor_proxy
|
||||
.send(CompositorMsg::SetFrameTree(frame_tree));
|
||||
.send(CompositorMsg::CreateOrUpdateWebView(frame_tree));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -59,37 +59,41 @@ mod from_compositor {
|
|||
fn log_target(&self) -> &'static str {
|
||||
match self {
|
||||
Self::Exit => target!("Exit"),
|
||||
Self::GetBrowsingContext(_, _) => target!("GetBrowsingContext"),
|
||||
Self::GetPipeline(_, _) => target!("GetPipeline"),
|
||||
Self::GetFocusTopLevelBrowsingContext(_) => {
|
||||
Self::GetBrowsingContext(..) => target!("GetBrowsingContext"),
|
||||
Self::GetPipeline(..) => target!("GetPipeline"),
|
||||
Self::GetFocusTopLevelBrowsingContext(..) => {
|
||||
target!("GetFocusTopLevelBrowsingContext")
|
||||
},
|
||||
Self::IsReadyToSaveImage(_) => target!("IsReadyToSaveImage"),
|
||||
Self::Keyboard(_) => target!("Keyboard"),
|
||||
Self::AllowNavigationResponse(_, _) => target!("AllowNavigationResponse"),
|
||||
Self::LoadUrl(_, _) => target!("LoadUrl"),
|
||||
Self::IsReadyToSaveImage(..) => target!("IsReadyToSaveImage"),
|
||||
Self::Keyboard(..) => target!("Keyboard"),
|
||||
Self::AllowNavigationResponse(..) => target!("AllowNavigationResponse"),
|
||||
Self::LoadUrl(..) => target!("LoadUrl"),
|
||||
Self::ClearCache => target!("ClearCache"),
|
||||
Self::TraverseHistory(_, _) => target!("TraverseHistory"),
|
||||
Self::WindowSize(_, _, _) => target!("WindowSize"),
|
||||
Self::TickAnimation(_, _) => target!("TickAnimation"),
|
||||
Self::WebDriverCommand(_) => target!("WebDriverCommand"),
|
||||
Self::Reload(_) => target!("Reload"),
|
||||
Self::LogEntry(_, _, _) => target!("LogEntry"),
|
||||
Self::NewWebView(_, _) => target!("NewWebView"),
|
||||
Self::CloseWebView(_) => target!("CloseWebView"),
|
||||
Self::SendError(_, _) => target!("SendError"),
|
||||
Self::FocusWebView(_) => target!("FocusWebView"),
|
||||
Self::TraverseHistory(..) => target!("TraverseHistory"),
|
||||
Self::WindowSize(..) => target!("WindowSize"),
|
||||
Self::TickAnimation(..) => target!("TickAnimation"),
|
||||
Self::WebDriverCommand(..) => target!("WebDriverCommand"),
|
||||
Self::Reload(..) => target!("Reload"),
|
||||
Self::LogEntry(..) => target!("LogEntry"),
|
||||
Self::NewWebView(..) => target!("NewWebView"),
|
||||
Self::CloseWebView(..) => target!("CloseWebView"),
|
||||
Self::SendError(..) => target!("SendError"),
|
||||
Self::MoveResizeWebView(..) => target!("MoveResizeWebView"),
|
||||
Self::ShowWebView(..) => target!("ShowWebView"),
|
||||
Self::HideWebView(..) => target!("HideWebView"),
|
||||
Self::RaiseWebViewToTop(..) => target!("RaiseWebViewToTop"),
|
||||
Self::FocusWebView(..) => target!("FocusWebView"),
|
||||
Self::BlurWebView => target!("BlurWebView"),
|
||||
Self::ForwardEvent(_, event) => event.log_target(),
|
||||
Self::SetCursor(_) => target!("SetCursor"),
|
||||
Self::EnableProfiler(_, _) => target!("EnableProfiler"),
|
||||
Self::SetCursor(..) => target!("SetCursor"),
|
||||
Self::EnableProfiler(..) => target!("EnableProfiler"),
|
||||
Self::DisableProfiler => target!("DisableProfiler"),
|
||||
Self::ExitFullScreen(_) => target!("ExitFullScreen"),
|
||||
Self::MediaSessionAction(_) => target!("MediaSessionAction"),
|
||||
Self::SetWebViewThrottled(_, _) => target!("SetWebViewThrottled"),
|
||||
Self::IMEDismissed => target!("IMEDismissed"),
|
||||
Self::ReadyToPresent(_) => target!("ReadyToPresent"),
|
||||
Self::Gamepad(_) => target!("Gamepad"),
|
||||
Self::ReadyToPresent(..) => target!("ReadyToPresent"),
|
||||
Self::Gamepad(..) => target!("Gamepad"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -102,15 +106,15 @@ mod from_compositor {
|
|||
};
|
||||
}
|
||||
match self {
|
||||
Self::ResizeEvent(_, _) => target_variant!("ResizeEvent"),
|
||||
Self::MouseButtonEvent(_, _, _, _, _, _) => target_variant!("MouseButtonEvent"),
|
||||
Self::MouseMoveEvent(_, _, _) => target_variant!("MouseMoveEvent"),
|
||||
Self::TouchEvent(_, _, _, _) => target_variant!("TouchEvent"),
|
||||
Self::WheelEvent(_, _, _) => target_variant!("WheelEvent"),
|
||||
Self::KeyboardEvent(_) => target_variant!("KeyboardEvent"),
|
||||
Self::CompositionEvent(_) => target_variant!("CompositionEvent"),
|
||||
Self::ResizeEvent(..) => target_variant!("ResizeEvent"),
|
||||
Self::MouseButtonEvent(..) => target_variant!("MouseButtonEvent"),
|
||||
Self::MouseMoveEvent(..) => target_variant!("MouseMoveEvent"),
|
||||
Self::TouchEvent(..) => target_variant!("TouchEvent"),
|
||||
Self::WheelEvent(..) => target_variant!("WheelEvent"),
|
||||
Self::KeyboardEvent(..) => target_variant!("KeyboardEvent"),
|
||||
Self::CompositionEvent(..) => target_variant!("CompositionEvent"),
|
||||
Self::IMEDismissedEvent => target_variant!("IMEDismissedEvent"),
|
||||
Self::GamepadEvent(_) => target_variant!("GamepadEvent"),
|
||||
Self::GamepadEvent(..) => target_variant!("GamepadEvent"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -128,65 +132,65 @@ mod from_script {
|
|||
impl LogTarget for script_traits::ScriptMsg {
|
||||
fn log_target(&self) -> &'static str {
|
||||
match self {
|
||||
Self::CompleteMessagePortTransfer(_, _) => target!("CompleteMessagePortTransfer"),
|
||||
Self::MessagePortTransferResult(_, _, _) => target!("MessagePortTransferResult"),
|
||||
Self::NewMessagePort(_, _) => target!("NewMessagePort"),
|
||||
Self::NewMessagePortRouter(_, _) => target!("NewMessagePortRouter"),
|
||||
Self::RemoveMessagePortRouter(_) => target!("RemoveMessagePortRouter"),
|
||||
Self::RerouteMessagePort(_, _) => target!("RerouteMessagePort"),
|
||||
Self::MessagePortShipped(_) => target!("MessagePortShipped"),
|
||||
Self::RemoveMessagePort(_) => target!("RemoveMessagePort"),
|
||||
Self::EntanglePorts(_, _) => target!("EntanglePorts"),
|
||||
Self::NewBroadcastChannelRouter(_, _, _) => target!("NewBroadcastChannelRouter"),
|
||||
Self::RemoveBroadcastChannelRouter(_, _) => target!("RemoveBroadcastChannelRouter"),
|
||||
Self::NewBroadcastChannelNameInRouter(_, _, _) => {
|
||||
Self::CompleteMessagePortTransfer(..) => target!("CompleteMessagePortTransfer"),
|
||||
Self::MessagePortTransferResult(..) => target!("MessagePortTransferResult"),
|
||||
Self::NewMessagePort(..) => target!("NewMessagePort"),
|
||||
Self::NewMessagePortRouter(..) => target!("NewMessagePortRouter"),
|
||||
Self::RemoveMessagePortRouter(..) => target!("RemoveMessagePortRouter"),
|
||||
Self::RerouteMessagePort(..) => target!("RerouteMessagePort"),
|
||||
Self::MessagePortShipped(..) => target!("MessagePortShipped"),
|
||||
Self::RemoveMessagePort(..) => target!("RemoveMessagePort"),
|
||||
Self::EntanglePorts(..) => target!("EntanglePorts"),
|
||||
Self::NewBroadcastChannelRouter(..) => target!("NewBroadcastChannelRouter"),
|
||||
Self::RemoveBroadcastChannelRouter(..) => target!("RemoveBroadcastChannelRouter"),
|
||||
Self::NewBroadcastChannelNameInRouter(..) => {
|
||||
target!("NewBroadcastChannelNameInRouter")
|
||||
},
|
||||
Self::RemoveBroadcastChannelNameInRouter(_, _, _) => {
|
||||
Self::RemoveBroadcastChannelNameInRouter(..) => {
|
||||
target!("RemoveBroadcastChannelNameInRouter")
|
||||
},
|
||||
Self::ScheduleBroadcast(_, _) => target!("ScheduleBroadcast"),
|
||||
Self::ScheduleBroadcast(..) => target!("ScheduleBroadcast"),
|
||||
Self::ForwardToEmbedder(msg) => msg.log_target(),
|
||||
Self::InitiateNavigateRequest(_, _) => target!("InitiateNavigateRequest"),
|
||||
Self::BroadcastStorageEvent(_, _, _, _, _) => target!("BroadcastStorageEvent"),
|
||||
Self::ChangeRunningAnimationsState(_) => target!("ChangeRunningAnimationsState"),
|
||||
Self::CreateCanvasPaintThread(_, _) => target!("CreateCanvasPaintThread"),
|
||||
Self::InitiateNavigateRequest(..) => target!("InitiateNavigateRequest"),
|
||||
Self::BroadcastStorageEvent(..) => target!("BroadcastStorageEvent"),
|
||||
Self::ChangeRunningAnimationsState(..) => target!("ChangeRunningAnimationsState"),
|
||||
Self::CreateCanvasPaintThread(..) => target!("CreateCanvasPaintThread"),
|
||||
Self::Focus => target!("Focus"),
|
||||
Self::GetTopForBrowsingContext(_, _) => target!("GetTopForBrowsingContext"),
|
||||
Self::GetBrowsingContextInfo(_, _) => target!("GetBrowsingContextInfo"),
|
||||
Self::GetChildBrowsingContextId(_, _, _) => target!("GetChildBrowsingContextId"),
|
||||
Self::GetTopForBrowsingContext(..) => target!("GetTopForBrowsingContext"),
|
||||
Self::GetBrowsingContextInfo(..) => target!("GetBrowsingContextInfo"),
|
||||
Self::GetChildBrowsingContextId(..) => target!("GetChildBrowsingContextId"),
|
||||
Self::LoadComplete => target!("LoadComplete"),
|
||||
Self::LoadUrl(_, _) => target!("LoadUrl"),
|
||||
Self::LoadUrl(..) => target!("LoadUrl"),
|
||||
Self::AbortLoadUrl => target!("AbortLoadUrl"),
|
||||
Self::PostMessage { .. } => target!("PostMessage"),
|
||||
Self::NavigatedToFragment(_, _) => target!("NavigatedToFragment"),
|
||||
Self::TraverseHistory(_) => target!("TraverseHistory"),
|
||||
Self::PushHistoryState(_, _) => target!("PushHistoryState"),
|
||||
Self::ReplaceHistoryState(_, _) => target!("ReplaceHistoryState"),
|
||||
Self::JointSessionHistoryLength(_) => target!("JointSessionHistoryLength"),
|
||||
Self::RemoveIFrame(_, _) => target!("RemoveIFrame"),
|
||||
Self::SetThrottledComplete(_) => target!("SetThrottledComplete"),
|
||||
Self::ScriptLoadedURLInIFrame(_) => target!("ScriptLoadedURLInIFrame"),
|
||||
Self::ScriptNewIFrame(_) => target!("ScriptNewIFrame"),
|
||||
Self::ScriptNewAuxiliary(_) => target!("ScriptNewAuxiliary"),
|
||||
Self::NavigatedToFragment(..) => target!("NavigatedToFragment"),
|
||||
Self::TraverseHistory(..) => target!("TraverseHistory"),
|
||||
Self::PushHistoryState(..) => target!("PushHistoryState"),
|
||||
Self::ReplaceHistoryState(..) => target!("ReplaceHistoryState"),
|
||||
Self::JointSessionHistoryLength(..) => target!("JointSessionHistoryLength"),
|
||||
Self::RemoveIFrame(..) => target!("RemoveIFrame"),
|
||||
Self::SetThrottledComplete(..) => target!("SetThrottledComplete"),
|
||||
Self::ScriptLoadedURLInIFrame(..) => target!("ScriptLoadedURLInIFrame"),
|
||||
Self::ScriptNewIFrame(..) => target!("ScriptNewIFrame"),
|
||||
Self::ScriptNewAuxiliary(..) => target!("ScriptNewAuxiliary"),
|
||||
Self::ActivateDocument => target!("ActivateDocument"),
|
||||
Self::SetDocumentState(_) => target!("SetDocumentState"),
|
||||
Self::SetLayoutEpoch(_, _) => target!("SetLayoutEpoch"),
|
||||
Self::SetFinalUrl(_) => target!("SetFinalUrl"),
|
||||
Self::TouchEventProcessed(_) => target!("TouchEventProcessed"),
|
||||
Self::LogEntry(_, _) => target!("LogEntry"),
|
||||
Self::SetDocumentState(..) => target!("SetDocumentState"),
|
||||
Self::SetLayoutEpoch(..) => target!("SetLayoutEpoch"),
|
||||
Self::SetFinalUrl(..) => target!("SetFinalUrl"),
|
||||
Self::TouchEventProcessed(..) => target!("TouchEventProcessed"),
|
||||
Self::LogEntry(..) => target!("LogEntry"),
|
||||
Self::DiscardDocument => target!("DiscardDocument"),
|
||||
Self::DiscardTopLevelBrowsingContext => target!("DiscardTopLevelBrowsingContext"),
|
||||
Self::PipelineExited => target!("PipelineExited"),
|
||||
Self::ForwardDOMMessage(_, _) => target!("ForwardDOMMessage"),
|
||||
Self::ScheduleJob(_) => target!("ScheduleJob"),
|
||||
Self::GetClientWindow(_) => target!("GetClientWindow"),
|
||||
Self::GetScreenSize(_) => target!("GetScreenSize"),
|
||||
Self::GetScreenAvailSize(_) => target!("GetScreenAvailSize"),
|
||||
Self::MediaSessionEvent(_, _) => target!("MediaSessionEvent"),
|
||||
Self::RequestAdapter(_, _, _) => target!("RequestAdapter"),
|
||||
Self::GetWebGPUChan(_) => target!("GetWebGPUChan"),
|
||||
Self::TitleChanged(_, _) => target!("TitleChanged"),
|
||||
Self::ForwardDOMMessage(..) => target!("ForwardDOMMessage"),
|
||||
Self::ScheduleJob(..) => target!("ScheduleJob"),
|
||||
Self::GetClientWindow(..) => target!("GetClientWindow"),
|
||||
Self::GetScreenSize(..) => target!("GetScreenSize"),
|
||||
Self::GetScreenAvailSize(..) => target!("GetScreenAvailSize"),
|
||||
Self::MediaSessionEvent(..) => target!("MediaSessionEvent"),
|
||||
Self::RequestAdapter(..) => target!("RequestAdapter"),
|
||||
Self::GetWebGPUChan(..) => target!("GetWebGPUChan"),
|
||||
Self::TitleChanged(..) => target!("TitleChanged"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -199,43 +203,43 @@ mod from_script {
|
|||
};
|
||||
}
|
||||
match self {
|
||||
Self::Status(_) => target_variant!("Status"),
|
||||
Self::ChangePageTitle(_) => target_variant!("ChangePageTitle"),
|
||||
Self::MoveTo(_) => target_variant!("MoveTo"),
|
||||
Self::ResizeTo(_) => target_variant!("ResizeTo"),
|
||||
Self::Prompt(_, _) => target_variant!("Prompt"),
|
||||
Self::ShowContextMenu(_, _, _) => target_variant!("ShowContextMenu"),
|
||||
Self::AllowNavigationRequest(_, _) => target_variant!("AllowNavigationRequest"),
|
||||
Self::AllowOpeningWebView(_) => target_variant!("AllowOpeningWebView"),
|
||||
Self::WebViewOpened(_) => target_variant!("WebViewOpened"),
|
||||
Self::WebViewClosed(_) => target_variant!("WebViewClosed"),
|
||||
Self::WebViewFocused(_) => target_variant!("WebViewFocused"),
|
||||
Self::Status(..) => target_variant!("Status"),
|
||||
Self::ChangePageTitle(..) => target_variant!("ChangePageTitle"),
|
||||
Self::MoveTo(..) => target_variant!("MoveTo"),
|
||||
Self::ResizeTo(..) => target_variant!("ResizeTo"),
|
||||
Self::Prompt(..) => target_variant!("Prompt"),
|
||||
Self::ShowContextMenu(..) => target_variant!("ShowContextMenu"),
|
||||
Self::AllowNavigationRequest(..) => target_variant!("AllowNavigationRequest"),
|
||||
Self::AllowOpeningWebView(..) => target_variant!("AllowOpeningWebView"),
|
||||
Self::WebViewOpened(..) => target_variant!("WebViewOpened"),
|
||||
Self::WebViewClosed(..) => target_variant!("WebViewClosed"),
|
||||
Self::WebViewFocused(..) => target_variant!("WebViewFocused"),
|
||||
Self::WebViewBlurred => target_variant!("WebViewBlurred"),
|
||||
Self::AllowUnload(_) => target_variant!("AllowUnload"),
|
||||
Self::Keyboard(_) => target_variant!("Keyboard"),
|
||||
Self::GetClipboardContents(_) => target_variant!("GetClipboardContents"),
|
||||
Self::SetClipboardContents(_) => target_variant!("SetClipboardContents"),
|
||||
Self::SetCursor(_) => target_variant!("SetCursor"),
|
||||
Self::NewFavicon(_) => target_variant!("NewFavicon"),
|
||||
Self::AllowUnload(..) => target_variant!("AllowUnload"),
|
||||
Self::Keyboard(..) => target_variant!("Keyboard"),
|
||||
Self::GetClipboardContents(..) => target_variant!("GetClipboardContents"),
|
||||
Self::SetClipboardContents(..) => target_variant!("SetClipboardContents"),
|
||||
Self::SetCursor(..) => target_variant!("SetCursor"),
|
||||
Self::NewFavicon(..) => target_variant!("NewFavicon"),
|
||||
Self::HeadParsed => target_variant!("HeadParsed"),
|
||||
Self::HistoryChanged(_, _) => target_variant!("HistoryChanged"),
|
||||
Self::SetFullscreenState(_) => target_variant!("SetFullscreenState"),
|
||||
Self::HistoryChanged(..) => target_variant!("HistoryChanged"),
|
||||
Self::SetFullscreenState(..) => target_variant!("SetFullscreenState"),
|
||||
Self::LoadStart => target_variant!("LoadStart"),
|
||||
Self::LoadComplete => target_variant!("LoadComplete"),
|
||||
Self::Panic(_, _) => target_variant!("Panic"),
|
||||
Self::GetSelectedBluetoothDevice(_, _) => {
|
||||
Self::Panic(..) => target_variant!("Panic"),
|
||||
Self::GetSelectedBluetoothDevice(..) => {
|
||||
target_variant!("GetSelectedBluetoothDevice")
|
||||
},
|
||||
Self::SelectFiles(_, _, _) => target_variant!("SelectFiles"),
|
||||
Self::PromptPermission(_, _) => target_variant!("PromptPermission"),
|
||||
Self::ShowIME(_, _, _, _) => target_variant!("ShowIME"),
|
||||
Self::SelectFiles(..) => target_variant!("SelectFiles"),
|
||||
Self::PromptPermission(..) => target_variant!("PromptPermission"),
|
||||
Self::ShowIME(..) => target_variant!("ShowIME"),
|
||||
Self::HideIME => target_variant!("HideIME"),
|
||||
Self::Shutdown => target_variant!("Shutdown"),
|
||||
Self::ReportProfile(_) => target_variant!("ReportProfile"),
|
||||
Self::MediaSessionEvent(_) => target_variant!("MediaSessionEvent"),
|
||||
Self::OnDevtoolsStarted(_, _) => target_variant!("OnDevtoolsStarted"),
|
||||
Self::ReadyToPresent => target_variant!("ReadyToPresent"),
|
||||
Self::EventDelivered(_) => target_variant!("EventDelivered"),
|
||||
Self::ReportProfile(..) => target_variant!("ReportProfile"),
|
||||
Self::MediaSessionEvent(..) => target_variant!("MediaSessionEvent"),
|
||||
Self::OnDevtoolsStarted(..) => target_variant!("OnDevtoolsStarted"),
|
||||
Self::ReadyToPresent(..) => target_variant!("ReadyToPresent"),
|
||||
Self::EventDelivered(..) => target_variant!("EventDelivered"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -253,8 +257,8 @@ mod from_layout {
|
|||
impl LogTarget for script_traits::LayoutMsg {
|
||||
fn log_target(&self) -> &'static str {
|
||||
match self {
|
||||
Self::IFrameSizes(_) => target!("IFrameSizes"),
|
||||
Self::PendingPaintMetric(_, _) => target!("PendingPaintMetric"),
|
||||
Self::IFrameSizes(..) => target!("IFrameSizes"),
|
||||
Self::PendingPaintMetric(..) => target!("PendingPaintMetric"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -101,12 +101,12 @@ mod test {
|
|||
|
||||
use msg::constellation_msg::{
|
||||
BrowsingContextId, BrowsingContextIndex, PipelineNamespace, PipelineNamespaceId,
|
||||
TopLevelBrowsingContextId,
|
||||
TopLevelBrowsingContextId, WebViewId,
|
||||
};
|
||||
|
||||
use crate::webview::WebViewManager;
|
||||
|
||||
fn top_level_id(namespace_id: u32, index: u32) -> TopLevelBrowsingContextId {
|
||||
fn id(namespace_id: u32, index: u32) -> WebViewId {
|
||||
TopLevelBrowsingContextId(BrowsingContextId {
|
||||
namespace_id: PipelineNamespaceId(namespace_id),
|
||||
index: BrowsingContextIndex(NonZeroU32::new(index).expect("Incorrect test case")),
|
||||
|
@ -115,7 +115,7 @@ mod test {
|
|||
|
||||
fn webviews_sorted<WebView: Clone>(
|
||||
webviews: &WebViewManager<WebView>,
|
||||
) -> Vec<(TopLevelBrowsingContextId, WebView)> {
|
||||
) -> Vec<(WebViewId, WebView)> {
|
||||
let mut keys = webviews.webviews.keys().collect::<Vec<_>>();
|
||||
keys.sort();
|
||||
keys.iter()
|
||||
|
@ -138,59 +138,59 @@ mod test {
|
|||
let mut webviews = WebViewManager::default();
|
||||
|
||||
// add() adds the webview to the map, but does not focus it.
|
||||
webviews.add(TopLevelBrowsingContextId::new(), 'a');
|
||||
webviews.add(TopLevelBrowsingContextId::new(), 'b');
|
||||
webviews.add(TopLevelBrowsingContextId::new(), 'c');
|
||||
webviews.add(WebViewId::new(), 'a');
|
||||
webviews.add(WebViewId::new(), 'b');
|
||||
webviews.add(WebViewId::new(), 'c');
|
||||
assert_eq!(
|
||||
webviews_sorted(&webviews),
|
||||
vec![
|
||||
(top_level_id(0, 1), 'a'),
|
||||
(top_level_id(0, 2), 'b'),
|
||||
(top_level_id(0, 3), 'c'),
|
||||
]
|
||||
vec![(id(0, 1), 'a'), (id(0, 2), 'b'), (id(0, 3), 'c'),]
|
||||
);
|
||||
assert!(webviews.focus_order.is_empty());
|
||||
assert_eq!(webviews.is_focused, false);
|
||||
|
||||
// focus() makes the given webview the latest in focus order.
|
||||
webviews.focus(top_level_id(0, 2));
|
||||
assert_eq!(webviews.focus_order, vec![top_level_id(0, 2)]);
|
||||
webviews.focus(id(0, 2));
|
||||
assert_eq!(webviews.focus_order, vec![id(0, 2)]);
|
||||
assert_eq!(webviews.is_focused, true);
|
||||
webviews.focus(top_level_id(0, 1));
|
||||
assert_eq!(
|
||||
webviews.focus_order,
|
||||
vec![top_level_id(0, 2), top_level_id(0, 1)]
|
||||
);
|
||||
webviews.focus(id(0, 1));
|
||||
assert_eq!(webviews.focus_order, vec![id(0, 2), id(0, 1)]);
|
||||
assert_eq!(webviews.is_focused, true);
|
||||
webviews.focus(top_level_id(0, 3));
|
||||
assert_eq!(
|
||||
webviews.focus_order,
|
||||
vec![top_level_id(0, 2), top_level_id(0, 1), top_level_id(0, 3)]
|
||||
);
|
||||
webviews.focus(id(0, 3));
|
||||
assert_eq!(webviews.focus_order, vec![id(0, 2), id(0, 1), id(0, 3)]);
|
||||
assert_eq!(webviews.is_focused, true);
|
||||
|
||||
// unfocus() clears the “is focused” flag, but does not touch the focus order.
|
||||
webviews.unfocus();
|
||||
assert_eq!(
|
||||
webviews.focus_order,
|
||||
vec![top_level_id(0, 2), top_level_id(0, 1), top_level_id(0, 3)]
|
||||
);
|
||||
assert_eq!(webviews.focus_order, vec![id(0, 2), id(0, 1), id(0, 3)]);
|
||||
assert_eq!(webviews.is_focused, false);
|
||||
|
||||
// focus() avoids duplicates in focus order, when the given webview has been focused before.
|
||||
webviews.focus(top_level_id(0, 1));
|
||||
assert_eq!(
|
||||
webviews.focus_order,
|
||||
vec![top_level_id(0, 2), top_level_id(0, 3), top_level_id(0, 1)]
|
||||
);
|
||||
webviews.focus(id(0, 1));
|
||||
assert_eq!(webviews.focus_order, vec![id(0, 2), id(0, 3), id(0, 1)]);
|
||||
assert_eq!(webviews.is_focused, true);
|
||||
|
||||
// remove() clears the “is focused” flag iff the given webview was focused.
|
||||
webviews.remove(top_level_id(0, 2));
|
||||
webviews.remove(id(1, 1));
|
||||
assert_eq!(webviews.is_focused, true);
|
||||
webviews.remove(top_level_id(0, 1));
|
||||
webviews.remove(id(1, 2));
|
||||
assert_eq!(webviews.is_focused, true);
|
||||
webviews.remove(id(2, 1));
|
||||
assert_eq!(webviews.is_focused, true);
|
||||
webviews.remove(id(2, 2));
|
||||
assert_eq!(webviews.is_focused, true);
|
||||
webviews.remove(id(2, 3));
|
||||
assert_eq!(webviews.is_focused, true);
|
||||
webviews.remove(id(2, 4));
|
||||
assert_eq!(webviews.is_focused, true);
|
||||
webviews.remove(id(3, 1));
|
||||
assert_eq!(webviews.is_focused, true);
|
||||
webviews.remove(id(4, 1));
|
||||
assert_eq!(webviews.is_focused, true);
|
||||
webviews.remove(id(0, 2));
|
||||
assert_eq!(webviews.is_focused, true);
|
||||
webviews.remove(id(0, 1));
|
||||
assert_eq!(webviews.is_focused, false);
|
||||
webviews.remove(top_level_id(0, 3));
|
||||
webviews.remove(id(0, 3));
|
||||
assert_eq!(webviews.is_focused, false);
|
||||
|
||||
// remove() removes the given webview from both the map and the focus order.
|
||||
|
|
|
@ -30,6 +30,7 @@ use bluetooth_traits::BluetoothRequest;
|
|||
use canvas::canvas_paint_thread::{self, CanvasPaintThread};
|
||||
use canvas::WebGLComm;
|
||||
use canvas_traits::webgl::WebGLThreads;
|
||||
use compositing::webview::UnknownWebView;
|
||||
use compositing::windowing::{EmbedderEvent, EmbedderMethods, WindowMethods};
|
||||
use compositing::{CompositeTarget, IOCompositor, InitialCompositorState, ShutdownState};
|
||||
use compositing_traits::{
|
||||
|
@ -598,7 +599,7 @@ where
|
|||
self.compositor.composite();
|
||||
},
|
||||
|
||||
EmbedderEvent::Resize => {
|
||||
EmbedderEvent::WindowResize => {
|
||||
return self.compositor.on_resize_window_event();
|
||||
},
|
||||
EmbedderEvent::InvalidateNativeSurface => {
|
||||
|
@ -761,6 +762,33 @@ where
|
|||
}
|
||||
},
|
||||
|
||||
EmbedderEvent::MoveResizeWebView(webview_id, rect) => {
|
||||
self.compositor.move_resize_webview(webview_id, rect);
|
||||
},
|
||||
EmbedderEvent::ShowWebView(webview_id, hide_others) => {
|
||||
if let Err(UnknownWebView(webview_id)) =
|
||||
self.compositor.show_webview(webview_id, hide_others)
|
||||
{
|
||||
warn!("{webview_id}: ShowWebView on unknown webview id");
|
||||
}
|
||||
},
|
||||
EmbedderEvent::HideWebView(webview_id) => {
|
||||
if let Err(UnknownWebView(webview_id)) = self.compositor.hide_webview(webview_id) {
|
||||
warn!("{webview_id}: HideWebView on unknown webview id");
|
||||
}
|
||||
},
|
||||
EmbedderEvent::RaiseWebViewToTop(webview_id, hide_others) => {
|
||||
if let Err(UnknownWebView(webview_id)) = self
|
||||
.compositor
|
||||
.raise_webview_to_top(webview_id, hide_others)
|
||||
{
|
||||
warn!("{webview_id}: RaiseWebViewToTop on unknown webview id");
|
||||
}
|
||||
},
|
||||
EmbedderEvent::BlurWebView => {
|
||||
self.send_to_constellation(ConstellationMsg::BlurWebView);
|
||||
},
|
||||
|
||||
EmbedderEvent::SendError(top_level_browsing_context_id, e) => {
|
||||
let msg = ConstellationMsg::SendError(top_level_browsing_context_id, e);
|
||||
if let Err(e) = self.constellation_chan.send(msg) {
|
||||
|
@ -801,6 +829,13 @@ where
|
|||
false
|
||||
}
|
||||
|
||||
fn send_to_constellation(&self, msg: ConstellationMsg) {
|
||||
let variant_name = msg.variant_name();
|
||||
if let Err(e) = self.constellation_chan.send(msg) {
|
||||
warn!("Sending {variant_name} to constellation failed: {e:?}");
|
||||
}
|
||||
}
|
||||
|
||||
fn receive_messages(&mut self) {
|
||||
while let Some((top_level_browsing_context, msg)) =
|
||||
self.embedder_receiver.try_recv_embedder_msg()
|
||||
|
@ -882,10 +917,6 @@ where
|
|||
self.compositor.present();
|
||||
}
|
||||
|
||||
pub fn recomposite(&mut self) {
|
||||
self.compositor.composite();
|
||||
}
|
||||
|
||||
/// Return the OpenGL framebuffer name of the most-recently-completed frame when compositing to
|
||||
/// [`CompositeTarget::Fbo`], or None otherwise.
|
||||
pub fn offscreen_framebuffer_id(&self) -> Option<u32> {
|
||||
|
|
|
@ -11,13 +11,14 @@ use gfx_traits::Epoch;
|
|||
use ipc_channel::ipc::IpcSender;
|
||||
use keyboard_types::KeyboardEvent;
|
||||
use msg::constellation_msg::{
|
||||
BrowsingContextId, PipelineId, TopLevelBrowsingContextId, TraversalDirection,
|
||||
BrowsingContextId, PipelineId, TopLevelBrowsingContextId, TraversalDirection, WebViewId,
|
||||
};
|
||||
use script_traits::{
|
||||
AnimationTickType, CompositorEvent, GamepadEvent, LogEntry, MediaSessionActionType,
|
||||
WebDriverCommandMsg, WindowSizeData, WindowSizeType,
|
||||
};
|
||||
use servo_url::ServoUrl;
|
||||
use webrender_api::units::DeviceRect;
|
||||
|
||||
/// Messages to the constellation.
|
||||
pub enum ConstellationMsg {
|
||||
|
@ -60,9 +61,17 @@ pub enum ConstellationMsg {
|
|||
CloseWebView(TopLevelBrowsingContextId),
|
||||
/// Panic a top level browsing context.
|
||||
SendError(Option<TopLevelBrowsingContextId>, String),
|
||||
/// Make a top-level browsing context focused.
|
||||
/// Move and/or resize a webview to the given rect.
|
||||
MoveResizeWebView(TopLevelBrowsingContextId, DeviceRect),
|
||||
/// Start painting a webview, and optionally stop painting all others.
|
||||
ShowWebView(TopLevelBrowsingContextId, bool),
|
||||
/// Stop painting a webview.
|
||||
HideWebView(TopLevelBrowsingContextId),
|
||||
/// Start painting a webview on top of all others, and optionally stop painting all others.
|
||||
RaiseWebViewToTop(TopLevelBrowsingContextId, bool),
|
||||
/// Make a webview focused.
|
||||
FocusWebView(TopLevelBrowsingContextId),
|
||||
/// Make none of the top-level browsing contexts focused.
|
||||
/// Make none of the webviews focused.
|
||||
BlurWebView,
|
||||
/// Forward an event to the script task of the given pipeline.
|
||||
ForwardEvent(PipelineId, CompositorEvent),
|
||||
|
@ -80,16 +89,23 @@ pub enum ConstellationMsg {
|
|||
SetWebViewThrottled(TopLevelBrowsingContextId, bool),
|
||||
/// Virtual keyboard was dismissed
|
||||
IMEDismissed,
|
||||
/// Compositing done, but external code needs to present.
|
||||
ReadyToPresent(TopLevelBrowsingContextId),
|
||||
/// Notify the embedder that it needs to present a new frame.
|
||||
ReadyToPresent(Vec<WebViewId>),
|
||||
/// Gamepad state has changed
|
||||
Gamepad(GamepadEvent),
|
||||
}
|
||||
|
||||
impl fmt::Debug for ConstellationMsg {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(formatter, "ConstellationMsg::{}", self.variant_name())
|
||||
}
|
||||
}
|
||||
|
||||
impl ConstellationMsg {
|
||||
/// Return the variant name, for error logging that happens after the message is consumed.
|
||||
pub fn variant_name(&self) -> &'static str {
|
||||
use self::ConstellationMsg::*;
|
||||
let variant = match *self {
|
||||
match *self {
|
||||
Exit => "Exit",
|
||||
GetBrowsingContext(..) => "GetBrowsingContext",
|
||||
GetPipeline(..) => "GetPipeline",
|
||||
|
@ -106,6 +122,10 @@ impl fmt::Debug for ConstellationMsg {
|
|||
LogEntry(..) => "LogEntry",
|
||||
NewWebView(..) => "NewWebView",
|
||||
CloseWebView(..) => "CloseWebView",
|
||||
MoveResizeWebView(..) => "MoveResizeWebView",
|
||||
ShowWebView(..) => "ShowWebView",
|
||||
HideWebView(..) => "HideWebView",
|
||||
RaiseWebViewToTop(..) => "RaiseWebViewToTop",
|
||||
FocusWebView(..) => "FocusWebView",
|
||||
BlurWebView => "BlurWebView",
|
||||
SendError(..) => "SendError",
|
||||
|
@ -120,7 +140,6 @@ impl fmt::Debug for ConstellationMsg {
|
|||
ClearCache => "ClearCache",
|
||||
ReadyToPresent(..) => "ReadyToPresent",
|
||||
Gamepad(..) => "Gamepad",
|
||||
};
|
||||
write!(formatter, "ConstellationMsg::{}", variant)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ use script_traits::{
|
|||
ScriptToCompositorMsg,
|
||||
};
|
||||
use style_traits::CSSPixel;
|
||||
use webrender_api::units::{DeviceIntPoint, DeviceIntSize};
|
||||
use webrender_api::units::{DeviceIntPoint, DeviceIntSize, DeviceRect};
|
||||
use webrender_api::{self, FontInstanceKey, FontKey, ImageKey};
|
||||
|
||||
/// Sends messages to the compositor.
|
||||
|
@ -73,8 +73,18 @@ pub enum CompositorMsg {
|
|||
ShutdownComplete,
|
||||
/// Alerts the compositor that the given pipeline has changed whether it is running animations.
|
||||
ChangeRunningAnimationsState(PipelineId, AnimationState),
|
||||
/// Replaces the current frame tree, typically called during main frame navigation.
|
||||
SetFrameTree(SendableFrameTree),
|
||||
/// Create or update a webview, given its frame tree.
|
||||
CreateOrUpdateWebView(SendableFrameTree),
|
||||
/// Remove a webview.
|
||||
RemoveWebView(TopLevelBrowsingContextId),
|
||||
/// Move and/or resize a webview to the given rect.
|
||||
MoveResizeWebView(TopLevelBrowsingContextId, DeviceRect),
|
||||
/// Start painting a webview, and optionally stop painting all others.
|
||||
ShowWebView(TopLevelBrowsingContextId, bool),
|
||||
/// Stop painting a webview.
|
||||
HideWebView(TopLevelBrowsingContextId),
|
||||
/// Start painting a webview on top of all others, and optionally stop painting all others.
|
||||
RaiseWebViewToTop(TopLevelBrowsingContextId, bool),
|
||||
/// Script has handled a touch event, and either prevented or allowed default actions.
|
||||
TouchEventProcessed(EventResult),
|
||||
/// Composite to a PNG file and return the Image over a passed channel.
|
||||
|
@ -153,7 +163,12 @@ impl Debug for CompositorMsg {
|
|||
CompositorMsg::ChangeRunningAnimationsState(_, state) => {
|
||||
write!(f, "ChangeRunningAnimationsState({:?})", state)
|
||||
},
|
||||
CompositorMsg::SetFrameTree(..) => write!(f, "SetFrameTree"),
|
||||
CompositorMsg::CreateOrUpdateWebView(..) => write!(f, "CreateOrUpdateWebView"),
|
||||
CompositorMsg::RemoveWebView(..) => write!(f, "RemoveWebView"),
|
||||
CompositorMsg::MoveResizeWebView(..) => write!(f, "MoveResizeWebView"),
|
||||
CompositorMsg::ShowWebView(..) => write!(f, "ShowWebView"),
|
||||
CompositorMsg::HideWebView(..) => write!(f, "HideWebView"),
|
||||
CompositorMsg::RaiseWebViewToTop(..) => write!(f, "RaiseWebViewToTop"),
|
||||
CompositorMsg::TouchEventProcessed(..) => write!(f, "TouchEventProcessed"),
|
||||
CompositorMsg::CreatePng(..) => write!(f, "CreatePng"),
|
||||
CompositorMsg::IsReadyToSaveImageReply(..) => write!(f, "IsReadyToSaveImageReply"),
|
||||
|
|
|
@ -10,7 +10,7 @@ use crossbeam_channel::{Receiver, Sender};
|
|||
use ipc_channel::ipc::IpcSender;
|
||||
use keyboard_types::KeyboardEvent;
|
||||
use log::warn;
|
||||
use msg::constellation_msg::{InputMethodType, PipelineId, TopLevelBrowsingContextId};
|
||||
use msg::constellation_msg::{InputMethodType, PipelineId, TopLevelBrowsingContextId, WebViewId};
|
||||
use num_derive::FromPrimitive;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use servo_url::ServoUrl;
|
||||
|
@ -156,13 +156,13 @@ pub enum EmbedderMsg {
|
|||
AllowNavigationRequest(PipelineId, ServoUrl),
|
||||
/// Whether or not to allow script to open a new tab/browser
|
||||
AllowOpeningWebView(IpcSender<bool>),
|
||||
/// A browser was created
|
||||
/// A webview was created.
|
||||
WebViewOpened(TopLevelBrowsingContextId),
|
||||
/// A browser was destroyed
|
||||
/// A webview was destroyed.
|
||||
WebViewClosed(TopLevelBrowsingContextId),
|
||||
/// A browser gained focus for keyboard events
|
||||
/// A webview gained focus for keyboard events.
|
||||
WebViewFocused(TopLevelBrowsingContextId),
|
||||
/// All browsers lost focus for keyboard events
|
||||
/// All webviews lost focus for keyboard events.
|
||||
WebViewBlurred,
|
||||
/// Wether or not to unload a document
|
||||
AllowUnload(IpcSender<bool>),
|
||||
|
@ -210,8 +210,8 @@ pub enum EmbedderMsg {
|
|||
MediaSessionEvent(MediaSessionEvent),
|
||||
/// Report the status of Devtools Server with a token that can be used to bypass the permission prompt.
|
||||
OnDevtoolsStarted(Result<u16, ()>, String),
|
||||
/// Compositing done, but external code needs to present.
|
||||
ReadyToPresent,
|
||||
/// Notify the embedder that it needs to present a new frame.
|
||||
ReadyToPresent(Vec<WebViewId>),
|
||||
/// The given event was delivered to a pipeline in the given browser.
|
||||
EventDelivered(CompositorEventVariant),
|
||||
}
|
||||
|
@ -261,12 +261,12 @@ impl Debug for EmbedderMsg {
|
|||
EmbedderMsg::WebViewOpened(..) => write!(f, "WebViewOpened"),
|
||||
EmbedderMsg::WebViewClosed(..) => write!(f, "WebViewClosed"),
|
||||
EmbedderMsg::WebViewFocused(..) => write!(f, "WebViewFocused"),
|
||||
EmbedderMsg::WebViewBlurred => write!(f, "WebViewUnfocused"),
|
||||
EmbedderMsg::WebViewBlurred => write!(f, "WebViewBlurred"),
|
||||
EmbedderMsg::ReportProfile(..) => write!(f, "ReportProfile"),
|
||||
EmbedderMsg::MediaSessionEvent(..) => write!(f, "MediaSessionEvent"),
|
||||
EmbedderMsg::OnDevtoolsStarted(..) => write!(f, "OnDevtoolsStarted"),
|
||||
EmbedderMsg::ShowContextMenu(..) => write!(f, "ShowContextMenu"),
|
||||
EmbedderMsg::ReadyToPresent => write!(f, "ReadyToPresent"),
|
||||
EmbedderMsg::ReadyToPresent(..) => write!(f, "ReadyToPresent"),
|
||||
EmbedderMsg::EventDelivered(..) => write!(f, "HitTestedEvent"),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -435,7 +435,7 @@ impl ServoGlue {
|
|||
pub fn resize(&mut self, coordinates: Coordinates) -> Result<(), &'static str> {
|
||||
info!("resize");
|
||||
*self.callbacks.coordinates.borrow_mut() = coordinates;
|
||||
self.process_event(EmbedderEvent::Resize)
|
||||
self.process_event(EmbedderEvent::WindowResize)
|
||||
}
|
||||
|
||||
/// Start scrolling.
|
||||
|
@ -818,7 +818,7 @@ impl ServoGlue {
|
|||
EmbedderMsg::Panic(reason, backtrace) => {
|
||||
self.callbacks.host_callbacks.on_panic(reason, backtrace);
|
||||
},
|
||||
EmbedderMsg::ReadyToPresent => {
|
||||
EmbedderMsg::ReadyToPresent(_webview_ids) => {
|
||||
need_present = true;
|
||||
},
|
||||
EmbedderMsg::Status(..) |
|
||||
|
|
|
@ -124,17 +124,15 @@ impl App {
|
|||
|
||||
if let Some(mut minibrowser) = app.minibrowser() {
|
||||
// Servo is not yet initialised, so there is no `servo_framebuffer_id`.
|
||||
minibrowser.update(window.winit_window().unwrap(), None, "init");
|
||||
minibrowser.update(
|
||||
window.winit_window().unwrap(),
|
||||
&mut app.webviews.borrow_mut(),
|
||||
None,
|
||||
"init",
|
||||
);
|
||||
window.set_toolbar_height(minibrowser.toolbar_height);
|
||||
}
|
||||
|
||||
// Whether or not to recomposite during the next RedrawRequested event.
|
||||
// Normally this is true, including for RedrawRequested events that come from the platform
|
||||
// (e.g. X11 without picom or similar) when an offscreen or obscured window becomes visible.
|
||||
// If we are calling request_redraw in response to the compositor having painted to this
|
||||
// frame, set this to false, so we can avoid an unnecessary recomposite.
|
||||
let mut need_recomposite = true;
|
||||
|
||||
let t_start = Instant::now();
|
||||
let mut t = t_start;
|
||||
let ev_waker = events_loop.create_event_loop_waker();
|
||||
|
@ -208,22 +206,17 @@ impl App {
|
|||
|
||||
// WARNING: do not defer painting or presenting to some later tick of the event
|
||||
// loop or servoshell may become unresponsive! (servo#30312)
|
||||
if need_recomposite {
|
||||
trace!("need_recomposite");
|
||||
app.servo.as_mut().unwrap().recomposite();
|
||||
}
|
||||
if let Some(mut minibrowser) = app.minibrowser() {
|
||||
minibrowser.update(
|
||||
window.winit_window().unwrap(),
|
||||
&mut app.webviews.borrow_mut(),
|
||||
app.servo.as_ref().unwrap().offscreen_framebuffer_id(),
|
||||
"RedrawRequested",
|
||||
);
|
||||
minibrowser.paint(window.winit_window().unwrap());
|
||||
}
|
||||
app.servo.as_mut().unwrap().present();
|
||||
|
||||
// By default, the next RedrawRequested event will need to recomposite.
|
||||
need_recomposite = true;
|
||||
app.servo.as_mut().unwrap().present();
|
||||
}
|
||||
|
||||
// Handle the event
|
||||
|
@ -303,6 +296,7 @@ impl App {
|
|||
// redraw, doing so would delay the location update by two frames.
|
||||
minibrowser.update(
|
||||
window.winit_window().unwrap(),
|
||||
webviews,
|
||||
app.servo.as_ref().unwrap().offscreen_framebuffer_id(),
|
||||
"update_location_in_toolbar",
|
||||
);
|
||||
|
@ -314,13 +308,13 @@ impl App {
|
|||
// The window was resized.
|
||||
trace!("PumpResult::Present::Immediate");
|
||||
|
||||
// Resizes are unusual in that we need to repaint synchronously.
|
||||
// TODO(servo#30049) can we replace this with the simpler Servo::recomposite?
|
||||
app.servo.as_mut().unwrap().repaint_synchronously();
|
||||
|
||||
// If we had resized any of the viewports in response to this, we would need to
|
||||
// call Servo::repaint_synchronously. At the moment we don’t, so there won’t be
|
||||
// any paint scheduled, and calling it would hang the compositor forever.
|
||||
if let Some(mut minibrowser) = app.minibrowser() {
|
||||
minibrowser.update(
|
||||
window.winit_window().unwrap(),
|
||||
&mut app.webviews.borrow_mut(),
|
||||
app.servo.as_ref().unwrap().offscreen_framebuffer_id(),
|
||||
"PumpResult::Present::Immediate",
|
||||
);
|
||||
|
@ -339,10 +333,6 @@ impl App {
|
|||
} else {
|
||||
app.servo.as_mut().unwrap().present();
|
||||
}
|
||||
|
||||
// We don’t need the compositor to paint to this frame during the redraw event.
|
||||
// TODO(servo#30331) broken on macOS?
|
||||
// need_recomposite = false;
|
||||
},
|
||||
Present::None => {},
|
||||
}
|
||||
|
|
|
@ -8,7 +8,6 @@ use std::cell::{Cell, RefCell};
|
|||
use std::collections::HashMap;
|
||||
use std::rc::Rc;
|
||||
|
||||
use euclid::num::Zero;
|
||||
use euclid::{Angle, Length, Point2D, Rotation3D, Scale, Size2D, UnknownUnit, Vector2D, Vector3D};
|
||||
use log::{debug, info, trace};
|
||||
use raw_window_handle::{HasRawDisplayHandle, HasRawWindowHandle};
|
||||
|
@ -309,8 +308,11 @@ impl WindowPortsMethods for Window {
|
|||
}
|
||||
|
||||
fn set_inner_size(&self, size: DeviceIntSize) {
|
||||
let toolbar_height = self.toolbar_height() * self.hidpi_factor();
|
||||
let toolbar_height = toolbar_height.get().ceil() as i32;
|
||||
let total_size = PhysicalSize::new(size.width, size.height + toolbar_height);
|
||||
self.winit_window
|
||||
.set_inner_size::<PhysicalSize<i32>>(PhysicalSize::new(size.width, size.height))
|
||||
.set_inner_size::<PhysicalSize<i32>>(total_size)
|
||||
}
|
||||
|
||||
fn set_position(&self, point: DeviceIntPoint) {
|
||||
|
@ -399,9 +401,7 @@ impl WindowPortsMethods for Window {
|
|||
}
|
||||
},
|
||||
winit::event::WindowEvent::CursorMoved { position, .. } => {
|
||||
let toolbar_height = self.toolbar_height.get() * self.hidpi_factor();
|
||||
let mut position = winit_position_to_euclid_point(position).to_f32();
|
||||
position -= Size2D::from_lengths(Length::zero(), toolbar_height);
|
||||
let position = winit_position_to_euclid_point(position);
|
||||
self.mouse_pos.set(position.to_i32());
|
||||
self.event_queue
|
||||
.borrow_mut()
|
||||
|
@ -476,7 +476,9 @@ impl WindowPortsMethods for Window {
|
|||
.resize(physical_size.to_i32())
|
||||
.expect("Failed to resize");
|
||||
self.inner_size.set(new_size);
|
||||
self.event_queue.borrow_mut().push(EmbedderEvent::Resize);
|
||||
self.event_queue
|
||||
.borrow_mut()
|
||||
.push(EmbedderEvent::WindowResize);
|
||||
}
|
||||
},
|
||||
_ => {},
|
||||
|
@ -510,6 +512,10 @@ impl WindowPortsMethods for Window {
|
|||
Some(&self.winit_window)
|
||||
}
|
||||
|
||||
fn toolbar_height(&self) -> Length<f32, DeviceIndependentPixel> {
|
||||
self.toolbar_height.get()
|
||||
}
|
||||
|
||||
fn set_toolbar_height(&self, height: Length<f32, DeviceIndependentPixel>) {
|
||||
self.toolbar_height.set(height);
|
||||
}
|
||||
|
@ -520,13 +526,8 @@ impl WindowMethods for Window {
|
|||
let window_size = winit_size_to_euclid_size(self.winit_window.outer_size()).to_i32();
|
||||
let window_origin = self.winit_window.outer_position().unwrap_or_default();
|
||||
let window_origin = winit_position_to_euclid_point(window_origin).to_i32();
|
||||
let inner_size = winit_size_to_euclid_size(self.winit_window.inner_size()).to_f32();
|
||||
|
||||
// Subtract the minibrowser toolbar height if any
|
||||
let toolbar_height = self.toolbar_height.get() * self.hidpi_factor();
|
||||
let viewport_size = inner_size - Size2D::from_lengths(Length::zero(), toolbar_height);
|
||||
|
||||
let viewport_origin = DeviceIntPoint::zero(); // bottom left
|
||||
let viewport_size = winit_size_to_euclid_size(self.winit_window.inner_size()).to_f32();
|
||||
let viewport = DeviceIntRect::from_origin_and_size(viewport_origin, viewport_size.to_i32());
|
||||
let screen = self.screen_size.to_i32();
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ use std::cell::Cell;
|
|||
use std::rc::Rc;
|
||||
use std::sync::RwLock;
|
||||
|
||||
use euclid::num::Zero;
|
||||
use euclid::{Length, Point2D, Rotation3D, Scale, Size2D, UnknownUnit, Vector3D};
|
||||
use log::warn;
|
||||
use servo::compositing::windowing::{
|
||||
|
@ -93,7 +94,7 @@ impl WindowPortsMethods for Window {
|
|||
Ok(()) => {
|
||||
self.inner_size.set(new_size);
|
||||
if let Ok(ref mut queue) = self.event_queue.write() {
|
||||
queue.push(EmbedderEvent::Resize);
|
||||
queue.push(EmbedderEvent::WindowResize);
|
||||
}
|
||||
},
|
||||
Err(error) => warn!("Could not resize window: {error:?}"),
|
||||
|
@ -148,6 +149,10 @@ impl WindowPortsMethods for Window {
|
|||
None
|
||||
}
|
||||
|
||||
fn toolbar_height(&self) -> Length<f32, DeviceIndependentPixel> {
|
||||
Length::zero()
|
||||
}
|
||||
|
||||
fn set_toolbar_height(&self, _height: Length<f32, DeviceIndependentPixel>) {
|
||||
unimplemented!("headless Window only")
|
||||
}
|
||||
|
|
|
@ -7,10 +7,13 @@ use std::num::NonZeroU32;
|
|||
use std::sync::Arc;
|
||||
use std::time::Instant;
|
||||
|
||||
use egui::{CentralPanel, Color32, Frame, Key, Modifiers, PaintCallback, Spinner, TopBottomPanel};
|
||||
use egui::{
|
||||
CentralPanel, Color32, Frame, Key, Modifiers, PaintCallback, Pos2, Spinner, TopBottomPanel,
|
||||
Vec2,
|
||||
};
|
||||
use egui_glow::CallbackFn;
|
||||
use egui_winit::EventResponse;
|
||||
use euclid::{Length, Point2D, Scale};
|
||||
use euclid::{Box2D, Length, Point2D, Scale, Size2D};
|
||||
use gleam::gl;
|
||||
use glow::NativeFramebuffer;
|
||||
use log::{trace, warn};
|
||||
|
@ -19,6 +22,7 @@ use servo::msg::constellation_msg::TraversalDirection;
|
|||
use servo::rendering_context::RenderingContext;
|
||||
use servo::servo_geometry::DeviceIndependentPixel;
|
||||
use servo::servo_url::ServoUrl;
|
||||
use servo::style_traits::DevicePixel;
|
||||
|
||||
use crate::egui_glue::EguiGlow;
|
||||
use crate::events_loop::EventsLoop;
|
||||
|
@ -124,6 +128,7 @@ impl Minibrowser {
|
|||
pub fn update(
|
||||
&mut self,
|
||||
window: &winit::window::Window,
|
||||
webviews: &mut WebViewManager<dyn WindowPortsMethods>,
|
||||
servo_framebuffer_id: Option<gl::GLuint>,
|
||||
reason: &'static str,
|
||||
) {
|
||||
|
@ -203,9 +208,32 @@ impl Minibrowser {
|
|||
// point, but the Context is correct and the TopBottomPanel is wrong.
|
||||
*toolbar_height = Length::new(ctx.available_rect().min.y);
|
||||
|
||||
let scale =
|
||||
Scale::<_, DeviceIndependentPixel, DevicePixel>::new(ctx.pixels_per_point());
|
||||
let Some(focused_webview_id) = webviews.focused_webview_id() else {
|
||||
return;
|
||||
};
|
||||
let Some(webview) = webviews.get_mut(focused_webview_id) else {
|
||||
return;
|
||||
};
|
||||
let mut embedder_events = vec![];
|
||||
CentralPanel::default()
|
||||
.frame(Frame::none())
|
||||
.show(ctx, |ui| {
|
||||
let Pos2 { x, y } = ui.cursor().min;
|
||||
let Vec2 {
|
||||
x: width,
|
||||
y: height,
|
||||
} = ui.available_size();
|
||||
let rect = Box2D::from_origin_and_size(
|
||||
Point2D::new(x, y),
|
||||
Size2D::new(width, height),
|
||||
) * scale;
|
||||
if rect != webview.rect {
|
||||
webview.rect = rect;
|
||||
embedder_events
|
||||
.push(EmbedderEvent::MoveResizeWebView(focused_webview_id, rect));
|
||||
}
|
||||
let min = ui.cursor().min;
|
||||
let size = ui.available_size();
|
||||
let rect = egui::Rect::from_min_size(min, size);
|
||||
|
@ -255,6 +283,10 @@ impl Minibrowser {
|
|||
});
|
||||
});
|
||||
|
||||
if !embedder_events.is_empty() {
|
||||
webviews.handle_window_events(embedder_events);
|
||||
}
|
||||
|
||||
*last_update = now;
|
||||
});
|
||||
}
|
||||
|
|
|
@ -81,7 +81,7 @@ mod from_winit {
|
|||
Self::Suspended => target!("Suspended"),
|
||||
Self::Resumed => target!("Resumed"),
|
||||
Self::MainEventsCleared => target!("MainEventsCleared"),
|
||||
Self::RedrawRequested(_) => target!("RedrawRequested"),
|
||||
Self::RedrawRequested(..) => target!("RedrawRequested"),
|
||||
Self::RedrawEventsCleared => target!("RedrawEventsCleared"),
|
||||
Self::LoopDestroyed => target!("LoopDestroyed"),
|
||||
}
|
||||
|
@ -96,18 +96,18 @@ mod from_winit {
|
|||
};
|
||||
}
|
||||
match self {
|
||||
Self::Resized(_) => target_variant!("Resized"),
|
||||
Self::Moved(_) => target_variant!("Moved"),
|
||||
Self::Resized(..) => target_variant!("Resized"),
|
||||
Self::Moved(..) => target_variant!("Moved"),
|
||||
Self::CloseRequested => target_variant!("CloseRequested"),
|
||||
Self::Destroyed => target_variant!("Destroyed"),
|
||||
Self::DroppedFile(_) => target_variant!("DroppedFile"),
|
||||
Self::HoveredFile(_) => target_variant!("HoveredFile"),
|
||||
Self::DroppedFile(..) => target_variant!("DroppedFile"),
|
||||
Self::HoveredFile(..) => target_variant!("HoveredFile"),
|
||||
Self::HoveredFileCancelled => target_variant!("HoveredFileCancelled"),
|
||||
Self::ReceivedCharacter(_) => target_variant!("ReceivedCharacter"),
|
||||
Self::Focused(_) => target_variant!("Focused"),
|
||||
Self::ReceivedCharacter(..) => target_variant!("ReceivedCharacter"),
|
||||
Self::Focused(..) => target_variant!("Focused"),
|
||||
Self::KeyboardInput { .. } => target_variant!("KeyboardInput"),
|
||||
Self::ModifiersChanged(_) => target_variant!("ModifiersChanged"),
|
||||
Self::Ime(_) => target_variant!("Ime"),
|
||||
Self::ModifiersChanged(..) => target_variant!("ModifiersChanged"),
|
||||
Self::Ime(..) => target_variant!("Ime"),
|
||||
Self::CursorMoved { .. } => target_variant!("CursorMoved"),
|
||||
Self::CursorEntered { .. } => target_variant!("CursorEntered"),
|
||||
Self::CursorLeft { .. } => target_variant!("CursorLeft"),
|
||||
|
@ -118,10 +118,10 @@ mod from_winit {
|
|||
Self::TouchpadRotate { .. } => target_variant!("TouchpadRotate"),
|
||||
Self::TouchpadPressure { .. } => target_variant!("TouchpadPressure"),
|
||||
Self::AxisMotion { .. } => target_variant!("AxisMotion"),
|
||||
Self::Touch(_) => target_variant!("Touch"),
|
||||
Self::Touch(..) => target_variant!("Touch"),
|
||||
Self::ScaleFactorChanged { .. } => target_variant!("ScaleFactorChanged"),
|
||||
Self::ThemeChanged(_) => target_variant!("ThemeChanged"),
|
||||
Self::Occluded(_) => target_variant!("Occluded"),
|
||||
Self::ThemeChanged(..) => target_variant!("ThemeChanged"),
|
||||
Self::Occluded(..) => target_variant!("Occluded"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -139,41 +139,41 @@ mod from_servo {
|
|||
impl LogTarget for servo::embedder_traits::EmbedderMsg {
|
||||
fn log_target(&self) -> &'static str {
|
||||
match self {
|
||||
Self::Status(_) => target!("Status"),
|
||||
Self::ChangePageTitle(_) => target!("ChangePageTitle"),
|
||||
Self::MoveTo(_) => target!("MoveTo"),
|
||||
Self::ResizeTo(_) => target!("ResizeTo"),
|
||||
Self::Prompt(_, _) => target!("Prompt"),
|
||||
Self::ShowContextMenu(_, _, _) => target!("ShowContextMenu"),
|
||||
Self::AllowNavigationRequest(_, _) => target!("AllowNavigationRequest"),
|
||||
Self::AllowOpeningWebView(_) => target!("AllowOpeningWebView"),
|
||||
Self::WebViewOpened(_) => target!("WebViewOpened"),
|
||||
Self::WebViewClosed(_) => target!("WebViewClosed"),
|
||||
Self::WebViewFocused(_) => target!("WebViewFocused"),
|
||||
Self::Status(..) => target!("Status"),
|
||||
Self::ChangePageTitle(..) => target!("ChangePageTitle"),
|
||||
Self::MoveTo(..) => target!("MoveTo"),
|
||||
Self::ResizeTo(..) => target!("ResizeTo"),
|
||||
Self::Prompt(..) => target!("Prompt"),
|
||||
Self::ShowContextMenu(..) => target!("ShowContextMenu"),
|
||||
Self::AllowNavigationRequest(..) => target!("AllowNavigationRequest"),
|
||||
Self::AllowOpeningWebView(..) => target!("AllowOpeningWebView"),
|
||||
Self::WebViewOpened(..) => target!("WebViewOpened"),
|
||||
Self::WebViewClosed(..) => target!("WebViewClosed"),
|
||||
Self::WebViewFocused(..) => target!("WebViewFocused"),
|
||||
Self::WebViewBlurred => target!("WebViewBlurred"),
|
||||
Self::AllowUnload(_) => target!("AllowUnload"),
|
||||
Self::Keyboard(_) => target!("Keyboard"),
|
||||
Self::GetClipboardContents(_) => target!("GetClipboardContents"),
|
||||
Self::SetClipboardContents(_) => target!("SetClipboardContents"),
|
||||
Self::SetCursor(_) => target!("SetCursor"),
|
||||
Self::NewFavicon(_) => target!("NewFavicon"),
|
||||
Self::AllowUnload(..) => target!("AllowUnload"),
|
||||
Self::Keyboard(..) => target!("Keyboard"),
|
||||
Self::GetClipboardContents(..) => target!("GetClipboardContents"),
|
||||
Self::SetClipboardContents(..) => target!("SetClipboardContents"),
|
||||
Self::SetCursor(..) => target!("SetCursor"),
|
||||
Self::NewFavicon(..) => target!("NewFavicon"),
|
||||
Self::HeadParsed => target!("HeadParsed"),
|
||||
Self::HistoryChanged(_, _) => target!("HistoryChanged"),
|
||||
Self::SetFullscreenState(_) => target!("SetFullscreenState"),
|
||||
Self::HistoryChanged(..) => target!("HistoryChanged"),
|
||||
Self::SetFullscreenState(..) => target!("SetFullscreenState"),
|
||||
Self::LoadStart => target!("LoadStart"),
|
||||
Self::LoadComplete => target!("LoadComplete"),
|
||||
Self::Panic(_, _) => target!("Panic"),
|
||||
Self::GetSelectedBluetoothDevice(_, _) => target!("GetSelectedBluetoothDevice"),
|
||||
Self::SelectFiles(_, _, _) => target!("SelectFiles"),
|
||||
Self::PromptPermission(_, _) => target!("PromptPermission"),
|
||||
Self::ShowIME(_, _, _, _) => target!("ShowIME"),
|
||||
Self::Panic(..) => target!("Panic"),
|
||||
Self::GetSelectedBluetoothDevice(..) => target!("GetSelectedBluetoothDevice"),
|
||||
Self::SelectFiles(..) => target!("SelectFiles"),
|
||||
Self::PromptPermission(..) => target!("PromptPermission"),
|
||||
Self::ShowIME(..) => target!("ShowIME"),
|
||||
Self::HideIME => target!("HideIME"),
|
||||
Self::Shutdown => target!("Shutdown"),
|
||||
Self::ReportProfile(_) => target!("ReportProfile"),
|
||||
Self::MediaSessionEvent(_) => target!("MediaSessionEvent"),
|
||||
Self::OnDevtoolsStarted(_, _) => target!("OnDevtoolsStarted"),
|
||||
Self::ReadyToPresent => target!("ReadyToPresent"),
|
||||
Self::EventDelivered(_) => target!("EventDelivered"),
|
||||
Self::ReportProfile(..) => target!("ReportProfile"),
|
||||
Self::MediaSessionEvent(..) => target!("MediaSessionEvent"),
|
||||
Self::OnDevtoolsStarted(..) => target!("OnDevtoolsStarted"),
|
||||
Self::ReadyToPresent(..) => target!("ReadyToPresent"),
|
||||
Self::EventDelivered(..) => target!("EventDelivered"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -193,36 +193,41 @@ mod to_servo {
|
|||
match self {
|
||||
Self::Idle => target!("Idle"),
|
||||
Self::Refresh => target!("Refresh"),
|
||||
Self::Resize => target!("Resize"),
|
||||
Self::AllowNavigationResponse(_, _) => target!("AllowNavigationResponse"),
|
||||
Self::LoadUrl(_, _) => target!("LoadUrl"),
|
||||
Self::MouseWindowEventClass(_) => target!("MouseWindowEventClass"),
|
||||
Self::MouseWindowMoveEventClass(_) => target!("MouseWindowMoveEventClass"),
|
||||
Self::Touch(_, _, _) => target!("Touch"),
|
||||
Self::Wheel(_, _) => target!("Wheel"),
|
||||
Self::Scroll(_, _, _) => target!("Scroll"),
|
||||
Self::Zoom(_) => target!("Zoom"),
|
||||
Self::PinchZoom(_) => target!("PinchZoom"),
|
||||
Self::WindowResize => target!("WindowResize"),
|
||||
Self::AllowNavigationResponse(..) => target!("AllowNavigationResponse"),
|
||||
Self::LoadUrl(..) => target!("LoadUrl"),
|
||||
Self::MouseWindowEventClass(..) => target!("MouseWindowEventClass"),
|
||||
Self::MouseWindowMoveEventClass(..) => target!("MouseWindowMoveEventClass"),
|
||||
Self::Touch(..) => target!("Touch"),
|
||||
Self::Wheel(..) => target!("Wheel"),
|
||||
Self::Scroll(..) => target!("Scroll"),
|
||||
Self::Zoom(..) => target!("Zoom"),
|
||||
Self::PinchZoom(..) => target!("PinchZoom"),
|
||||
Self::ResetZoom => target!("ResetZoom"),
|
||||
Self::Navigation(_, _) => target!("Navigation"),
|
||||
Self::Navigation(..) => target!("Navigation"),
|
||||
Self::Quit => target!("Quit"),
|
||||
Self::ExitFullScreen(_) => target!("ExitFullScreen"),
|
||||
Self::Keyboard(_) => target!("Keyboard"),
|
||||
Self::Reload(_) => target!("Reload"),
|
||||
Self::NewWebView(_, _) => target!("NewWebView"),
|
||||
Self::CloseWebView(_) => target!("CloseWebView"),
|
||||
Self::SendError(_, _) => target!("SendError"),
|
||||
Self::FocusWebView(_) => target!("FocusWebView"),
|
||||
Self::ToggleWebRenderDebug(_) => target!("ToggleWebRenderDebug"),
|
||||
Self::ExitFullScreen(..) => target!("ExitFullScreen"),
|
||||
Self::Keyboard(..) => target!("Keyboard"),
|
||||
Self::Reload(..) => target!("Reload"),
|
||||
Self::NewWebView(..) => target!("NewWebView"),
|
||||
Self::CloseWebView(..) => target!("CloseWebView"),
|
||||
Self::SendError(..) => target!("SendError"),
|
||||
Self::MoveResizeWebView(..) => target!("MoveResizeWebView"),
|
||||
Self::ShowWebView(..) => target!("ShowWebView"),
|
||||
Self::HideWebView(..) => target!("HideWebView"),
|
||||
Self::RaiseWebViewToTop(..) => target!("RaiseWebViewToTop"),
|
||||
Self::FocusWebView(..) => target!("FocusWebView"),
|
||||
Self::BlurWebView => target!("BlurWebView"),
|
||||
Self::ToggleWebRenderDebug(..) => target!("ToggleWebRenderDebug"),
|
||||
Self::CaptureWebRender => target!("CaptureWebRender"),
|
||||
Self::ClearCache => target!("ClearCache"),
|
||||
Self::ToggleSamplingProfiler(_, _) => target!("ToggleSamplingProfiler"),
|
||||
Self::MediaSessionAction(_) => target!("MediaSessionAction"),
|
||||
Self::SetWebViewThrottled(_, _) => target!("SetWebViewThrottled"),
|
||||
Self::ToggleSamplingProfiler(..) => target!("ToggleSamplingProfiler"),
|
||||
Self::MediaSessionAction(..) => target!("MediaSessionAction"),
|
||||
Self::SetWebViewThrottled(..) => target!("SetWebViewThrottled"),
|
||||
Self::IMEDismissed => target!("IMEDismissed"),
|
||||
Self::InvalidateNativeSurface => target!("InvalidateNativeSurface"),
|
||||
Self::ReplaceNativeSurface(_, _) => target!("ReplaceNativeSurface"),
|
||||
Self::Gamepad(_) => target!("Gamepad"),
|
||||
Self::ReplaceNativeSurface(..) => target!("ReplaceNativeSurface"),
|
||||
Self::Gamepad(..) => target!("Gamepad"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ use servo::script_traits::{
|
|||
};
|
||||
use servo::servo_config::opts;
|
||||
use servo::servo_url::ServoUrl;
|
||||
use servo::webrender_api::units::DeviceRect;
|
||||
use servo::webrender_api::ScrollLocation;
|
||||
use tinyfiledialogs::{self, MessageBoxIcon, OkCancel, YesNo};
|
||||
|
||||
|
@ -60,7 +61,9 @@ pub struct WebViewManager<Window: WindowPortsMethods + ?Sized> {
|
|||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct WebView {}
|
||||
pub struct WebView {
|
||||
pub rect: DeviceRect,
|
||||
}
|
||||
|
||||
pub struct ServoEventResponse {
|
||||
pub need_present: bool,
|
||||
|
@ -111,6 +114,14 @@ where
|
|||
self.focused_webview_id
|
||||
}
|
||||
|
||||
pub fn get_mut(&mut self, webview_id: WebViewId) -> Option<&mut WebView> {
|
||||
self.webviews.get_mut(&webview_id)
|
||||
}
|
||||
|
||||
pub fn focused_webview_id(&self) -> Option<WebViewId> {
|
||||
self.focused_webview_id.clone()
|
||||
}
|
||||
|
||||
pub fn current_url_string(&self) -> Option<&str> {
|
||||
self.current_url_string.as_deref()
|
||||
}
|
||||
|
@ -453,6 +464,20 @@ where
|
|||
self.window.set_position(point);
|
||||
},
|
||||
EmbedderMsg::ResizeTo(size) => {
|
||||
if let Some(webview_id) = webview_id {
|
||||
let new_rect = self.get_mut(webview_id).and_then(|webview| {
|
||||
if webview.rect.size() != size.to_f32() {
|
||||
webview.rect.set_size(size.to_f32());
|
||||
Some(webview.rect)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
if let Some(new_rect) = new_rect {
|
||||
self.event_queue
|
||||
.push(EmbedderEvent::MoveResizeWebView(webview_id, new_rect));
|
||||
}
|
||||
}
|
||||
self.window.set_inner_size(size);
|
||||
},
|
||||
EmbedderMsg::Prompt(definition, origin) => {
|
||||
|
@ -555,10 +580,22 @@ where
|
|||
};
|
||||
},
|
||||
EmbedderMsg::WebViewOpened(new_webview_id) => {
|
||||
self.webviews.insert(new_webview_id, WebView {});
|
||||
let scale = self.window.hidpi_factor().get();
|
||||
let toolbar = self.window.toolbar_height().get();
|
||||
|
||||
// Adjust for our toolbar height.
|
||||
// TODO: Adjust for egui window decorations if we end up using those
|
||||
let mut rect = self.window.get_coordinates().get_viewport().to_f32();
|
||||
rect.min.y += toolbar * scale;
|
||||
|
||||
self.webviews.insert(new_webview_id, WebView { rect });
|
||||
self.creation_order.push(new_webview_id);
|
||||
self.event_queue
|
||||
.push(EmbedderEvent::FocusWebView(new_webview_id));
|
||||
self.event_queue
|
||||
.push(EmbedderEvent::MoveResizeWebView(new_webview_id, rect));
|
||||
self.event_queue
|
||||
.push(EmbedderEvent::RaiseWebViewToTop(new_webview_id, true));
|
||||
},
|
||||
EmbedderMsg::WebViewClosed(webview_id) => {
|
||||
self.webviews.retain(|&id, _| id != webview_id);
|
||||
|
@ -573,6 +610,10 @@ where
|
|||
},
|
||||
EmbedderMsg::WebViewFocused(webview_id) => {
|
||||
self.focused_webview_id = Some(webview_id);
|
||||
// Show the most recently created webview and hide all others.
|
||||
// TODO: Stop doing this once we have full multiple webviews support
|
||||
self.event_queue
|
||||
.push(EmbedderEvent::ShowWebView(webview_id, true));
|
||||
},
|
||||
EmbedderMsg::WebViewBlurred => {
|
||||
self.focused_webview_id = None;
|
||||
|
@ -681,15 +722,18 @@ where
|
|||
EmbedderMsg::ShowContextMenu(sender, ..) => {
|
||||
let _ = sender.send(ContextMenuResult::Ignored);
|
||||
},
|
||||
EmbedderMsg::ReadyToPresent => {
|
||||
EmbedderMsg::ReadyToPresent(_webview_ids) => {
|
||||
need_present = true;
|
||||
},
|
||||
EmbedderMsg::EventDelivered(event) => {
|
||||
if let (Some(webview_id), CompositorEventVariant::MouseButtonEvent) =
|
||||
(webview_id, event)
|
||||
{
|
||||
// TODO Focus webview and/or raise to top if needed.
|
||||
trace!("{}: Got a mouse button event", webview_id);
|
||||
self.event_queue
|
||||
.push(EmbedderEvent::RaiseWebViewToTop(webview_id, true));
|
||||
self.event_queue
|
||||
.push(EmbedderEvent::FocusWebView(webview_id));
|
||||
}
|
||||
},
|
||||
}
|
||||
|
|
|
@ -47,5 +47,6 @@ pub trait WindowPortsMethods: WindowMethods {
|
|||
events_loop: &winit::event_loop::EventLoopWindowTarget<WakerEvent>,
|
||||
) -> Box<dyn webxr::glwindow::GlWindow>;
|
||||
fn winit_window(&self) -> Option<&winit::window::Window>;
|
||||
fn toolbar_height(&self) -> Length<f32, DeviceIndependentPixel>;
|
||||
fn set_toolbar_height(&self, height: Length<f32, DeviceIndependentPixel>);
|
||||
}
|
||||
|
|
|
@ -162,6 +162,7 @@ class MachCommands(CommandBase):
|
|||
"crown",
|
||||
"constellation",
|
||||
"style_config",
|
||||
"compositing",
|
||||
]
|
||||
if not packages:
|
||||
packages = set(os.listdir(path.join(self.context.topdir, "tests", "unit"))) - set(['.DS_Store'])
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue