diff --git a/components/constellation/tracing.rs b/components/constellation/tracing.rs index 562c499cef4..cbedd2da872 100644 --- a/components/constellation/tracing.rs +++ b/components/constellation/tracing.rs @@ -121,6 +121,8 @@ mod from_compositor { } mod from_script { + use embedder_traits::LoadStatus; + use super::LogTarget; macro_rules! target { @@ -222,11 +224,17 @@ mod from_script { 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::LoadStart(..) => target_variant!("LoadStart"), - Self::LoadComplete(..) => target_variant!("LoadComplete"), + Self::NotifyLoadStatusChanged(_, LoadStatus::Started) => { + target_variant!("NotifyLoadStatusChanged(LoadStatus::Started)") + }, + Self::NotifyLoadStatusChanged(_, LoadStatus::HeadParsed) => { + target_variant!("NotifyLoadStatusChanged(LoadStatus::HeadParsed)") + }, + Self::NotifyLoadStatusChanged(_, LoadStatus::Complete) => { + target_variant!("NotifyLoadStatusChanged(LoadStatus::Complete") + }, Self::Panic(..) => target_variant!("Panic"), Self::GetSelectedBluetoothDevice(..) => { target_variant!("GetSelectedBluetoothDevice") diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index 83a98351ddc..b2c7ddd68a6 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -24,8 +24,8 @@ use cssparser::match_ignore_ascii_case; use devtools_traits::ScriptToDevtoolsControlMsg; use dom_struct::dom_struct; use embedder_traits::{ - ClipboardEventType, EmbedderMsg, MouseButton, MouseEventType, TouchEventType, TouchId, - WheelDelta, + ClipboardEventType, EmbedderMsg, LoadStatus, MouseButton, MouseEventType, TouchEventType, + TouchId, WheelDelta, }; use encoding_rs::{Encoding, UTF_8}; use euclid::default::{Point2D, Rect, Size2D}; @@ -1032,13 +1032,19 @@ impl Document { match state { DocumentReadyState::Loading => { if self.window().is_top_level() { - self.send_to_embedder(EmbedderMsg::LoadStart(self.webview_id())); + self.send_to_embedder(EmbedderMsg::NotifyLoadStatusChanged( + self.webview_id(), + LoadStatus::Started, + )); self.send_to_embedder(EmbedderMsg::Status(self.webview_id(), None)); } }, DocumentReadyState::Complete => { if self.window().is_top_level() { - self.send_to_embedder(EmbedderMsg::LoadComplete(self.webview_id())); + self.send_to_embedder(EmbedderMsg::NotifyLoadStatusChanged( + self.webview_id(), + LoadStatus::Complete, + )); } update_with_current_instant(&self.dom_complete); }, diff --git a/components/script/dom/htmlbodyelement.rs b/components/script/dom/htmlbodyelement.rs index 228e1490200..b531e27f0a1 100644 --- a/components/script/dom/htmlbodyelement.rs +++ b/components/script/dom/htmlbodyelement.rs @@ -3,7 +3,7 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ use dom_struct::dom_struct; -use embedder_traits::EmbedderMsg; +use embedder_traits::{EmbedderMsg, LoadStatus}; use html5ever::{local_name, namespace_url, ns, LocalName, Prefix}; use js::rust::HandleObject; use servo_url::ServoUrl; @@ -153,7 +153,10 @@ impl VirtualMethods for HTMLBodyElement { let window = self.owner_window(); window.prevent_layout_until_load_event(); if window.is_top_level() { - window.send_to_embedder(EmbedderMsg::HeadParsed(window.webview_id())); + window.send_to_embedder(EmbedderMsg::NotifyLoadStatusChanged( + window.webview_id(), + LoadStatus::HeadParsed, + )); } } diff --git a/components/shared/embedder/lib.rs b/components/shared/embedder/lib.rs index 5d425983800..92e1ba9e6e6 100644 --- a/components/shared/embedder/lib.rs +++ b/components/shared/embedder/lib.rs @@ -193,16 +193,12 @@ pub enum EmbedderMsg { SetCursor(WebViewId, Cursor), /// A favicon was detected NewFavicon(WebViewId, ServoUrl), - /// `` tag finished parsing - HeadParsed(WebViewId), /// The history state has changed. HistoryChanged(WebViewId, Vec, usize), /// Enter or exit fullscreen SetFullscreenState(WebViewId, bool), - /// The load of a page has begun - LoadStart(WebViewId), - /// The load of a page has completed - LoadComplete(WebViewId), + /// The [`LoadStatus`] of the Given `WebView` has changed. + NotifyLoadStatusChanged(WebViewId, LoadStatus), WebResourceRequested( Option, WebResourceRequest, @@ -286,11 +282,11 @@ impl Debug for EmbedderMsg { EmbedderMsg::SetClipboardContents(..) => write!(f, "SetClipboardContents"), EmbedderMsg::SetCursor(..) => write!(f, "SetCursor"), EmbedderMsg::NewFavicon(..) => write!(f, "NewFavicon"), - EmbedderMsg::HeadParsed(..) => write!(f, "HeadParsed"), EmbedderMsg::HistoryChanged(..) => write!(f, "HistoryChanged"), EmbedderMsg::SetFullscreenState(..) => write!(f, "SetFullscreenState"), - EmbedderMsg::LoadStart(..) => write!(f, "LoadStart"), - EmbedderMsg::LoadComplete(..) => write!(f, "LoadComplete"), + EmbedderMsg::NotifyLoadStatusChanged(_, status) => { + write!(f, "NotifyLoadStatusChanged({status:?})") + }, EmbedderMsg::WebResourceRequested(..) => write!(f, "WebResourceRequested"), EmbedderMsg::Panic(..) => write!(f, "Panic"), EmbedderMsg::GetSelectedBluetoothDevice(..) => write!(f, "GetSelectedBluetoothDevice"), @@ -736,3 +732,17 @@ pub enum MediaSessionActionType { /// The action intent is to move the playback time to a specific time. SeekTo, } + +/// The status of the load in this `WebView`. +#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)] +pub enum LoadStatus { + /// The load has started, but the headers have not yet been parsed. + Started, + /// The `` tag has been parsed in the currently loading page. At this point the page's + /// `HTMLBodyElement` is now available in the DOM. + HeadParsed, + /// The `Document` and all subresources have loaded. This is equivalent to + /// `document.readyState` == `complete`. + /// See + Complete, +} diff --git a/ports/servoshell/desktop/minibrowser.rs b/ports/servoshell/desktop/minibrowser.rs index aaab62930fb..d30dacde8fb 100644 --- a/ports/servoshell/desktop/minibrowser.rs +++ b/ports/servoshell/desktop/minibrowser.rs @@ -24,14 +24,14 @@ use servo::servo_geometry::DeviceIndependentPixel; use servo::servo_url::ServoUrl; use servo::webrender_api::units::DevicePixel; use servo::webrender_traits::SurfmanRenderingContext; -use servo::Servo; +use servo::{LoadStatus, Servo}; use winit::event::{ElementState, MouseButton, WindowEvent}; use winit::event_loop::ActiveEventLoop; use winit::window::Window; use super::egui_glue::EguiGlow; use super::geometry::winit_position_to_euclid_point; -use super::webview::{LoadStatus, WebView, WebViewManager}; +use super::webview::{WebView, WebViewManager}; pub struct Minibrowser { pub context: EguiGlow, @@ -108,7 +108,7 @@ impl Minibrowser { last_mouse_position: None, location: RefCell::new(initial_url.to_string()), location_dirty: false.into(), - load_status: LoadStatus::LoadComplete, + load_status: LoadStatus::Complete, status_text: None, } } @@ -300,12 +300,12 @@ impl Minibrowser { } match self.load_status { - LoadStatus::LoadStart | LoadStatus::HeadParsed => { + LoadStatus::Started | LoadStatus::HeadParsed => { if ui.add(Minibrowser::toolbar_button("X")).clicked() { warn!("Do not support stop yet."); } }, - LoadStatus::LoadComplete => { + LoadStatus::Complete => { if ui.add(Minibrowser::toolbar_button("↻")).clicked() { event_queue.borrow_mut().push(MinibrowserEvent::Reload); } diff --git a/ports/servoshell/desktop/tracing.rs b/ports/servoshell/desktop/tracing.rs index 243fc02f05a..eedee21ca65 100644 --- a/ports/servoshell/desktop/tracing.rs +++ b/ports/servoshell/desktop/tracing.rs @@ -148,11 +148,9 @@ mod from_servo { 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::LoadStart(..) => target!("LoadStart"), - Self::LoadComplete(..) => target!("LoadComplete"), + Self::NotifyLoadStatusChanged(..) => target!("NotifyLoadStatusChanged"), Self::Panic(..) => target!("Panic"), Self::GetSelectedBluetoothDevice(..) => target!("GetSelectedBluetoothDevice"), Self::SelectFiles(..) => target!("SelectFiles"), diff --git a/ports/servoshell/desktop/webview.rs b/ports/servoshell/desktop/webview.rs index abad072daa8..ce6a646d95f 100644 --- a/ports/servoshell/desktop/webview.rs +++ b/ports/servoshell/desktop/webview.rs @@ -23,8 +23,9 @@ use servo::webrender_api::ScrollLocation; use servo::{ CompositorEventVariant, ContextMenuResult, DualRumbleEffectParams, EmbedderMsg, FilterPattern, GamepadEvent, GamepadHapticEffectType, GamepadIndex, GamepadInputBounds, - GamepadSupportedHapticEffects, GamepadUpdateType, PermissionPrompt, PermissionRequest, - PromptCredentialsInput, PromptDefinition, PromptOrigin, PromptResult, Servo, TouchEventType, + GamepadSupportedHapticEffects, GamepadUpdateType, LoadStatus, PermissionPrompt, + PermissionRequest, PromptCredentialsInput, PromptDefinition, PromptOrigin, PromptResult, Servo, + TouchEventType, }; use tinyfiledialogs::{self, MessageBoxIcon, OkCancel, YesNo}; @@ -53,13 +54,6 @@ pub struct WebViewManager { shutdown_requested: bool, } -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub enum LoadStatus { - HeadParsed, - LoadStart, - LoadComplete, -} - // The state of each Tab/WebView pub struct WebView { pub rect: DeviceRect, @@ -77,7 +71,7 @@ impl WebView { title: None, url: None, focused: false, - load_status: LoadStatus::LoadComplete, + load_status: LoadStatus::Complete, servo_webview, } } @@ -171,7 +165,7 @@ impl WebViewManager { pub fn load_status(&self) -> LoadStatus { match self.focused_webview() { Some(webview) => webview.load_status, - None => LoadStatus::LoadComplete, + None => LoadStatus::Complete, } } @@ -423,7 +417,7 @@ impl WebViewManager { opts: &Opts, messages: Vec, ) -> ServoEventResponse { - let mut need_present = self.load_status() != LoadStatus::LoadComplete; + let mut need_present = self.load_status() != LoadStatus::Complete; let mut need_update = false; for message in messages { trace_embedder_msg!(message, "{message:?}"); @@ -638,9 +632,9 @@ impl WebViewManager { EmbedderMsg::NewFavicon(_, _url) => { // FIXME: show favicons in the UI somehow }, - EmbedderMsg::HeadParsed(webview_id) => { + EmbedderMsg::NotifyLoadStatusChanged(webview_id, load_status) => { if let Some(webview) = self.get_mut(webview_id) { - webview.load_status = LoadStatus::HeadParsed; + webview.load_status = load_status; need_update = true; }; }, @@ -653,18 +647,6 @@ impl WebViewManager { EmbedderMsg::SetFullscreenState(_, state) => { self.window.set_fullscreen(state); }, - EmbedderMsg::LoadStart(webview_id) => { - if let Some(webview) = self.get_mut(webview_id) { - webview.load_status = LoadStatus::LoadStart; - need_update = true; - }; - }, - EmbedderMsg::LoadComplete(webview_id) => { - if let Some(webview) = self.get_mut(webview_id) { - webview.load_status = LoadStatus::LoadComplete; - need_update = true; - }; - }, EmbedderMsg::WebResourceRequested(_, _web_resource_request, _response_sender) => {}, EmbedderMsg::Shutdown => { self.shutdown_requested = true; diff --git a/ports/servoshell/egl/android.rs b/ports/servoshell/egl/android.rs index 503494d7c03..7039c387c0f 100644 --- a/ports/servoshell/egl/android.rs +++ b/ports/servoshell/egl/android.rs @@ -15,7 +15,7 @@ use jni::objects::{GlobalRef, JClass, JObject, JString, JValue, JValueOwned}; use jni::sys::{jboolean, jfloat, jint, jobject}; use jni::{JNIEnv, JavaVM}; use log::{debug, error, info, warn}; -use servo::MediaSessionActionType; +use servo::{LoadStatus, MediaSessionActionType}; use simpleservo::{ DeviceIntRect, EventLoopWaker, InitOptions, InputMethodType, MediaSessionPlaybackState, PromptResult, SERVO, @@ -496,18 +496,20 @@ impl HostTrait for HostCallbacks { Some(default) } - fn on_load_started(&self) { - debug!("on_load_started"); + fn notify_load_status_changed(&self, load_status: LoadStatus) { + debug!("notify_load_status_changed: {load_status:?}"); let mut env = self.jvm.get_env().unwrap(); - env.call_method(self.callbacks.as_obj(), "onLoadStarted", "()V", &[]) - .unwrap(); - } - - fn on_load_ended(&self) { - debug!("on_load_ended"); - let mut env = self.jvm.get_env().unwrap(); - env.call_method(self.callbacks.as_obj(), "onLoadEnded", "()V", &[]) - .unwrap(); + match load_status { + LoadStatus::Started => { + env.call_method(self.callbacks.as_obj(), "onLoadStarted", "()V", &[]) + .unwrap(); + }, + LoadStatus::HeadParsed => {}, + LoadStatus::Complete => { + env.call_method(self.callbacks.as_obj(), "onLoadEnded", "()V", &[]) + .unwrap(); + }, + }; } fn on_shutdown_complete(&self) { diff --git a/ports/servoshell/egl/host_trait.rs b/ports/servoshell/egl/host_trait.rs index bc18a48572b..7d6ee078bea 100644 --- a/ports/servoshell/egl/host_trait.rs +++ b/ports/servoshell/egl/host_trait.rs @@ -3,7 +3,7 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ use servo::webrender_api::units::DeviceIntRect; -use servo::{InputMethodType, MediaSessionPlaybackState, PromptResult}; +use servo::{InputMethodType, LoadStatus, MediaSessionPlaybackState, PromptResult}; /// Callbacks. Implemented by embedder. Called by Servo. pub trait HostTrait { @@ -17,16 +17,16 @@ pub trait HostTrait { fn prompt_input(&self, msg: String, default: String, trusted: bool) -> Option; /// Show context menu fn show_context_menu(&self, title: Option, items: Vec); - /// Page starts loading. - /// "Reload button" should be disabled. - /// "Stop button" should be enabled. - /// Throbber starts spinning. - fn on_load_started(&self); - /// Page has loaded. - /// "Reload button" should be enabled. - /// "Stop button" should be disabled. - /// Throbber stops spinning. - fn on_load_ended(&self); + /// Notify that the load status of the page has changed. + /// Started: + /// - "Reload button" should be disabled. + /// - "Stop button" should be enabled. + /// - Throbber starts spinning. + /// Complete: + /// - "Reload button" should be enabled. + /// - "Stop button" should be disabled. + /// - Throbber stops spinning. + fn notify_load_status_changed(&self, load_status: LoadStatus); /// Page title has changed. fn on_title_changed(&self, title: Option); /// Allow Navigation. diff --git a/ports/servoshell/egl/ohos.rs b/ports/servoshell/egl/ohos.rs index 908a4c75240..de32080d9bd 100644 --- a/ports/servoshell/egl/ohos.rs +++ b/ports/servoshell/egl/ohos.rs @@ -21,7 +21,7 @@ use napi_ohos::{Env, JsObject, JsString, NapiRaw}; use ohos_ime::{AttachOptions, Ime, ImeProxy, RawTextEditorProxy}; use ohos_ime_sys::types::InputMethod_EnterKeyType; use servo::style::Zero; -use servo::{InputMethodType, MediaSessionPlaybackState, PromptResult}; +use servo::{InputMethodType, LoadStatus, MediaSessionPlaybackState, PromptResult}; use simpleservo::EventLoopWaker; use xcomponent_sys::{ OH_NativeXComponent, OH_NativeXComponent_Callback, OH_NativeXComponent_GetKeyEvent, @@ -733,19 +733,17 @@ impl HostTrait for HostCallbacks { warn!("show_context_menu not implemented") } - fn on_load_started(&self) { - warn!("on_load_started not implemented") - } - - fn on_load_ended(&self) { - // Note: It seems that we don't necessarily get 1 `on_load_ended` for each - // each time `on_loaded_started` is called. Presumably this requires some API changes, + fn notify_load_status_changed(&self, load_status: LoadStatus) { + // Note: It seems that we don't necessarily get 1 `LoadStatus::Complete` for each + // each time `LoadStatus::Started` is called. Presumably this requires some API changes, // e.g. including webview id, perhaps URL and some additional investigation effort. // For now we just add a trace event here, so that we can see in the trace if we // successfully loaded **a** page. - #[cfg(feature = "tracing-hitrace")] - let _scope = hitrace::ScopedTrace::start_trace(&c"PageLoadEndedPrompt"); - self.prompt_alert("Page finished loading!".to_string(), true); + if load_status == LoadStatus::Complete { + #[cfg(feature = "tracing-hitrace")] + let _scope = hitrace::ScopedTrace::start_trace(&c"PageLoadEndedPrompt"); + self.prompt_alert("Page finished loading!".to_string(), true); + } } fn on_title_changed(&self, title: Option) { diff --git a/ports/servoshell/egl/servo_glue.rs b/ports/servoshell/egl/servo_glue.rs index 5311f2a197c..2d9f9db1b41 100644 --- a/ports/servoshell/egl/servo_glue.rs +++ b/ports/servoshell/egl/servo_glue.rs @@ -479,11 +479,10 @@ impl ServoGlue { .host_callbacks .on_url_changed(entries[current].clone().to_string()); }, - EmbedderMsg::LoadStart(_) => { - self.callbacks.host_callbacks.on_load_started(); - }, - EmbedderMsg::LoadComplete(_) => { - self.callbacks.host_callbacks.on_load_ended(); + EmbedderMsg::NotifyLoadStatusChanged(_, load_status) => { + self.callbacks + .host_callbacks + .notify_load_status_changed(load_status); }, EmbedderMsg::GetSelectedBluetoothDevice(_, _, sender) => { let _ = sender.send(None); @@ -653,7 +652,6 @@ impl ServoGlue { EmbedderMsg::MoveTo(..) | EmbedderMsg::SetCursor(..) | EmbedderMsg::NewFavicon(..) | - EmbedderMsg::HeadParsed(..) | EmbedderMsg::SetFullscreenState(..) | EmbedderMsg::ReportProfile(..) | EmbedderMsg::EventDelivered(..) |