script: Improve webdriver_handler::get_element_in_view_center_point (#38058)

1. Some rounding was wrongly used which can be a source of inaccuracy. 
2. Use `window.InnerWidth` instead of `body.ClientWidth` according to
spec.

Testing: Many new passing cases.
Fixes: Part of #38042.

---------

Signed-off-by: Euclid Ye <euclid.ye@huawei.com>
This commit is contained in:
Euclid Ye 2025-07-15 08:14:17 +08:00 committed by GitHub
parent f13311a00e
commit 8877adccf2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 63 additions and 69 deletions

View file

@ -2,7 +2,6 @@
* 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::cmp;
use std::collections::{HashMap, HashSet};
use std::ffi::CString;
use std::ptr::NonNull;
@ -630,37 +629,44 @@ pub(crate) fn handle_get_browsing_context_id(
.unwrap();
}
// https://w3c.github.io/webdriver/#dfn-center-point
/// <https://w3c.github.io/webdriver/#dfn-center-point>
fn get_element_in_view_center_point(element: &Element, can_gc: CanGc) -> Option<Point2D<i64>> {
element
.owner_document()
.GetBody()
.map(DomRoot::upcast::<Element>)
.and_then(|body| {
let doc = element.owner_document();
// Step 1: Let rectangle be the first element of the DOMRect sequence
// returned by calling getClientRects() on element.
element.GetClientRects(can_gc).first().map(|rectangle| {
let x = rectangle.X().round() as i64;
let y = rectangle.Y().round() as i64;
let width = rectangle.Width().round() as i64;
let height = rectangle.Height().round() as i64;
let client_width = body.ClientWidth(can_gc) as i64;
let client_height = body.ClientHeight(can_gc) as i64;
// Steps 2 - 5
let left = cmp::max(0, cmp::min(x, x + width));
let right = cmp::min(client_width, cmp::max(x, x + width));
let top = cmp::max(0, cmp::min(y, y + height));
let bottom = cmp::min(client_height, cmp::max(y, y + height));
// Steps 6 - 7
let x = (left + right) / 2;
let y = (top + bottom) / 2;
let x = rectangle.X();
let y = rectangle.Y();
let width = rectangle.Width();
let height = rectangle.Height();
debug!(
"get_element_in_view_center_point: Element rectangle at \
(x: {x}, y: {y}, width: {width}, height: {height})",
);
let window = doc.window();
// Steps 2. Let left be max(0, min(x coordinate, x coordinate + width dimension)).
let left = (x.min(x + width)).max(0.0);
// Step 3. Let right be min(innerWidth, max(x coordinate, x coordinate + width dimension)).
let right = f64::min(window.InnerWidth() as f64, x.max(x + width));
// Step 4. Let top be max(0, min(y coordinate, y coordinate + height dimension)).
let top = (y.min(y + height)).max(0.0);
// Step 5. Let bottom be
// min(innerHeight, max(y coordinate, y coordinate + height dimension)).
let bottom = f64::min(window.InnerHeight() as f64, y.max(y + height));
debug!(
"get_element_in_view_center_point: Computed rectangle is \
(left: {left}, right: {right}, top: {top}, bottom: {bottom})",
);
// Step 6. Let x be floor((left + right) ÷ 2.0).
let center_x = ((left + right) / 2.0).floor() as i64;
// Step 7. Let y be floor((top + bottom) ÷ 2.0).
let center_y = ((top + bottom) / 2.0).floor() as i64;
debug!(
"get_element_in_view_center_point: Element center point at ({center_x}, {center_y})",
);
// Step 8
Point2D::new(x, y)
})
Point2D::new(center_x, center_y)
})
}

View file

@ -1875,7 +1875,7 @@ impl Handler {
fn handle_element_click(&mut self, element: &WebElement) -> WebDriverResult<WebDriverResponse> {
let (sender, receiver) = ipc::channel().unwrap();
// Steps 1 - 7
// Steps 1 - 7 + Step 8 for <option>
let cmd = WebDriverScriptCommand::ElementClick(element.to_string(), sender);
self.browsing_context_script_command(cmd, VerifyBrowsingContextIsOpen::Yes)?;
@ -1883,7 +1883,7 @@ impl Handler {
Ok(element_id) => match element_id {
Some(element_id) => {
let id = Uuid::new_v4().to_string();
// Step 8 for elements other than <option>
// Step 8.1
self.session_mut()?.input_state_table.borrow_mut().insert(
id.clone(),

View file

@ -40,3 +40,6 @@
[test_add_cookie_with_invalid_samesite_flag]
expected: FAIL
[test_add_cookie_with_expiry_in_the_future]
expected: FAIL

View file

@ -1,30 +1,3 @@
[scroll_into_view.py]
[test_scroll_into_view]
expected: FAIL
[test_partially_visible_does_not_scroll[9\]]
expected: FAIL
[test_partially_visible_does_not_scroll[8\]]
expected: FAIL
[test_partially_visible_does_not_scroll[7\]]
expected: FAIL
[test_partially_visible_does_not_scroll[6\]]
expected: FAIL
[test_partially_visible_does_not_scroll[5\]]
expected: FAIL
[test_partially_visible_does_not_scroll[4\]]
expected: FAIL
[test_partially_visible_does_not_scroll[3\]]
expected: FAIL
[test_partially_visible_does_not_scroll[2\]]
expected: FAIL
[test_partially_visible_does_not_scroll[1\]]
expected: FAIL

View file

@ -10,3 +10,6 @@
[test_seen_nodes[https coop\]]
expected: FAIL
[test_removed_iframe]
expected: FAIL

View file

@ -4,6 +4,3 @@
[test_control_click[\\ue051-ctrlKey\]]
expected: FAIL
[test_release_control_click]
expected: FAIL

View file

@ -1,9 +1,3 @@
[pointer_origin.py]
[test_element_center_point]
expected: FAIL
[test_element_center_point_with_offset]
expected: FAIL
[test_element_larger_than_viewport]
expected: FAIL

View file

@ -43,3 +43,21 @@
[test_no_change[rect19\]]
expected: FAIL
[test_partial_input[rect2\]]
expected: FAIL
[test_partial_input[rect3\]]
expected: FAIL
[test_partial_input[rect4\]]
expected: FAIL
[test_partial_input[rect5\]]
expected: FAIL
[test_partial_input[rect6\]]
expected: FAIL
[test_partial_input[rect7\]]
expected: FAIL