playwright/imp/
page.rs

1use crate::imp::{
2    browser_context::BrowserContext,
3    console_message::ConsoleMessage,
4    core::*,
5    download::Download,
6    element_handle::may_save,
7    file_hooser::FileChooser,
8    frame::Frame,
9    prelude::*,
10    request::Request,
11    response::Response,
12    utils::{
13        ColorScheme, DocumentLoadState, FloatRect, Header, Length, MouseButton, PdfMargins,
14        ScreenshotType, Viewport
15    },
16    video::Video,
17    websocket::WebSocket,
18    worker::Worker
19};
20
21#[derive(Debug)]
22pub(crate) struct Page {
23    channel: ChannelOwner,
24    main_frame: Weak<Frame>,
25    browser_context: Weak<BrowserContext>,
26    var: Mutex<Variable>,
27    tx: Mutex<Option<broadcast::Sender<Evt>>>
28}
29
30#[derive(Debug, Default)]
31pub(crate) struct Variable {
32    viewport: Option<Viewport>,
33    frames: Vec<Weak<Frame>>,
34    timeout: Option<u32>,
35    navigation_timeout: Option<u32>,
36    workers: Vec<Weak<Worker>>,
37    video: Option<Video>
38}
39
40macro_rules! navigation {
41    ($f: ident, $m: literal) => {
42        pub(crate) async fn $f(
43            &self,
44            args: ReloadArgs
45        ) -> Result<Option<Weak<Response>>, Arc<Error>> {
46            let v = send_message!(self, $m, args);
47            let guid = match as_only_guid(&v) {
48                Some(g) => g,
49                None => return Ok(None)
50            };
51            let r = get_object!(self.context()?.lock().unwrap(), &guid, Response)?;
52            Ok(Some(r))
53        }
54    };
55}
56
57macro_rules! mouse_down {
58    ($f:ident, $m:literal) => {
59        pub(crate) async fn $f(
60            &self,
61            button: Option<MouseButton>,
62            click_count: Option<i32>
63        ) -> Result<(), Arc<Error>> {
64            #[skip_serializing_none]
65            #[derive(Serialize)]
66            #[serde(rename_all = "camelCase")]
67            struct Args {
68                button: Option<MouseButton>,
69                click_count: Option<i32>
70            }
71            let args = Args {
72                button,
73                click_count
74            };
75            let _ = send_message!(self, $m, args);
76            Ok(())
77        }
78    };
79}
80
81impl Page {
82    const DEFAULT_TIMEOUT: u32 = 30000;
83
84    pub(crate) fn try_new(ctx: &Context, channel: ChannelOwner) -> Result<Self, Error> {
85        let Initializer {
86            main_frame: OnlyGuid { guid },
87            viewport
88        } = serde_json::from_value(channel.initializer.clone())?;
89        let browser_context = match &channel.parent {
90            Some(RemoteWeak::BrowserContext(c)) => c.clone(),
91            _ => return Err(Error::InvalidParams)
92        };
93        let main_frame = get_object!(ctx, &guid, Frame)?;
94        let var = Mutex::new(Variable {
95            frames: vec![main_frame.clone()],
96            viewport,
97            ..Variable::default()
98        });
99        Ok(Self {
100            channel,
101            main_frame,
102            browser_context,
103            var,
104            tx: Mutex::default()
105        })
106    }
107
108    pub(crate) fn hook_created(&self, this: Weak<Page>) -> Result<(), Error> {
109        upgrade(&self.main_frame)?.set_page(this);
110        Ok(())
111    }
112
113    pub(crate) fn browser_context(&self) -> Weak<BrowserContext> { self.browser_context.clone() }
114
115    pub(crate) fn main_frame(&self) -> Weak<Frame> { self.main_frame.clone() }
116
117    navigation! {reload, "reload"}
118    navigation! {go_back, "goBack"}
119    navigation! {go_forward, "goForward"}
120
121    pub(crate) async fn key_down(&self, key: &str) -> Result<(), Arc<Error>> {
122        let mut args = HashMap::new();
123        args.insert("key", key);
124        let _ = send_message!(self, "keyboardDown", args);
125        Ok(())
126    }
127
128    pub(crate) async fn key_up(&self, key: &str) -> Result<(), Arc<Error>> {
129        let mut args = HashMap::new();
130        args.insert("key", key);
131        let _ = send_message!(self, "keyboardUp", args);
132        Ok(())
133    }
134
135    pub(crate) async fn key_input_text(&self, text: &str) -> Result<(), Arc<Error>> {
136        let mut args = HashMap::new();
137        args.insert("text", text);
138        let _ = send_message!(self, "keyboardInsertText", args);
139        Ok(())
140    }
141
142    pub(crate) async fn key_type(&self, text: &str, delay: Option<f64>) -> Result<(), Arc<Error>> {
143        #[skip_serializing_none]
144        #[derive(Serialize)]
145        #[serde(rename_all = "camelCase")]
146        struct Args<'b> {
147            text: &'b str,
148            delay: Option<f64>
149        }
150        let args = Args { text, delay };
151        let _ = send_message!(self, "keyboardInsertText", args);
152        Ok(())
153    }
154
155    pub(crate) async fn key_press(&self, text: &str, delay: Option<f64>) -> Result<(), Arc<Error>> {
156        #[skip_serializing_none]
157        #[derive(Serialize)]
158        #[serde(rename_all = "camelCase")]
159        struct Args<'b> {
160            text: &'b str,
161            delay: Option<f64>
162        }
163        let args = Args { text, delay };
164        let _ = send_message!(self, "keyboardPress", args);
165        Ok(())
166    }
167
168    pub(crate) async fn screen_tap(&self, x: f64, y: f64) -> Result<(), Arc<Error>> {
169        #[derive(Serialize)]
170        #[serde(rename_all = "camelCase")]
171        struct Args {
172            x: f64,
173            y: f64
174        }
175        let args = Args { x, y };
176        let _ = send_message!(self, "touchscreenTap", args);
177        Ok(())
178    }
179
180    pub(crate) async fn mouse_move(
181        &self,
182        x: f64,
183        y: f64,
184        steps: Option<i32>
185    ) -> Result<(), Arc<Error>> {
186        #[skip_serializing_none]
187        #[derive(Serialize)]
188        #[serde(rename_all = "camelCase")]
189        struct Args {
190            x: f64,
191            y: f64,
192            steps: Option<i32>
193        }
194        let args = Args { x, y, steps };
195        let _ = send_message!(self, "mouseMove", args);
196        Ok(())
197    }
198
199    mouse_down! {mouse_down, "mouseDown"}
200    mouse_down! {mouse_up, "mouseUp"}
201
202    pub(crate) async fn mouse_click(&self, args: MouseClickArgs) -> Result<(), Arc<Error>> {
203        let _ = send_message!(self, "mouseClick", args);
204        Ok(())
205    }
206
207    pub(crate) async fn mouse_dblclick(&self, args: MouseClickArgs) -> Result<(), Arc<Error>> {
208        let args = MouseClickArgs {
209            click_count: Some(2),
210            ..args
211        };
212        self.mouse_click(args).await
213    }
214
215    pub(crate) async fn accessibility_snapshot(
216        &self,
217        args: AccessibilitySnapshotArgs
218    ) -> ArcResult<Option<AccessibilitySnapshotResponse>> {
219        let v = send_message!(self, "accessibilitySnapshot", args);
220        let first = match first(&v) {
221            None => return Ok(None),
222            Some(x) => x
223        };
224        let res: AccessibilitySnapshotResponse =
225            serde_json::from_value((*first).clone()).map_err(Error::Serde)?;
226        Ok(Some(res))
227    }
228
229    pub(crate) async fn bring_to_front(&self) -> ArcResult<()> {
230        let _ = send_message!(self, "bringToFront", Map::new());
231        Ok(())
232    }
233
234    pub(crate) async fn add_init_script(&self, source: &str) -> ArcResult<()> {
235        let mut args = HashMap::new();
236        args.insert("source", source);
237        let _ = send_message!(self, "addInitScript", args);
238        Ok(())
239    }
240
241    pub(crate) async fn pdf(
242        &self,
243        args: PdfArgs<'_, '_, '_, '_, '_, '_, '_, '_, '_, '_>
244    ) -> ArcResult<Vec<u8>> {
245        let path = args.path.clone();
246        let v = send_message!(self, "pdf", args);
247        let b64 = only_str(&v)?;
248        let bytes = base64::decode(b64).map_err(Error::InvalidBase64)?;
249        may_save(path.as_deref(), &bytes)?;
250        Ok(bytes)
251    }
252
253    pub(crate) async fn close(&self, run_before_unload: Option<bool>) -> Result<(), Arc<Error>> {
254        #[skip_serializing_none]
255        #[derive(Serialize)]
256        #[serde(rename_all = "camelCase")]
257        struct Args {
258            run_before_unload: Option<bool>
259        }
260        let args = Args { run_before_unload };
261        let _ = send_message!(self, "close", args);
262        Ok(())
263    }
264
265    pub(crate) async fn screenshot(&self, args: ScreenshotArgs) -> ArcResult<Vec<u8>> {
266        let path = args.path.clone();
267        let v = send_message!(self, "screenshot", args);
268        let b64 = only_str(&v)?;
269        let bytes = base64::decode(b64).map_err(Error::InvalidBase64)?;
270        may_save(path.as_deref(), &bytes)?;
271        Ok(bytes)
272    }
273
274    pub(crate) async fn emulate_media(&self, args: EmulateMediaArgs) -> ArcResult<()> {
275        let _ = send_message!(self, "emulateMedia", args);
276        Ok(())
277    }
278
279    pub(crate) async fn opener(&self) -> ArcResult<Option<Weak<Page>>> {
280        let v = send_message!(self, "opener", Map::new());
281        let guid = match as_only_guid(&v) {
282            Some(g) => g,
283            None => return Ok(None)
284        };
285        let p = get_object!(self.context()?.lock().unwrap(), guid, Page)?;
286        Ok(Some(p))
287    }
288
289    pub(crate) async fn set_extra_http_headers<T>(&self, headers: T) -> ArcResult<()>
290    where
291        T: IntoIterator<Item = (String, String)>
292    {
293        #[derive(Serialize)]
294        #[serde(rename_all = "camelCase")]
295        struct Args {
296            headers: Vec<Header>
297        }
298        let args = Args {
299            headers: headers.into_iter().map(Header::from).collect()
300        };
301        let _ = send_message!(self, "setExtraHTTPHeaders", args);
302        Ok(())
303    }
304}
305
306// mutable
307impl Page {
308    pub(crate) fn viewport_size(&self) -> Option<Viewport> {
309        self.var.lock().unwrap().viewport.clone()
310    }
311
312    pub(crate) async fn set_viewport_size(&self, viewport_size: Viewport) -> ArcResult<()> {
313        #[derive(Debug, Serialize)]
314        #[serde(rename_all = "camelCase")]
315        struct Args {
316            viewport_size: Viewport
317        }
318        let args = Args {
319            viewport_size: viewport_size.clone()
320        };
321        let _ = send_message!(self, "setViewportSize", args);
322        self.var.lock().unwrap().viewport = Some(viewport_size);
323        Ok(())
324    }
325
326    pub(crate) fn frames(&self) -> Vec<Weak<Frame>> { self.var.lock().unwrap().frames.clone() }
327
328    pub(crate) fn default_timeout(&self) -> u32 {
329        let this = self.var.lock().unwrap().timeout;
330        let parent = || {
331            self.browser_context
332                .upgrade()
333                .map(|c| c.default_timeout())
334                .unwrap_or(Self::DEFAULT_TIMEOUT)
335        };
336        this.unwrap_or_else(parent)
337    }
338
339    pub(crate) fn default_navigation_timeout(&self) -> u32 {
340        let this = self.var.lock().unwrap().navigation_timeout;
341        let parent = || {
342            self.browser_context
343                .upgrade()
344                .map(|c| c.default_navigation_timeout())
345                .unwrap_or(Self::DEFAULT_TIMEOUT)
346        };
347        this.unwrap_or_else(parent)
348    }
349
350    pub(crate) async fn set_default_timeout(&self, timeout: u32) -> ArcResult<()> {
351        let mut args = Map::new();
352        args.insert("timeout".into(), timeout.into());
353        let _ = send_message!(self, "setDefaultTimeoutNoReply", args);
354        self.var.lock().unwrap().timeout = Some(timeout);
355        Ok(())
356    }
357
358    pub(crate) async fn set_default_navigation_timeout(&self, timeout: u32) -> ArcResult<()> {
359        let mut args = Map::new();
360        args.insert("timeout".into(), timeout.into());
361        let _ = send_message!(self, "setDefaultNavigationTimeoutNoReply", args);
362        self.var.lock().unwrap().navigation_timeout = Some(timeout);
363        Ok(())
364    }
365
366    pub(crate) fn on_frame_navigated(&self, f: Weak<Frame>) {
367        self.emit_event(Evt::FrameNavigated(f));
368    }
369
370    pub(crate) fn set_video(&self, video: Video) -> Result<(), Error> {
371        self.var.lock().unwrap().video = Some(video);
372        Ok(())
373    }
374
375    pub(crate) fn video(&self) -> Option<Video> { self.var.lock().unwrap().video.clone() }
376
377    fn on_close(&self, ctx: &Context) -> Result<(), Error> {
378        let bc = match self.browser_context().upgrade() {
379            None => return Ok(()),
380            Some(b) => b
381        };
382        let this = get_object!(ctx, self.guid(), Page)?;
383        bc.remove_page(&this);
384        self.emit_event(Evt::Close);
385        Ok(())
386    }
387
388    fn on_frame_attached(&self, ctx: &Context, guid: Str<Guid>) -> Result<(), Error> {
389        let this = get_object!(ctx, self.guid(), Page)?;
390        let f = get_object!(ctx, &guid, Frame)?;
391        upgrade(&f)?.set_page(this);
392        self.var.lock().unwrap().frames.push(f.clone());
393        self.emit_event(Evt::FrameAttached(f));
394        Ok(())
395    }
396
397    fn on_frame_detached(&self, ctx: &Context, guid: Str<Guid>) -> Result<(), Error> {
398        let frames = &mut self.var.lock().unwrap().frames;
399        *frames = frames
400            .iter()
401            .filter(|w| w.upgrade().map(|a| a.guid() != guid).unwrap_or(false))
402            .cloned()
403            .collect();
404        let f = get_object!(ctx, &guid, Frame)?;
405        self.emit_event(Evt::FrameDetached(f));
406        Ok(())
407    }
408
409    fn on_request_failed(&self, ctx: &Context, params: Map<String, Value>) -> Result<(), Error> {
410        #[derive(Debug, Deserialize)]
411        #[serde(rename_all = "camelCase")]
412        struct De {
413            request: OnlyGuid,
414            response_end_timing: f64,
415            failure_text: Option<String>
416        }
417        let De {
418            request: OnlyGuid { guid },
419            response_end_timing,
420            failure_text
421        } = serde_json::from_value(params.into())?;
422        let request = get_object!(ctx, &guid, Request)?;
423        let req = upgrade(&request)?;
424        req.set_failure(failure_text);
425        req.set_response_end(response_end_timing);
426        self.emit_event(Evt::RequestFailed(request));
427        Ok(())
428    }
429
430    fn on_request_finished(&self, ctx: &Context, params: Map<String, Value>) -> Result<(), Error> {
431        #[derive(Debug, Deserialize)]
432        #[serde(rename_all = "camelCase")]
433        struct De {
434            request: OnlyGuid,
435            response_end_timing: f64
436        }
437        let De {
438            request: OnlyGuid { guid },
439            response_end_timing
440        } = serde_json::from_value(params.into())?;
441        let request = get_object!(ctx, &guid, Request)?;
442        let req = upgrade(&request)?;
443        req.set_response_end(response_end_timing);
444        self.emit_event(Evt::RequestFinished(request));
445        Ok(())
446    }
447
448    pub(crate) fn workers(&self) -> Vec<Weak<Worker>> { self.var.lock().unwrap().workers.clone() }
449
450    fn push_worker(&self, worker: Weak<Worker>) { self.var.lock().unwrap().workers.push(worker); }
451
452    pub(crate) fn remove_worker(&self, worker: &Weak<Worker>) {
453        let workers = &mut self.var.lock().unwrap().workers;
454        workers.remove_one(|w| w.ptr_eq(worker));
455    }
456
457    fn on_worker(&self, ctx: &Context, worker: Weak<Worker>) -> Result<(), Error> {
458        self.push_worker(worker.clone());
459        let this = get_object!(ctx, self.guid(), Page)?;
460        upgrade(&worker)?.set_page(this);
461        self.emit_event(Evt::Worker(worker));
462        Ok(())
463    }
464
465    fn on_download(&self, ctx: &Context, params: Map<String, Value>) -> Result<(), Error> {
466        #[derive(Deserialize)]
467        #[serde(rename_all = "camelCase")]
468        struct De {
469            url: String,
470            suggested_filename: String,
471            artifact: OnlyGuid
472        }
473        let De {
474            url,
475            suggested_filename,
476            artifact: OnlyGuid { guid }
477        } = serde_json::from_value(params.into())?;
478        let artifact = get_object!(ctx, &guid, Artifact)?;
479        // TODO: set_is_remote
480        // artifactObject._isRemote = !!this._browserContext._browser && this._browserContext._browser._isRemote;
481        let download = Download::new(artifact, url, suggested_filename);
482        self.emit_event(Evt::Download(Arc::new(download)));
483        Ok(())
484    }
485
486    fn on_video(&self, ctx: &Context, params: Map<String, Value>) -> Result<(), Error> {
487        let v = params.into();
488        let guid = only_guid(&v)?;
489        let artifact = get_object!(ctx, guid, Artifact)?;
490        let video = Video::new(artifact);
491        self.set_video(video.clone())?;
492        self.emit_event(Evt::Video(video));
493        Ok(())
494    }
495
496    fn on_file_chooser(&self, ctx: &Context, params: Map<String, Value>) -> Result<(), Error> {
497        #[derive(Deserialize)]
498        #[serde(rename_all = "camelCase")]
499        struct De {
500            element: OnlyGuid,
501            is_multiple: bool
502        }
503        let De {
504            element: OnlyGuid { guid },
505            is_multiple
506        } = serde_json::from_value(params.into())?;
507        let element = get_object!(ctx, &guid, ElementHandle)?;
508        let this = get_object!(ctx, self.guid(), Page)?;
509        let file_chooser = FileChooser::new(this, element, is_multiple);
510        // self.emit_event(Evt::FileChooser(file_chooser));
511        Ok(())
512    }
513}
514
515impl RemoteObject for Page {
516    fn channel(&self) -> &ChannelOwner { &self.channel }
517    fn channel_mut(&mut self) -> &mut ChannelOwner { &mut self.channel }
518
519    fn handle_event(
520        &self,
521        ctx: &Context,
522        method: Str<Method>,
523        params: Map<String, Value>
524    ) -> Result<(), Error> {
525        match method.as_str() {
526            "close" => self.on_close(ctx)?,
527            "frameattached" => {
528                let first = first_object(&params).ok_or(Error::InvalidParams)?;
529                let OnlyGuid { guid } = serde_json::from_value((*first).clone())?;
530                self.on_frame_attached(ctx, guid)?;
531            }
532            "framedetached" => {
533                let first = first_object(&params).ok_or(Error::InvalidParams)?;
534                let OnlyGuid { guid } = serde_json::from_value((*first).clone())?;
535                self.on_frame_detached(ctx, guid)?;
536            }
537            "load" => self.emit_event(Evt::Load),
538            "domcontentloaded" => self.emit_event(Evt::DomContentLoaded),
539            "crash" => self.emit_event(Evt::Crash),
540            "console" => {
541                let first = first_object(&params).ok_or(Error::InvalidParams)?;
542                let OnlyGuid { guid } = serde_json::from_value((*first).clone())?;
543                let console = get_object!(ctx, &guid, ConsoleMessage)?;
544                self.emit_event(Evt::Console(console));
545            }
546            "request" => {
547                let first = first_object(&params).ok_or(Error::InvalidParams)?;
548                let OnlyGuid { guid } = serde_json::from_value((*first).clone())?;
549                let request = get_object!(ctx, &guid, Request)?;
550                self.emit_event(Evt::Request(request));
551            }
552            "requestfailed" => self.on_request_failed(ctx, params)?,
553            "requestfinished" => self.on_request_finished(ctx, params)?,
554            "response" => {
555                let first = first_object(&params).ok_or(Error::InvalidParams)?;
556                let OnlyGuid { guid } = serde_json::from_value((*first).clone())?;
557                let response = get_object!(ctx, &guid, Response)?;
558                self.emit_event(Evt::Response(response));
559            }
560            "popup" => {
561                let first = first_object(&params).ok_or(Error::InvalidParams)?;
562                let OnlyGuid { guid } = serde_json::from_value((*first).clone())?;
563                let page = get_object!(ctx, &guid, Page)?;
564                self.emit_event(Evt::Popup(page));
565            }
566            "websocket" => {
567                let first = first_object(&params).ok_or(Error::InvalidParams)?;
568                let OnlyGuid { guid } = serde_json::from_value((*first).clone())?;
569                let websocket = get_object!(ctx, &guid, WebSocket)?;
570                self.emit_event(Evt::WebSocket(websocket));
571            }
572            "worker" => {
573                let first = first_object(&params).ok_or(Error::InvalidParams)?;
574                let OnlyGuid { guid } = serde_json::from_value((*first).clone())?;
575                let worker = get_object!(ctx, &guid, Worker)?;
576                self.on_worker(ctx, worker)?;
577            }
578            "download" => self.on_download(ctx, params)?,
579            "video" => self.on_video(ctx, params)?,
580            "filechooser" => self.on_file_chooser(ctx, params)?,
581            _ => {}
582        }
583        Ok(())
584    }
585}
586
587#[derive(Debug, Clone)]
588pub(crate) enum Evt {
589    Close,
590    Crash,
591    Console(Weak<ConsoleMessage>),
592    /// Not Implemented Yet
593    Dialog,
594    Download(Arc<Download>),
595    /// Not Implemented Yet
596    // FileChooser(FileChooser),
597    DomContentLoaded,
598    /// Not Implemented Yet
599    PageError,
600    Request(Weak<Request>),
601    Response(Weak<Response>),
602    RequestFailed(Weak<Request>),
603    RequestFinished(Weak<Request>),
604    FrameAttached(Weak<Frame>),
605    FrameDetached(Weak<Frame>),
606    FrameNavigated(Weak<Frame>),
607    Load,
608    Popup(Weak<Page>),
609    WebSocket(Weak<WebSocket>),
610    Worker(Weak<Worker>),
611    Video(Video)
612}
613
614impl EventEmitter for Page {
615    type Event = Evt;
616    fn tx(&self) -> Option<broadcast::Sender<Self::Event>> { self.tx.lock().unwrap().clone() }
617    fn set_tx(&self, tx: broadcast::Sender<Self::Event>) { *self.tx.lock().unwrap() = Some(tx); }
618}
619
620#[derive(Debug, Clone, Copy, PartialEq)]
621pub enum EventType {
622    Close,
623    Crash,
624    Console,
625    Dialog,
626    Download,
627    // FileChooser,
628    DomContentLoaded,
629    PageError,
630    Request,
631    Response,
632    RequestFailed,
633    RequestFinished,
634    FrameAttached,
635    FrameDetached,
636    FrameNavigated,
637    Load,
638    Popup,
639    WebSocket,
640    Worker,
641    Video
642}
643
644impl IsEvent for Evt {
645    type EventType = EventType;
646
647    fn event_type(&self) -> Self::EventType {
648        match self {
649            Self::Close => EventType::Close,
650            Self::Crash => EventType::Crash,
651            Self::Console(_) => EventType::Console,
652            Self::Dialog => EventType::Dialog,
653            Self::Download(_) => EventType::Download,
654            // Self::FileChooser(_) => EventType::FileChooser,
655            Self::DomContentLoaded => EventType::DomContentLoaded,
656            Self::PageError => EventType::PageError,
657            Self::Request(_) => EventType::Request,
658            Self::Response(_) => EventType::Response,
659            Self::RequestFailed(_) => EventType::RequestFailed,
660            Self::RequestFinished(_) => EventType::RequestFinished,
661            Self::FrameAttached(_) => EventType::FrameAttached,
662            Self::FrameDetached(_) => EventType::FrameDetached,
663            Self::FrameNavigated(_) => EventType::FrameNavigated,
664            Self::Load => EventType::Load,
665            Self::Popup(_) => EventType::Popup,
666            Self::WebSocket(_) => EventType::WebSocket,
667            Self::Worker(_) => EventType::Worker,
668            Self::Video(_) => EventType::Video
669        }
670    }
671}
672
673#[derive(Deserialize)]
674#[serde(rename_all = "camelCase")]
675struct Initializer {
676    main_frame: OnlyGuid,
677    #[serde(rename = "viewportSize")]
678    viewport: Option<Viewport>
679}
680
681#[skip_serializing_none]
682#[derive(Serialize)]
683#[serde(rename_all = "camelCase")]
684pub(crate) struct MouseClickArgs {
685    x: f64,
686    y: f64,
687    pub(crate) delay: Option<f64>,
688    pub(crate) button: Option<MouseButton>,
689    pub(crate) click_count: Option<i32>
690}
691
692impl MouseClickArgs {
693    pub(crate) fn new(x: f64, y: f64) -> Self {
694        Self {
695            x,
696            y,
697            delay: None,
698            button: None,
699            click_count: None
700        }
701    }
702}
703
704#[skip_serializing_none]
705#[derive(Serialize, Default)]
706#[serde(rename_all = "camelCase")]
707pub(crate) struct AccessibilitySnapshotArgs {
708    pub(crate) interesting_only: Option<bool>,
709    pub(crate) root: Option<OnlyGuid>
710}
711
712#[derive(Debug, Deserialize, PartialEq)]
713#[serde(rename_all = "camelCase")]
714pub struct AccessibilitySnapshotResponse {
715    pub role: String,
716    pub name: String,
717    pub value: Option<Val>,
718    pub description: Option<String>,
719    pub keyshortcuts: Option<String>,
720    pub roledescription: Option<String>,
721    pub valuetext: Option<String>,
722    pub disabled: Option<bool>,
723    pub expanded: Option<bool>,
724    pub focused: Option<bool>,
725    pub modal: Option<bool>,
726    pub multiline: Option<bool>,
727    pub multiselectable: Option<bool>,
728    pub readonly: Option<bool>,
729    pub required: Option<bool>,
730    pub selected: Option<bool>,
731    pub checked: Option<Mixed>,
732    pub pressed: Option<Mixed>,
733    pub level: Option<i64>,
734    pub valuemin: Option<f64>,
735    pub valuemax: Option<f64>,
736    pub autocomplete: Option<String>,
737    pub haspopup: Option<String>,
738    pub invalid: Option<String>,
739    pub orientation: Option<String>,
740    #[serde(default)]
741    pub children: Vec<AccessibilitySnapshotResponse>
742}
743
744#[derive(Debug, Deserialize, PartialEq)]
745pub enum Val {
746    String(String),
747    Number(f64)
748}
749#[derive(Debug, Deserialize, PartialEq)]
750pub enum Mixed {
751    Mixed,
752    Bool(bool)
753}
754
755#[skip_serializing_none]
756#[derive(Serialize, Default)]
757#[serde(rename_all = "camelCase")]
758pub(crate) struct ReloadArgs {
759    pub(crate) timeout: Option<f64>,
760    pub(crate) wait_until: Option<DocumentLoadState>
761}
762
763#[skip_serializing_none]
764#[derive(Serialize, Default)]
765#[serde(rename_all = "camelCase")]
766pub(crate) struct PdfArgs<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i, 'j> {
767    pub(crate) scale: Option<f64>,
768    pub(crate) display_header_footer: Option<bool>,
769    pub(crate) header_template: Option<&'a str>,
770    pub(crate) footer_template: Option<&'b str>,
771    pub(crate) print_background: Option<bool>,
772    pub(crate) landscape: Option<bool>,
773    pub(crate) page_ranges: Option<&'c str>,
774    pub(crate) format: Option<&'d str>,
775    pub(crate) width: Option<Length<'e>>,
776    pub(crate) height: Option<Length<'f>>,
777    #[serde(rename = "preferCSSPageSize")]
778    pub(crate) prefer_css_page_size: Option<bool>,
779    pub(crate) margin: Option<PdfMargins<'g, 'h, 'i, 'j>>,
780    pub(crate) path: Option<PathBuf>
781}
782
783#[skip_serializing_none]
784#[derive(Serialize, Default)]
785#[serde(rename_all = "camelCase")]
786pub(crate) struct ScreenshotArgs {
787    pub(crate) timeout: Option<f64>,
788    pub(crate) r#type: Option<ScreenshotType>,
789    pub(crate) quality: Option<i32>,
790    pub(crate) omit_background: Option<bool>,
791    pub(crate) full_page: Option<bool>,
792    pub(crate) clip: Option<FloatRect>,
793    pub(crate) path: Option<PathBuf>
794}
795
796#[skip_serializing_none]
797#[derive(Serialize, Default)]
798#[serde(rename_all = "camelCase")]
799pub(crate) struct EmulateMediaArgs {
800    pub(crate) media: Option<Media>,
801    pub(crate) color_scheme: Option<ColorScheme>
802}
803
804#[derive(Serialize)]
805#[serde(rename_all = "lowercase")]
806pub enum Media {
807    /// Reset emulating
808    Null,
809    Print,
810    Screen
811}