Repository: servo/servo
File: components/webdriver_server/actions.rs (Rust)

Code before:
            PointerOrigin::Viewport => Ok((x_offset, y_offset)),
            PointerOrigin::Pointer => {
                // Step 1. Let start x be equal to the x property of source.
                // Step 2. Let start y be equal to the y property of source.
                let (start_x, start_y) = {
                    let pointer_input_state = self.get_pointer_input_state(source_id);
                    (pointer_input_state.x, pointer_input_state.y)
                };
                // Step 3. Let x equal start x + x offset and y equal start y + y offset.
                Ok((start_x + x_offset, start_y + y_offset))
            },
            PointerOrigin::Element(web_element) => {
                // Steps 1 - 3
                let (x_element, y_element) = self.get_element_in_view_center_point(web_element)?;
                // Step 4. Let x equal x element + x offset, and y equal y element + y offset.
                Ok((x_element as f64 + x_offset, y_element as f64 + y_offset))
            },
        }
    }

    /// <https://w3c.github.io/webdriver/#dfn-center-point>
    fn get_element_in_view_center_point(
        &self,
        web_element: &WebElement,
    ) -> Result<(i64, i64), ErrorStatus> {
        let (sender, receiver) = generic_channel::channel().unwrap();
        // Step 1. Let element be the result of trying to run actions options'
        // get element origin steps with origin and browsing context.
        self.browsing_context_script_command(
            WebDriverScriptCommand::GetElementInViewCenterPoint(web_element.to_string(), sender),
            VerifyBrowsingContextIsOpen::No,
        )
        .unwrap();

        // Step 2. If element is null, return error with error code no such element.
        let response = match wait_for_ipc_response(receiver) {
            Ok(response) => response,
            Err(WebDriverError { error, .. }) => return Err(error),
        };

        // Step 3. Let x element and y element be the result of calculating the in-view center point of element.
        match response? {
            Some(point) => Ok(point),
            None => Err(ErrorStatus::UnknownError),
        }
    }

    /// <https://w3c.github.io/webdriver/#dfn-extract-an-action-sequence>
    pub(crate) fn extract_an_action_sequence(
        &mut self,
        params: ActionsParameters,

Review comment (performance):
Instead of generic channels here, I suspect you can just unconditionally use Crossbeam channels, which I think will help improve performance on desktop Servo as well.

Code after:
        };
        if x > viewport_size.width.into() || y > viewport_size.height.into() {
            Err(ErrorStatus::MoveTargetOutOfBounds)
        } else {
            Ok(())
        }
    }

    /// <https://w3c.github.io/webdriver/#dfn-get-coordinates-relative-to-an-origin>
    pub(crate) fn get_origin_relative_coordinates(
        &self,
        origin: &PointerOrigin,
        x_offset: f64,
        y_offset: f64,
        source_id: &str,
    ) -> Result<(f64, f64), ErrorStatus> {
        match origin {
            PointerOrigin::Viewport => Ok((x_offset, y_offset)),
            PointerOrigin::Pointer => {
                // Step 1. Let start x be equal to the x property of source.
                // Step 2. Let start y be equal to the y property of source.
                let (start_x, start_y) = {
                    let pointer_input_state = self.get_pointer_input_state(source_id);
                    (pointer_input_state.x, pointer_input_state.y)
                };
                // Step 3. Let x equal start x + x offset and y equal start y + y offset.
                Ok((start_x + x_offset, start_y + y_offset))
            },
            PointerOrigin::Element(web_element) => {
                // Steps 1 - 3
                let (x_element, y_element) = self.get_element_in_view_center_point(web_element)?;
                // Step 4. Let x equal x element + x offset, and y equal y element + y offset.
                Ok((x_element as f64 + x_offset, y_element as f64 + y_offset))
            },
        }
    }

    /// <https://w3c.github.io/webdriver/#dfn-center-point>
    fn get_element_in_view_center_point(
        &self,
        web_element: &WebElement,
    ) -> Result<(i64, i64), ErrorStatus> {
        let (sender, receiver) = generic_channel::oneshot().unwrap();
        // Step 1. Let element be the result of trying to run actions options'
        // get element origin steps with origin and browsing context.
        self.browsing_context_script_command(
            WebDriverScriptCommand::GetElementInViewCenterPoint(web_element.to_string(), sender),
            VerifyBrowsingContextIsOpen::No,
        )
        .unwrap();