use chromiumoxide_cdp::cdp::browser_protocol::dom::Quad;
use chromiumoxide_cdp::cdp::browser_protocol::input::{
DispatchMouseEventParams, DispatchMouseEventType, MouseButton,
};
use chromiumoxide_cdp::cdp::browser_protocol::page::Viewport;
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Point {
pub x: f64,
pub y: f64,
}
impl Point {
pub fn new(x: f64, y: f64) -> Self {
Self { x, y }
}
fn area(&self, other: &Self) -> f64 {
(self.x * other.y - other.x * self.y) / 2.
}
}
impl std::ops::Add<Point> for Point {
type Output = Self;
fn add(self, other: Self) -> Self {
Self {
x: self.x + other.x,
y: self.y + other.y,
}
}
}
impl std::ops::Sub<Point> for Point {
type Output = Self;
fn sub(self, other: Self) -> Self {
Self {
x: self.x - other.x,
y: self.y - other.y,
}
}
}
impl std::ops::Div<f64> for Point {
type Output = Self;
fn div(self, other: f64) -> Self {
Self {
x: self.x / other,
y: self.y / other,
}
}
}
impl From<Point> for DispatchMouseEventParams {
fn from(el: Point) -> DispatchMouseEventParams {
let mut params =
DispatchMouseEventParams::new(DispatchMouseEventType::MousePressed, el.x, el.y);
params.button = Some(MouseButton::Left);
params.click_count = Some(1);
params
}
}
#[derive(Debug, Copy, Clone)]
pub struct ElementQuad {
pub top_left: Point,
pub top_right: Point,
pub bottom_right: Point,
pub bottom_left: Point,
}
impl ElementQuad {
pub fn from_quad(quad: &Quad) -> Self {
assert_eq!(quad.inner().len(), 8);
let raw_quad = quad.inner();
Self {
top_left: Point {
x: raw_quad[0],
y: raw_quad[1],
},
top_right: Point {
x: raw_quad[2],
y: raw_quad[3],
},
bottom_right: Point {
x: raw_quad[4],
y: raw_quad[5],
},
bottom_left: Point {
x: raw_quad[6],
y: raw_quad[7],
},
}
}
pub fn quad_center(&self) -> Point {
Point {
x: (self.top_left.x + self.top_right.x + self.bottom_right.x + self.bottom_left.x) / 4.,
y: (self.top_left.y + self.top_right.y + self.bottom_right.y + self.bottom_left.y) / 4.,
}
}
pub fn quad_area(&self) -> f64 {
let area = self.top_left.area(&self.top_right)
+ self.top_right.area(&self.bottom_right)
+ self.bottom_right.area(&self.bottom_left)
+ self.bottom_left.area(&self.top_left);
area.abs()
}
pub fn height(&self) -> f64 {
self.bottom_left.y - self.top_left.y
}
pub fn width(&self) -> f64 {
self.top_right.x - self.top_left.x
}
pub fn aspect_ratio(&self) -> f64 {
self.width() / self.height()
}
pub fn most_left(&self) -> f64 {
self.top_right
.x
.min(self.top_left.x)
.min(self.bottom_right.x)
.min(self.bottom_left.x)
}
pub fn most_right(&self) -> f64 {
self.top_right
.x
.max(self.top_left.x)
.max(self.bottom_right.x)
.max(self.bottom_left.x)
}
pub fn most_top(&self) -> f64 {
self.top_right
.y
.min(self.top_left.y)
.min(self.bottom_right.y)
.min(self.bottom_left.y)
}
pub fn most_bottom(&self) -> f64 {
self.top_right
.y
.max(self.top_left.y)
.max(self.bottom_right.y)
.max(self.bottom_left.y)
}
pub fn strictly_above(&self, other: &Self) -> bool {
self.most_bottom() < other.most_top()
}
pub fn above(&self, other: &Self) -> bool {
self.most_bottom() <= other.most_top()
}
pub fn strictly_below(&self, other: &Self) -> bool {
self.most_top() > other.most_bottom()
}
pub fn below(&self, other: &Self) -> bool {
self.most_top() >= other.most_bottom()
}
pub fn strictly_left_of(&self, other: &Self) -> bool {
self.most_right() < other.most_left()
}
pub fn left_of(&self, other: &Self) -> bool {
self.most_right() <= other.most_left()
}
pub fn strictly_right_of(&self, other: &Self) -> bool {
self.most_left() > other.most_right()
}
pub fn right_of(&self, other: &Self) -> bool {
self.most_left() >= other.most_right()
}
pub fn within_horizontal_bounds_of(&self, other: &Self) -> bool {
self.most_left() >= other.most_left() && self.most_right() <= other.most_right()
}
pub fn within_vertical_bounds_of(&self, other: &Self) -> bool {
self.most_top() >= other.most_top() && self.most_bottom() <= other.most_bottom()
}
pub fn within_bounds_of(&self, other: &Self) -> bool {
self.within_horizontal_bounds_of(other) && self.within_vertical_bounds_of(other)
}
}
#[derive(Debug, Clone)]
pub struct BoxModel {
pub content: ElementQuad,
pub padding: ElementQuad,
pub border: ElementQuad,
pub margin: ElementQuad,
pub width: u32,
pub height: u32,
}
impl BoxModel {
pub fn content_viewport(&self) -> Viewport {
Viewport {
x: self.content.top_left.x,
y: self.content.top_left.y,
width: self.content.width(),
height: self.content.height(),
scale: 1.0,
}
}
pub fn padding_viewport(&self) -> Viewport {
Viewport {
x: self.padding.top_left.x,
y: self.padding.top_left.y,
width: self.padding.width(),
height: self.padding.height(),
scale: 1.0,
}
}
pub fn border_viewport(&self) -> Viewport {
Viewport {
x: self.border.top_left.x,
y: self.border.top_left.y,
width: self.border.width(),
height: self.border.height(),
scale: 1.0,
}
}
pub fn margin_viewport(&self) -> Viewport {
Viewport {
x: self.margin.top_left.x,
y: self.margin.top_left.y,
width: self.margin.width(),
height: self.margin.height(),
scale: 1.0,
}
}
}
#[derive(Debug, Clone)]
pub struct BoundingBox {
pub x: f64,
pub y: f64,
pub width: f64,
pub height: f64,
}