From 5bb60f47fcc7f2a7ec297c8a325bebee1c963e4f Mon Sep 17 00:00:00 2001 From: Narfinger Date: Wed, 7 May 2025 11:01:23 +0200 Subject: [PATCH 1/3] Allow OHOS servoshell to have a simple multiple tab implementation. Currently we just pause the compositor and replace the window in it while having separate bookkeeping to remember which window belongs to which tab. Signed-off-by: Narfinger --- ports/servoshell/egl/app_state.rs | 83 +++++++---- ports/servoshell/egl/ohos.rs | 134 ++++++++++++------ ports/servoshell/egl/ohos/simpleservo.rs | 25 ++-- .../entry/src/main/ets/pages/Index.ets | 124 ++++++++++------ 4 files changed, 244 insertions(+), 122 deletions(-) diff --git a/ports/servoshell/egl/app_state.rs b/ports/servoshell/egl/app_state.rs index 737a2f23b7d..d75e70c815a 100644 --- a/ports/servoshell/egl/app_state.rs +++ b/ports/servoshell/egl/app_state.rs @@ -96,6 +96,9 @@ struct RunningAppStateInner { /// The HiDPI scaling factor to use for the display of [`WebView`]s. hidpi_scale_factor: Scale, + + /// Touch events should not be processed if the compositor is paused + compositor_paused: bool, } struct ServoShellServoDelegate { @@ -314,6 +317,7 @@ impl RunningAppState { focused_webview_id: None, animating_state_changed, hidpi_scale_factor: Scale::new(hidpi_scale_factor), + compositor_paused: false, }), }); @@ -337,6 +341,19 @@ impl RunningAppState { self.inner_mut().webviews.insert(webview.id(), webview); } + pub(crate) fn activate_webview(&self, id: u32) { + let inner = self.inner(); + let webview = inner + .creation_order + .get(id as usize) + .and_then(|id| inner.webviews.get(id)); + if let Some(webview) = webview { + webview.focus(); + } else { + error!("We could not find the webview with this id {id}"); + } + } + fn inner(&self) -> Ref { self.inner.borrow() } @@ -492,46 +509,54 @@ impl RunningAppState { /// Touch event: press down pub fn touch_down(&self, x: f32, y: f32, pointer_id: i32) { - self.active_webview() - .notify_input_event(InputEvent::Touch(TouchEvent::new( - TouchEventType::Down, - TouchId(pointer_id), - Point2D::new(x, y), - ))); - self.perform_updates(); + if !self.inner().compositor_paused { + self.active_webview() + .notify_input_event(InputEvent::Touch(TouchEvent::new( + TouchEventType::Down, + TouchId(pointer_id), + Point2D::new(x, y), + ))); + self.perform_updates(); + } } /// Touch event: move touching finger pub fn touch_move(&self, x: f32, y: f32, pointer_id: i32) { - self.active_webview() - .notify_input_event(InputEvent::Touch(TouchEvent::new( - TouchEventType::Move, - TouchId(pointer_id), - Point2D::new(x, y), - ))); - self.perform_updates(); + if !self.inner().compositor_paused { + self.active_webview() + .notify_input_event(InputEvent::Touch(TouchEvent::new( + TouchEventType::Move, + TouchId(pointer_id), + Point2D::new(x, y), + ))); + self.perform_updates(); + } } /// Touch event: Lift touching finger pub fn touch_up(&self, x: f32, y: f32, pointer_id: i32) { - self.active_webview() - .notify_input_event(InputEvent::Touch(TouchEvent::new( - TouchEventType::Up, - TouchId(pointer_id), - Point2D::new(x, y), - ))); - self.perform_updates(); + if !self.inner().compositor_paused { + self.active_webview() + .notify_input_event(InputEvent::Touch(TouchEvent::new( + TouchEventType::Up, + TouchId(pointer_id), + Point2D::new(x, y), + ))); + self.perform_updates(); + } } /// Cancel touch event pub fn touch_cancel(&self, x: f32, y: f32, pointer_id: i32) { - self.active_webview() - .notify_input_event(InputEvent::Touch(TouchEvent::new( - TouchEventType::Cancel, - TouchId(pointer_id), - Point2D::new(x, y), - ))); - self.perform_updates(); + if !self.inner().compositor_paused { + self.active_webview() + .notify_input_event(InputEvent::Touch(TouchEvent::new( + TouchEventType::Cancel, + TouchId(pointer_id), + Point2D::new(x, y), + ))); + self.perform_updates(); + } } /// Register a mouse movement. @@ -637,6 +662,7 @@ impl RunningAppState { if let Err(e) = self.rendering_context.take_window() { warn!("Unbinding native surface from context failed ({:?})", e); } + self.inner_mut().compositor_paused = true; self.perform_updates(); } @@ -649,6 +675,7 @@ impl RunningAppState { { warn!("Binding native surface to context failed ({:?})", e); } + self.inner_mut().compositor_paused = false; self.perform_updates(); } diff --git a/ports/servoshell/egl/ohos.rs b/ports/servoshell/egl/ohos.rs index ceccbdbe900..bb1b000c2d1 100644 --- a/ports/servoshell/egl/ohos.rs +++ b/ports/servoshell/egl/ohos.rs @@ -6,8 +6,9 @@ use std::cell::RefCell; use std::mem::MaybeUninit; use std::os::raw::c_void; +use std::rc::Rc; use std::sync::mpsc::{Receiver, Sender}; -use std::sync::{LazyLock, Once, OnceLock, mpsc}; +use std::sync::{LazyLock, Mutex, Once, OnceLock, mpsc}; use std::thread; use std::thread::sleep; use std::time::Duration; @@ -69,9 +70,11 @@ fn call(action: ServoAction) -> Result<(), CallError> { } #[repr(transparent)] -struct XComponentWrapper(*mut OH_NativeXComponent); +#[derive(Clone)] +pub(crate) struct XComponentWrapper(*mut OH_NativeXComponent); #[repr(transparent)] -struct WindowWrapper(*mut c_void); +#[derive(Clone)] +pub(crate) struct WindowWrapper(*mut c_void); unsafe impl Send for XComponentWrapper {} unsafe impl Send for WindowWrapper {} @@ -84,7 +87,6 @@ pub(super) enum TouchEventType { Unknown, } -#[derive(Debug)] pub(super) enum ServoAction { WakeUp, LoadUrl(String), @@ -108,6 +110,8 @@ pub(super) enum ServoAction { width: i32, height: i32, }, + FocusWebview(u32), + NewWebview(XComponentWrapper, WindowWrapper), } /// Queue length for the thread-safe function to submit URL updates to ArkTS @@ -127,6 +131,11 @@ static PROMPT_TOAST: OnceLock< ThreadsafeFunction, > = OnceLock::new(); +/// Currently we do not support different contexts for different windows but we might want to change tabs. +/// For this we store the window context for every tab and change the compositor by hand. +static WEBVIEW_TO_RAW_HANDLE: Mutex> = + Mutex::new(Vec::new()); + impl ServoAction { fn dispatch_touch_event( servo: &RunningAppState, @@ -145,7 +154,7 @@ impl ServoAction { } // todo: consider making this take `self`, so we don't need to needlessly clone. - fn do_action(&self, servo: &RunningAppState) { + fn do_action(&self, servo: &Rc) { use ServoAction::*; match self { WakeUp => servo.perform_updates(), @@ -157,7 +166,7 @@ impl ServoAction { x, y, pointer_id, - } => Self::dispatch_touch_event(servo, *kind, *x, *y, *pointer_id), + } => Self::dispatch_touch_event(&servo, *kind, *x, *y, *pointer_id), KeyUp(k) => servo.key_up(k.clone()), KeyDown(k) => servo.key_down(k.clone()), InsertText(text) => servo.ime_insert_text(text.clone()), @@ -185,6 +194,29 @@ impl ServoAction { servo.present_if_needed(); }, Resize { width, height } => servo.resize(Coordinates::new(0, 0, *width, *height)), + FocusWebview(id) => { + servo.activate_webview(id.clone()); + servo.pause_compositor(); + let webview_lock = WEBVIEW_TO_RAW_HANDLE.lock().unwrap(); + let (xcomponent_wrapper, window_wrapper) = webview_lock + .get(*id as usize) + .clone() + .expect("Could not find window handle to webview"); + let (window_handle, _, coordinates) = + simpleservo::get_raw_window_handle(xcomponent_wrapper.0, window_wrapper.0); + servo.resume_compositor(window_handle, coordinates); + }, + NewWebview(xcomponent, window) => { + servo.pause_compositor(); + servo.new_toplevel_webview("about:blank".parse().unwrap()); + let (window_handle, _, coordinates) = + simpleservo::get_raw_window_handle(xcomponent.0, window.0); + WEBVIEW_TO_RAW_HANDLE + .lock() + .unwrap() + .push((xcomponent.clone(), window.clone())); + servo.resume_compositor(window_handle, coordinates); + }, }; } } @@ -223,50 +255,60 @@ extern "C" fn on_surface_created_cb(xcomponent: *mut OH_NativeXComponent, window let xc_wrapper = XComponentWrapper(xcomponent); let window_wrapper = WindowWrapper(window); - // Todo: Perhaps it would be better to move this thread into the vsync signal thread. - // This would allow us to save one thread and the IPC for the vsync signal. - // - // Each thread will send its id via the channel - let _main_surface_thread = thread::spawn(move || { - let (tx, rx): (Sender, Receiver) = mpsc::channel(); + if !SERVO_CHANNEL.get().is_some() { + // Todo: Perhaps it would be better to move this thread into the vsync signal thread. + // This would allow us to save one thread and the IPC for the vsync signal. + // + // Each thread will send its id via the channel + let _main_surface_thread = thread::spawn(move || { + let (tx, rx): (Sender, Receiver) = mpsc::channel(); - SERVO_CHANNEL - .set(tx.clone()) - .expect("Servo channel already initialized"); + SERVO_CHANNEL + .set(tx.clone()) + .expect("Servo channel already initialized"); - let wakeup = Box::new(WakeupCallback::new(tx)); - let callbacks = Box::new(HostCallbacks::new()); + let wakeup = Box::new(WakeupCallback::new(tx)); + let callbacks = Box::new(HostCallbacks::new()); - let xc = xc_wrapper; - let window = window_wrapper; - let init_opts = if let Ok(ServoAction::Initialize(init_opts)) = rx.recv() { - init_opts - } else { - panic!("Servos GL thread received another event before it was initialized") - }; - let servo = simpleservo::init(*init_opts, window.0, xc.0, wakeup, callbacks) - .expect("Servo initialization failed"); + let xc = xc_wrapper; + let window = window_wrapper; - info!("Surface created!"); - let native_vsync = - ohos_vsync::NativeVsync::new("ServoVsync").expect("Failed to create NativeVsync"); - // get_period() returns an error - perhaps we need to wait until the first callback? - // info!("Native vsync period is {} nanoseconds", native_vsync.get_period().unwrap()); - unsafe { - native_vsync - .request_raw_callback_with_self(Some(on_vsync_cb)) - .expect("Failed to request vsync callback") - } - info!("Enabled Vsync!"); + WEBVIEW_TO_RAW_HANDLE + .lock() + .unwrap() + .push((xc.clone(), window.clone())); - while let Ok(action) = rx.recv() { - trace!("Wakeup message received!"); - action.do_action(&servo); - } + let init_opts = if let Ok(ServoAction::Initialize(init_opts)) = rx.recv() { + init_opts + } else { + panic!("Servos GL thread received another event before it was initialized") + }; + let servo = simpleservo::init(*init_opts, window.0, xc.0, wakeup, callbacks) + .expect("Servo initialization failed"); - info!("Sender disconnected - Terminating main surface thread"); - }); + info!("Surface created!"); + let native_vsync = + ohos_vsync::NativeVsync::new("ServoVsync").expect("Failed to create NativeVsync"); + // get_period() returns an error - perhaps we need to wait until the first callback? + // info!("Native vsync period is {} nanoseconds", native_vsync.get_period().unwrap()); + unsafe { + native_vsync + .request_raw_callback_with_self(Some(on_vsync_cb)) + .expect("Failed to request vsync callback") + } + info!("Enabled Vsync!"); + while let Ok(action) = rx.recv() { + trace!("Wakeup message received!"); + action.do_action(&servo); + } + + info!("Sender disconnected - Terminating main surface thread"); + }); + } else { + call(ServoAction::NewWebview(xc_wrapper, window_wrapper)) + .expect("Could not create new webview"); + } info!("Returning from on_surface_created_cb"); } @@ -644,6 +686,12 @@ pub fn init_servo(init_opts: InitOpts) -> napi_ohos::Result<()> { Ok(()) } +#[napi] +fn focus_webview(id: u32) { + debug!("Focusing webview {id} from napi"); + call(ServoAction::FocusWebview(id)).expect("Could not focus webview"); +} + struct OhosImeOptions { input_type: ohos_ime_sys::types::InputMethod_TextInputType, enterkey_type: InputMethod_EnterKeyType, diff --git a/ports/servoshell/egl/ohos/simpleservo.rs b/ports/servoshell/egl/ohos/simpleservo.rs index c867c7a5330..8fdc305927e 100644 --- a/ports/servoshell/egl/ohos/simpleservo.rs +++ b/ports/servoshell/egl/ohos/simpleservo.rs @@ -23,6 +23,20 @@ use crate::egl::ohos::InitOpts; use crate::egl::ohos::resources::ResourceReaderInstance; use crate::prefs::{ArgumentParsingResult, parse_command_line_arguments}; +pub(crate) fn get_raw_window_handle( + xcomponent: *mut OH_NativeXComponent, + window: *mut c_void, +) -> (RawWindowHandle, euclid::default::Size2D, Coordinates) { + let window_size = unsafe { super::get_xcomponent_size(xcomponent, window) } + .expect("Could not get native window size"); + let (x, y) = unsafe { super::get_xcomponent_offset(xcomponent, window)}.expect("Could not get native window offset"); + let coordinates = Coordinates::new(x, y, window_size.width, window_size.height); + let native_window = NonNull::new(window).expect("Could not get native window"); + let window_handle = RawWindowHandle::OhosNdk(OhosNdkWindowHandle::new(native_window)); + let coordinates = Coordinates::new(0, 0, window_size.width, window_size.height); + (window_handle, window_size, coordinates) +} + /// Initialize Servo. At that point, we need a valid GL context. /// In the future, this will be done in multiple steps. pub fn init( @@ -94,19 +108,12 @@ pub fn init( #[cfg(target_env = "ohos")] crate::egl::ohos::set_log_filter(servoshell_preferences.log_filter.as_deref()); - let Ok(window_size) = (unsafe { super::get_xcomponent_size(xcomponent, native_window) }) else { - return Err("Failed to get xcomponent size"); - }; - let Ok((x, y)) = (unsafe { super::get_xcomponent_offset(xcomponent, native_window) }) else { - return Err("Failed to get xcomponent offset"); - }; - let coordinates = Coordinates::new(x, y, window_size.width, window_size.height); + let (window_handle, window_size, coordinates) = + get_raw_window_handle(xcomponent, native_window); let display_handle = RawDisplayHandle::Ohos(OhosDisplayHandle::new()); let display_handle = unsafe { DisplayHandle::borrow_raw(display_handle) }; - let native_window = NonNull::new(native_window).expect("Could not get native window"); - let window_handle = RawWindowHandle::OhosNdk(OhosNdkWindowHandle::new(native_window)); let window_handle = unsafe { WindowHandle::borrow_raw(window_handle) }; let rendering_context = Rc::new( diff --git a/support/openharmony/entry/src/main/ets/pages/Index.ets b/support/openharmony/entry/src/main/ets/pages/Index.ets index 1d84d4478db..8060e9b40c6 100644 --- a/support/openharmony/entry/src/main/ets/pages/Index.ets +++ b/support/openharmony/entry/src/main/ets/pages/Index.ets @@ -5,10 +5,17 @@ import promptAction from '@ohos.promptAction'; interface ServoXComponentInterface { loadURL(url: string): void; + goBack(): void; + goForward(): void; + registerURLcallback(callback: (url: string) => void): void; + registerPromptToastCallback(callback: (msg: string) => void): void + + focusWebview(index: number):void; + initServo(options: InitOpts): void; } @@ -23,20 +30,20 @@ interface InitOpts { } function get_density(): number { - try { - let displayClass = display.getDefaultDisplaySync(); - console.info('Test densityDPI:' + JSON.stringify(displayClass.densityDPI)); - return displayClass.densityDPI / 160; + try { + let displayClass = display.getDefaultDisplaySync(); + console.info('Test densityDPI:' + JSON.stringify(displayClass.densityDPI)); + return displayClass.densityDPI / 160; } catch (exception) { - console.error('Failed to obtain the default display object. Code: ' + JSON.stringify(exception)); - return 3; + console.error('Failed to obtain the default display object. Code: ' + JSON.stringify(exception)); + return 3; } } function get_device_type(): string { let device_type: string = deviceInfo.deviceType; if (device_type == "") { - console.error("deviceInfo.deviceType is empty string!") + console.error("deviceInfo.deviceType is empty string!") } else { console.info("Device type is " + device_type) } @@ -44,10 +51,10 @@ function get_device_type(): string { } function prompt_toast(msg: string) { - promptAction.showToast({ - message: msg, - duration: 2000 - }); + promptAction.showToast({ + message: msg, + duration: 2000 + }); } // Use the getShared API to obtain the LocalStorage instance shared by stage. @@ -62,11 +69,12 @@ struct Index { type: XComponentType.SURFACE, libraryname: 'servoshell', } - private context = getContext(this) as common.UIAbilityContext; @LocalStorageProp('InitialURI') InitialURI: string = "unused" @LocalStorageProp('CommandlineArgs') CommandlineArgs: string = "" @State urlToLoad: string = this.InitialURI + @State tablist: Array = []; + @State currentIndex: number = 0; // Called when the user swipes from the right or left edge to the middle // Default behavior is bringing the app to the background. @@ -78,57 +86,89 @@ struct Index { build() { Column() { Row() { - Button('⇦').backgroundColor(Color.White) + Button('+') + .backgroundColor(Color.White) + .fontColor(Color.Black) + .fontWeight(FontWeight.Bolder) + .fontSize(22) + .width('12%') + .onClick((event) => { + if (this.tablist.length==0) { + this.tablist.push(2); + } else { + this.tablist.push(this.tablist[this.tablist.length-1]+1); + } + // yes this is correct as we always have one tab extra + // The tab extra is seperate for the initialization and will always exist. + // It is not in the tablist. + this.currentIndex = this.tablist.length; + }) + Button('⇦') + .backgroundColor(Color.White) .fontColor(Color.Black) .fontWeight(FontWeight.Bolder) .width('12%') .fontSize(12) - .onClick(()=>{ + .onClick(() => { this.onBackPress() }) - Button('⇨').backgroundColor(Color.White) + Button('⇨') + .backgroundColor(Color.White) .fontColor(Color.Black) .fontWeight(FontWeight.Bolder) .fontSize(12) .width('12%') - .onClick(()=> { + .onClick(() => { this.xComponentContext?.goForward() }) - TextInput({placeholder:'URL',text: $$this.urlToLoad}) + TextInput({ placeholder: 'URL', text: $$this.urlToLoad }) .type(InputType.Normal) .width('76%') .onChange((value) => { this.urlToLoad = value }) - .onSubmit((EnterKeyType)=>{ + .onSubmit((EnterKeyType) => { this.xComponentContext?.loadURL(this.urlToLoad) console.info('Load URL: ', this.urlToLoad) }) } - XComponent(this.xComponentAttrs) - .focusable(true) - .onLoad((xComponentContext) => { - this.xComponentContext = xComponentContext as ServoXComponentInterface; - let resource_dir: string = this.context.resourceDir; - let cache_dir: string = this.context.cacheDir; - console.debug("resourceDir: ", resource_dir); - console.debug("cacheDir: ", cache_dir); - let init_options: InitOpts = { - url: this.urlToLoad, - deviceType: get_device_type(), - osFullName: deviceInfo.osFullName, - displayDensity: get_density(), - resourceDir: resource_dir, - cacheDir: cache_dir, - commandlineArgs: this.CommandlineArgs - } - this.xComponentContext.initServo(init_options) - this.xComponentContext.registerURLcallback((new_url) => { - console.info('New URL from native: ', new_url) - this.urlToLoad = new_url - }) - this.xComponentContext.registerPromptToastCallback(prompt_toast) + + Tabs({ barPosition: BarPosition.Start, index: this.currentIndex}) { + TabContent() { + XComponent(this.xComponentAttrs) + .focusable(true) + .onLoad((xComponentContext) => { + this.xComponentContext = xComponentContext as ServoXComponentInterface; + let resource_dir: string = this.context.resourceDir; + let cache_dir: string = this.context.cacheDir; + console.debug("resourceDir: ", resource_dir); + console.debug("cacheDir: ", cache_dir); + let init_options: InitOpts = { + url: this.urlToLoad, + deviceType: get_device_type(), + osFullName: deviceInfo.osFullName, + displayDensity: get_density(), + resourceDir: resource_dir, + cacheDir: cache_dir, + commandlineArgs: this.CommandlineArgs + } + this.xComponentContext.initServo(init_options) + this.xComponentContext.registerURLcallback((new_url) => { + console.info('New URL from native: ', new_url) + this.urlToLoad = new_url + }) + this.xComponentContext.registerPromptToastCallback(prompt_toast) + }) + }.tabBar('1') + ForEach(this.tablist, (item: number) => { + TabContent() { + XComponent(this.xComponentAttrs) + .focusable(true) + }.tabBar(String(item)) }) + }.onChange((index: number) => { + this.xComponentContext?.focusWebview(index); + }) } .width('100%') } @@ -138,4 +178,4 @@ interface XComponentAttrs { id: string; type: number; libraryname: string; -} \ No newline at end of file +} From 7de9716dc04f322636c54db11b1da24aa6cf3e2a Mon Sep 17 00:00:00 2001 From: Narfinger Date: Thu, 8 May 2025 15:51:20 +0200 Subject: [PATCH 2/3] Fix a crash in the touch handler. If some move events take the long route over the script thread but get cleaned up by a fling the late one will crash the handler. Now we just ignore move events that are already cleaned up. Signed-off-by: Narfinger --- components/compositing/touch.rs | 186 +++++++++++---------- components/compositing/webview_renderer.rs | 1 + components/shared/embedder/input_events.rs | 1 + ports/servoshell/egl/app_state.rs | 70 ++++---- 4 files changed, 129 insertions(+), 129 deletions(-) diff --git a/components/compositing/touch.rs b/components/compositing/touch.rs index 76d87732b32..fedd569a051 100644 --- a/components/compositing/touch.rs +++ b/components/compositing/touch.rs @@ -292,6 +292,10 @@ impl TouchHandler { .expect("Current Touch sequence does not exist") } + fn try_get_current_touch_sequence_mut(&mut self) -> Option<&mut TouchSequenceInfo> { + self.touch_sequence_map.get_mut(&self.current_sequence_id) + } + pub(crate) fn get_touch_sequence(&self, sequence_id: TouchSequenceId) -> &TouchSequenceInfo { self.touch_sequence_map .get(&sequence_id) @@ -374,81 +378,87 @@ impl TouchHandler { id: TouchId, point: Point2D, ) -> TouchMoveAction { - let touch_sequence = self.get_current_touch_sequence_mut(); - let idx = match touch_sequence - .active_touch_points - .iter_mut() - .position(|t| t.id == id) - { - Some(i) => i, - None => { - error!("Got a touchmove event for a non-active touch point"); - return TouchMoveAction::NoAction; - }, - }; - let old_point = touch_sequence.active_touch_points[idx].point; - let delta = point - old_point; + // As `TouchHandler` is per `WebViewRenderer` which is per `WebView` we might get a Touch Sequence Move that + // started with a down on a different webview. As the touch_sequence id is only changed on touch_down this + // move event gets a touch id which is already cleaned up. + if let Some(touch_sequence) = self.try_get_current_touch_sequence_mut() { + let idx = match touch_sequence + .active_touch_points + .iter_mut() + .position(|t| t.id == id) + { + Some(i) => i, + None => { + error!("Got a touchmove event for a non-active touch point"); + return TouchMoveAction::NoAction; + }, + }; + let old_point = touch_sequence.active_touch_points[idx].point; + let delta = point - old_point; - let action = match touch_sequence.touch_count() { - 1 => { - if let Panning { ref mut velocity } = touch_sequence.state { - // TODO: Probably we should track 1-3 more points and use a smarter algorithm - *velocity += delta; - *velocity /= 2.0; - // update the touch point every time when panning. + let action = match touch_sequence.touch_count() { + 1 => { + if let Panning { ref mut velocity } = touch_sequence.state { + // TODO: Probably we should track 1-3 more points and use a smarter algorithm + *velocity += delta; + *velocity /= 2.0; + // update the touch point every time when panning. + touch_sequence.active_touch_points[idx].point = point; + TouchMoveAction::Scroll(delta, point) + } else if delta.x.abs() > TOUCH_PAN_MIN_SCREEN_PX || + delta.y.abs() > TOUCH_PAN_MIN_SCREEN_PX + { + touch_sequence.state = Panning { + velocity: Vector2D::new(delta.x, delta.y), + }; + // No clicks should be issued after we transitioned to move. + touch_sequence.prevent_click = true; + // update the touch point + touch_sequence.active_touch_points[idx].point = point; + TouchMoveAction::Scroll(delta, point) + } else { + // We don't update the touchpoint, so multiple small moves can + // accumulate and merge into a larger move. + TouchMoveAction::NoAction + } + }, + 2 => { + if touch_sequence.state == Pinching || + delta.x.abs() > TOUCH_PAN_MIN_SCREEN_PX || + delta.y.abs() > TOUCH_PAN_MIN_SCREEN_PX + { + touch_sequence.state = Pinching; + let (d0, c0) = touch_sequence.pinch_distance_and_center(); + // update the touch point with the enough distance or pinching. + touch_sequence.active_touch_points[idx].point = point; + let (d1, c1) = touch_sequence.pinch_distance_and_center(); + let magnification = d1 / d0; + let scroll_delta = c1 - c0 * Scale::new(magnification); + TouchMoveAction::Zoom(magnification, scroll_delta) + } else { + // We don't update the touchpoint, so multiple small moves can + // accumulate and merge into a larger move. + TouchMoveAction::NoAction + } + }, + _ => { touch_sequence.active_touch_points[idx].point = point; - TouchMoveAction::Scroll(delta, point) - } else if delta.x.abs() > TOUCH_PAN_MIN_SCREEN_PX || - delta.y.abs() > TOUCH_PAN_MIN_SCREEN_PX - { - touch_sequence.state = Panning { - velocity: Vector2D::new(delta.x, delta.y), - }; - // No clicks should be issued after we transitioned to move. - touch_sequence.prevent_click = true; - // update the touch point - touch_sequence.active_touch_points[idx].point = point; - TouchMoveAction::Scroll(delta, point) - } else { - // We don't update the touchpoint, so multiple small moves can - // accumulate and merge into a larger move. + touch_sequence.state = MultiTouch; TouchMoveAction::NoAction - } - }, - 2 => { - if touch_sequence.state == Pinching || - delta.x.abs() > TOUCH_PAN_MIN_SCREEN_PX || - delta.y.abs() > TOUCH_PAN_MIN_SCREEN_PX - { - touch_sequence.state = Pinching; - let (d0, c0) = touch_sequence.pinch_distance_and_center(); - // update the touch point with the enough distance or pinching. - touch_sequence.active_touch_points[idx].point = point; - let (d1, c1) = touch_sequence.pinch_distance_and_center(); - let magnification = d1 / d0; - let scroll_delta = c1 - c0 * Scale::new(magnification); - TouchMoveAction::Zoom(magnification, scroll_delta) - } else { - // We don't update the touchpoint, so multiple small moves can - // accumulate and merge into a larger move. - TouchMoveAction::NoAction - } - }, - _ => { - touch_sequence.active_touch_points[idx].point = point; - touch_sequence.state = MultiTouch; - TouchMoveAction::NoAction - }, - }; - // If the touch action is not `NoAction` and the first move has not been processed, - // set pending_touch_move_action. - if TouchMoveAction::NoAction != action && - touch_sequence.prevent_move == TouchMoveAllowed::Pending - { - touch_sequence.update_pending_touch_move_action(action); + }, + }; + // If the touch action is not `NoAction` and the first move has not been processed, + // set pending_touch_move_action. + if TouchMoveAction::NoAction != action && + touch_sequence.prevent_move == TouchMoveAllowed::Pending + { + touch_sequence.update_pending_touch_move_action(action); + } + + action + } else { + TouchMoveAction::NoAction } - - action } pub fn on_touch_up(&mut self, id: TouchId, point: Point2D) { @@ -529,22 +539,24 @@ impl TouchHandler { } pub fn on_touch_cancel(&mut self, id: TouchId, _point: Point2D) { - let touch_sequence = self.get_current_touch_sequence_mut(); - match touch_sequence - .active_touch_points - .iter() - .position(|t| t.id == id) - { - Some(i) => { - touch_sequence.active_touch_points.swap_remove(i); - }, - None => { - warn!("Got a touchcancel event for a non-active touch point"); - return; - }, - } - if touch_sequence.active_touch_points.is_empty() { - touch_sequence.state = Finished; + // A similar thing with touch move can happen here where the event is coming from a different webview. + if let Some(touch_sequence) = self.try_get_current_touch_sequence_mut() { + match touch_sequence + .active_touch_points + .iter() + .position(|t| t.id == id) + { + Some(i) => { + touch_sequence.active_touch_points.swap_remove(i); + }, + None => { + warn!("Got a touchcancel event for a non-active touch point"); + return; + }, + } + if touch_sequence.active_touch_points.is_empty() { + touch_sequence.state = Finished; + } } } } diff --git a/components/compositing/webview_renderer.rs b/components/compositing/webview_renderer.rs index 0a6bdf9ae0a..ee764d47a97 100644 --- a/components/compositing/webview_renderer.rs +++ b/components/compositing/webview_renderer.rs @@ -404,6 +404,7 @@ impl WebViewRenderer { self.dispatch_input_event(event); } + /// Send touch event to the pipeline. Returns true if the event was send fn send_touch_event(&self, mut event: TouchEvent) -> bool { let get_pipeline_details = |pipeline_id| self.pipelines.get(&pipeline_id); let Some(result) = self diff --git a/components/shared/embedder/input_events.rs b/components/shared/embedder/input_events.rs index acaa9afb3ff..34737f827fd 100644 --- a/components/shared/embedder/input_events.rs +++ b/components/shared/embedder/input_events.rs @@ -124,6 +124,7 @@ pub enum TouchEventType { pub struct TouchId(pub i32); /// An ID for a sequence of touch events between a `Down` and the `Up` or `Cancel` event. +/// The ID is the same for all events between `Down`` and `Up`` or `Cancel`` #[repr(transparent)] #[derive(Clone, Copy, Debug, Default, Deserialize, Eq, Hash, PartialEq, Serialize)] pub struct TouchSequenceId(u32); diff --git a/ports/servoshell/egl/app_state.rs b/ports/servoshell/egl/app_state.rs index d75e70c815a..00ec4200da9 100644 --- a/ports/servoshell/egl/app_state.rs +++ b/ports/servoshell/egl/app_state.rs @@ -96,9 +96,6 @@ struct RunningAppStateInner { /// The HiDPI scaling factor to use for the display of [`WebView`]s. hidpi_scale_factor: Scale, - - /// Touch events should not be processed if the compositor is paused - compositor_paused: bool, } struct ServoShellServoDelegate { @@ -317,7 +314,6 @@ impl RunningAppState { focused_webview_id: None, animating_state_changed, hidpi_scale_factor: Scale::new(hidpi_scale_factor), - compositor_paused: false, }), }); @@ -509,54 +505,46 @@ impl RunningAppState { /// Touch event: press down pub fn touch_down(&self, x: f32, y: f32, pointer_id: i32) { - if !self.inner().compositor_paused { - self.active_webview() - .notify_input_event(InputEvent::Touch(TouchEvent::new( - TouchEventType::Down, - TouchId(pointer_id), - Point2D::new(x, y), - ))); - self.perform_updates(); - } + self.active_webview() + .notify_input_event(InputEvent::Touch(TouchEvent::new( + TouchEventType::Down, + TouchId(pointer_id), + Point2D::new(x, y), + ))); + self.perform_updates(); } /// Touch event: move touching finger pub fn touch_move(&self, x: f32, y: f32, pointer_id: i32) { - if !self.inner().compositor_paused { - self.active_webview() - .notify_input_event(InputEvent::Touch(TouchEvent::new( - TouchEventType::Move, - TouchId(pointer_id), - Point2D::new(x, y), - ))); - self.perform_updates(); - } + self.active_webview() + .notify_input_event(InputEvent::Touch(TouchEvent::new( + TouchEventType::Move, + TouchId(pointer_id), + Point2D::new(x, y), + ))); + self.perform_updates(); } /// Touch event: Lift touching finger pub fn touch_up(&self, x: f32, y: f32, pointer_id: i32) { - if !self.inner().compositor_paused { - self.active_webview() - .notify_input_event(InputEvent::Touch(TouchEvent::new( - TouchEventType::Up, - TouchId(pointer_id), - Point2D::new(x, y), - ))); - self.perform_updates(); - } + self.active_webview() + .notify_input_event(InputEvent::Touch(TouchEvent::new( + TouchEventType::Up, + TouchId(pointer_id), + Point2D::new(x, y), + ))); + self.perform_updates(); } /// Cancel touch event pub fn touch_cancel(&self, x: f32, y: f32, pointer_id: i32) { - if !self.inner().compositor_paused { - self.active_webview() - .notify_input_event(InputEvent::Touch(TouchEvent::new( - TouchEventType::Cancel, - TouchId(pointer_id), - Point2D::new(x, y), - ))); - self.perform_updates(); - } + self.active_webview() + .notify_input_event(InputEvent::Touch(TouchEvent::new( + TouchEventType::Cancel, + TouchId(pointer_id), + Point2D::new(x, y), + ))); + self.perform_updates(); } /// Register a mouse movement. @@ -662,7 +650,6 @@ impl RunningAppState { if let Err(e) = self.rendering_context.take_window() { warn!("Unbinding native surface from context failed ({:?})", e); } - self.inner_mut().compositor_paused = true; self.perform_updates(); } @@ -675,7 +662,6 @@ impl RunningAppState { { warn!("Binding native surface to context failed ({:?})", e); } - self.inner_mut().compositor_paused = false; self.perform_updates(); } From d1389378ad2d34120745f2bfe78a5fe470097731 Mon Sep 17 00:00:00 2001 From: Narfinger Date: Thu, 8 May 2025 17:40:02 +0200 Subject: [PATCH 3/3] Incorporate suggestions. Co-authored-by: Jonathan Schwender <55576758+jschwe@users.noreply.github.com> Signed-off-by: Narfinger --- components/compositing/touch.rs | 182 ++++++++++----------- components/compositing/webview_renderer.rs | 3 +- components/shared/embedder/input_events.rs | 2 +- ports/servoshell/egl/app_state.rs | 14 +- ports/servoshell/egl/ohos.rs | 84 +++++++--- ports/servoshell/egl/ohos/simpleservo.rs | 4 +- 6 files changed, 163 insertions(+), 126 deletions(-) diff --git a/components/compositing/touch.rs b/components/compositing/touch.rs index fedd569a051..1fe8d14817d 100644 --- a/components/compositing/touch.rs +++ b/components/compositing/touch.rs @@ -381,84 +381,83 @@ impl TouchHandler { // As `TouchHandler` is per `WebViewRenderer` which is per `WebView` we might get a Touch Sequence Move that // started with a down on a different webview. As the touch_sequence id is only changed on touch_down this // move event gets a touch id which is already cleaned up. - if let Some(touch_sequence) = self.try_get_current_touch_sequence_mut() { - let idx = match touch_sequence - .active_touch_points - .iter_mut() - .position(|t| t.id == id) - { - Some(i) => i, - None => { - error!("Got a touchmove event for a non-active touch point"); - return TouchMoveAction::NoAction; - }, - }; - let old_point = touch_sequence.active_touch_points[idx].point; - let delta = point - old_point; + let Some(touch_sequence) = self.try_get_current_touch_sequence_mut() else { + return TouchMoveAction::NoAction; + }; + let idx = match touch_sequence + .active_touch_points + .iter_mut() + .position(|t| t.id == id) + { + Some(i) => i, + None => { + error!("Got a touchmove event for a non-active touch point"); + return TouchMoveAction::NoAction; + }, + }; + let old_point = touch_sequence.active_touch_points[idx].point; + let delta = point - old_point; - let action = match touch_sequence.touch_count() { - 1 => { - if let Panning { ref mut velocity } = touch_sequence.state { - // TODO: Probably we should track 1-3 more points and use a smarter algorithm - *velocity += delta; - *velocity /= 2.0; - // update the touch point every time when panning. - touch_sequence.active_touch_points[idx].point = point; - TouchMoveAction::Scroll(delta, point) - } else if delta.x.abs() > TOUCH_PAN_MIN_SCREEN_PX || - delta.y.abs() > TOUCH_PAN_MIN_SCREEN_PX - { - touch_sequence.state = Panning { - velocity: Vector2D::new(delta.x, delta.y), - }; - // No clicks should be issued after we transitioned to move. - touch_sequence.prevent_click = true; - // update the touch point - touch_sequence.active_touch_points[idx].point = point; - TouchMoveAction::Scroll(delta, point) - } else { - // We don't update the touchpoint, so multiple small moves can - // accumulate and merge into a larger move. - TouchMoveAction::NoAction - } - }, - 2 => { - if touch_sequence.state == Pinching || - delta.x.abs() > TOUCH_PAN_MIN_SCREEN_PX || - delta.y.abs() > TOUCH_PAN_MIN_SCREEN_PX - { - touch_sequence.state = Pinching; - let (d0, c0) = touch_sequence.pinch_distance_and_center(); - // update the touch point with the enough distance or pinching. - touch_sequence.active_touch_points[idx].point = point; - let (d1, c1) = touch_sequence.pinch_distance_and_center(); - let magnification = d1 / d0; - let scroll_delta = c1 - c0 * Scale::new(magnification); - TouchMoveAction::Zoom(magnification, scroll_delta) - } else { - // We don't update the touchpoint, so multiple small moves can - // accumulate and merge into a larger move. - TouchMoveAction::NoAction - } - }, - _ => { + let action = match touch_sequence.touch_count() { + 1 => { + if let Panning { ref mut velocity } = touch_sequence.state { + // TODO: Probably we should track 1-3 more points and use a smarter algorithm + *velocity += delta; + *velocity /= 2.0; + // update the touch point every time when panning. touch_sequence.active_touch_points[idx].point = point; - touch_sequence.state = MultiTouch; + TouchMoveAction::Scroll(delta, point) + } else if delta.x.abs() > TOUCH_PAN_MIN_SCREEN_PX || + delta.y.abs() > TOUCH_PAN_MIN_SCREEN_PX + { + touch_sequence.state = Panning { + velocity: Vector2D::new(delta.x, delta.y), + }; + // No clicks should be issued after we transitioned to move. + touch_sequence.prevent_click = true; + // update the touch point + touch_sequence.active_touch_points[idx].point = point; + TouchMoveAction::Scroll(delta, point) + } else { + // We don't update the touchpoint, so multiple small moves can + // accumulate and merge into a larger move. TouchMoveAction::NoAction - }, - }; - // If the touch action is not `NoAction` and the first move has not been processed, - // set pending_touch_move_action. - if TouchMoveAction::NoAction != action && - touch_sequence.prevent_move == TouchMoveAllowed::Pending - { - touch_sequence.update_pending_touch_move_action(action); - } - - action - } else { - TouchMoveAction::NoAction + } + }, + 2 => { + if touch_sequence.state == Pinching || + delta.x.abs() > TOUCH_PAN_MIN_SCREEN_PX || + delta.y.abs() > TOUCH_PAN_MIN_SCREEN_PX + { + touch_sequence.state = Pinching; + let (d0, c0) = touch_sequence.pinch_distance_and_center(); + // update the touch point with the enough distance or pinching. + touch_sequence.active_touch_points[idx].point = point; + let (d1, c1) = touch_sequence.pinch_distance_and_center(); + let magnification = d1 / d0; + let scroll_delta = c1 - c0 * Scale::new(magnification); + TouchMoveAction::Zoom(magnification, scroll_delta) + } else { + // We don't update the touchpoint, so multiple small moves can + // accumulate and merge into a larger move. + TouchMoveAction::NoAction + } + }, + _ => { + touch_sequence.active_touch_points[idx].point = point; + touch_sequence.state = MultiTouch; + TouchMoveAction::NoAction + }, + }; + // If the touch action is not `NoAction` and the first move has not been processed, + // set pending_touch_move_action. + if TouchMoveAction::NoAction != action && + touch_sequence.prevent_move == TouchMoveAllowed::Pending + { + touch_sequence.update_pending_touch_move_action(action); } + + action } pub fn on_touch_up(&mut self, id: TouchId, point: Point2D) { @@ -540,23 +539,24 @@ impl TouchHandler { pub fn on_touch_cancel(&mut self, id: TouchId, _point: Point2D) { // A similar thing with touch move can happen here where the event is coming from a different webview. - if let Some(touch_sequence) = self.try_get_current_touch_sequence_mut() { - match touch_sequence - .active_touch_points - .iter() - .position(|t| t.id == id) - { - Some(i) => { - touch_sequence.active_touch_points.swap_remove(i); - }, - None => { - warn!("Got a touchcancel event for a non-active touch point"); - return; - }, - } - if touch_sequence.active_touch_points.is_empty() { - touch_sequence.state = Finished; - } + let Some(touch_sequence) = self.try_get_current_touch_sequence_mut() else { + return; + }; + match touch_sequence + .active_touch_points + .iter() + .position(|t| t.id == id) + { + Some(i) => { + touch_sequence.active_touch_points.swap_remove(i); + }, + None => { + warn!("Got a touchcancel event for a non-active touch point"); + return; + }, + } + if touch_sequence.active_touch_points.is_empty() { + touch_sequence.state = Finished; } } } diff --git a/components/compositing/webview_renderer.rs b/components/compositing/webview_renderer.rs index ee764d47a97..e0bad862912 100644 --- a/components/compositing/webview_renderer.rs +++ b/components/compositing/webview_renderer.rs @@ -404,7 +404,8 @@ impl WebViewRenderer { self.dispatch_input_event(event); } - /// Send touch event to the pipeline. Returns true if the event was send + /// Send a [`TouchEvent`] to the Constellation for this [`WebViewRenderer`]. + /// Returns true if the event was send fn send_touch_event(&self, mut event: TouchEvent) -> bool { let get_pipeline_details = |pipeline_id| self.pipelines.get(&pipeline_id); let Some(result) = self diff --git a/components/shared/embedder/input_events.rs b/components/shared/embedder/input_events.rs index 34737f827fd..38a1aa4aa27 100644 --- a/components/shared/embedder/input_events.rs +++ b/components/shared/embedder/input_events.rs @@ -124,7 +124,7 @@ pub enum TouchEventType { pub struct TouchId(pub i32); /// An ID for a sequence of touch events between a `Down` and the `Up` or `Cancel` event. -/// The ID is the same for all events between `Down`` and `Up`` or `Cancel`` +/// The ID is the same for all events between `Down` and `Up` or `Cancel` #[repr(transparent)] #[derive(Clone, Copy, Debug, Default, Deserialize, Eq, Hash, PartialEq, Serialize)] pub struct TouchSequenceId(u32); diff --git a/ports/servoshell/egl/app_state.rs b/ports/servoshell/egl/app_state.rs index 00ec4200da9..f931c26b8f8 100644 --- a/ports/servoshell/egl/app_state.rs +++ b/ports/servoshell/egl/app_state.rs @@ -337,13 +337,9 @@ impl RunningAppState { self.inner_mut().webviews.insert(webview.id(), webview); } - pub(crate) fn activate_webview(&self, id: u32) { - let inner = self.inner(); - let webview = inner - .creation_order - .get(id as usize) - .and_then(|id| inner.webviews.get(id)); - if let Some(webview) = webview { + /// The focused webview will not be immediately valid via `active_webview()` + pub(crate) fn focus_webview(&self, id: WebViewId) { + if let Some(webview) = self.inner().webviews.get(&id) { webview.focus(); } else { error!("We could not find the webview with this id {id}"); @@ -366,14 +362,14 @@ impl RunningAppState { Ok(webview_id) } - fn newest_webview(&self) -> Option { + pub(crate) fn newest_webview(&self) -> Option { self.inner() .creation_order .last() .and_then(|id| self.inner().webviews.get(id).cloned()) } - fn active_webview(&self) -> WebView { + pub(crate) fn active_webview(&self) -> WebView { self.inner() .focused_webview_id .and_then(|id| self.inner().webviews.get(&id).cloned()) diff --git a/ports/servoshell/egl/ohos.rs b/ports/servoshell/egl/ohos.rs index bb1b000c2d1..427beebe447 100644 --- a/ports/servoshell/egl/ohos.rs +++ b/ports/servoshell/egl/ohos.rs @@ -24,7 +24,7 @@ use ohos_ime_sys::types::InputMethod_EnterKeyType; use servo::style::Zero; use servo::{ AlertResponse, EventLoopWaker, InputMethodType, LoadStatus, MediaSessionPlaybackState, - PermissionRequest, SimpleDialog, WebView, + PermissionRequest, SimpleDialog, WebView, WebViewId, }; use xcomponent_sys::{ OH_NativeXComponent, OH_NativeXComponent_Callback, OH_NativeXComponent_GetKeyEvent, @@ -131,10 +131,19 @@ static PROMPT_TOAST: OnceLock< ThreadsafeFunction, > = OnceLock::new(); +/// Storing webview related items +struct NativeWebViewComponents { + /// The id of the related webview + id: WebViewId, + /// The XComponentWrapper for the above webview + xcomponent: XComponentWrapper, + /// The WindowWrapper for the above webview + window: WindowWrapper, +} + /// Currently we do not support different contexts for different windows but we might want to change tabs. /// For this we store the window context for every tab and change the compositor by hand. -static WEBVIEW_TO_RAW_HANDLE: Mutex> = - Mutex::new(Vec::new()); +static NATIVE_WEBVIEWS: Mutex> = Mutex::new(Vec::new()); impl ServoAction { fn dispatch_touch_event( @@ -194,28 +203,55 @@ impl ServoAction { servo.present_if_needed(); }, Resize { width, height } => servo.resize(Coordinates::new(0, 0, *width, *height)), - FocusWebview(id) => { - servo.activate_webview(id.clone()); - servo.pause_compositor(); - let webview_lock = WEBVIEW_TO_RAW_HANDLE.lock().unwrap(); - let (xcomponent_wrapper, window_wrapper) = webview_lock - .get(*id as usize) - .clone() - .expect("Could not find window handle to webview"); - let (window_handle, _, coordinates) = - simpleservo::get_raw_window_handle(xcomponent_wrapper.0, window_wrapper.0); - servo.resume_compositor(window_handle, coordinates); + FocusWebview(arkts_id) => { + if let Some(native_webview_components) = + NATIVE_WEBVIEWS.lock().unwrap().get(*arkts_id as usize) + { + if (servo.active_webview().id() != native_webview_components.id) { + servo.focus_webview(native_webview_components.id); + servo.pause_compositor(); + let (window_handle, _, coordinates) = simpleservo::get_raw_window_handle( + native_webview_components.xcomponent.0, + native_webview_components.window.0, + ); + servo.resume_compositor(window_handle, coordinates); + let url = servo + .active_webview() + .url() + .map(|u| u.to_string()) + .unwrap_or(String::from("about:blank")); + SET_URL_BAR_CB + .get() + .map(|f| f.call(url, ThreadsafeFunctionCallMode::Blocking)); + } + } else { + error!("Could not find webview to focus"); + } }, NewWebview(xcomponent, window) => { servo.pause_compositor(); servo.new_toplevel_webview("about:blank".parse().unwrap()); let (window_handle, _, coordinates) = simpleservo::get_raw_window_handle(xcomponent.0, window.0); - WEBVIEW_TO_RAW_HANDLE + + servo.resume_compositor(window_handle, coordinates); + let webview = servo.newest_webview().expect("There should always be one"); + let id = webview.id(); + NATIVE_WEBVIEWS .lock() .unwrap() - .push((xcomponent.clone(), window.clone())); - servo.resume_compositor(window_handle, coordinates); + .push(NativeWebViewComponents { + id: id, + xcomponent: xcomponent.clone(), + window: window.clone(), + }); + let url = webview + .url() + .map(|u| u.to_string()) + .unwrap_or(String::from("about:blank")); + SET_URL_BAR_CB + .get() + .map(|f| f.call(url, ThreadsafeFunctionCallMode::Blocking)); }, }; } @@ -273,11 +309,6 @@ extern "C" fn on_surface_created_cb(xcomponent: *mut OH_NativeXComponent, window let xc = xc_wrapper; let window = window_wrapper; - WEBVIEW_TO_RAW_HANDLE - .lock() - .unwrap() - .push((xc.clone(), window.clone())); - let init_opts = if let Ok(ServoAction::Initialize(init_opts)) = rx.recv() { init_opts } else { @@ -286,6 +317,15 @@ extern "C" fn on_surface_created_cb(xcomponent: *mut OH_NativeXComponent, window let servo = simpleservo::init(*init_opts, window.0, xc.0, wakeup, callbacks) .expect("Servo initialization failed"); + NATIVE_WEBVIEWS + .lock() + .unwrap() + .push(NativeWebViewComponents { + id: servo.active_webview().id(), + xcomponent: xc, + window, + }); + info!("Surface created!"); let native_vsync = ohos_vsync::NativeVsync::new("ServoVsync").expect("Failed to create NativeVsync"); diff --git a/ports/servoshell/egl/ohos/simpleservo.rs b/ports/servoshell/egl/ohos/simpleservo.rs index 8fdc305927e..25ff8255442 100644 --- a/ports/servoshell/egl/ohos/simpleservo.rs +++ b/ports/servoshell/egl/ohos/simpleservo.rs @@ -29,11 +29,11 @@ pub(crate) fn get_raw_window_handle( ) -> (RawWindowHandle, euclid::default::Size2D, Coordinates) { let window_size = unsafe { super::get_xcomponent_size(xcomponent, window) } .expect("Could not get native window size"); - let (x, y) = unsafe { super::get_xcomponent_offset(xcomponent, window)}.expect("Could not get native window offset"); + let (x, y) = unsafe { super::get_xcomponent_offset(xcomponent, window) } + .expect("Could not get native window offset"); let coordinates = Coordinates::new(x, y, window_size.width, window_size.height); let native_window = NonNull::new(window).expect("Could not get native window"); let window_handle = RawWindowHandle::OhosNdk(OhosNdkWindowHandle::new(native_window)); - let coordinates = Coordinates::new(0, 0, window_size.width, window_size.height); (window_handle, window_size, coordinates) }