Skip to main content

script/dom/testing/
servotestutils.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5// check-tidy: no specs after this line
6
7use backtrace::Backtrace;
8use dom_struct::dom_struct;
9use js::context::JSContext;
10use layout_api::ReflowPhasesRun;
11use script_bindings::codegen::GenericBindings::WindowBinding::WindowMethods;
12use script_bindings::domstring::DOMString;
13use script_bindings::reflector::Reflector;
14use script_bindings::root::DomRoot;
15use servo_base::Epoch;
16use time::Duration;
17
18use crate::dom::bindings::codegen::Bindings::ServoTestUtilsBinding::ServoTestUtilsMethods;
19use crate::dom::globalscope::GlobalScope;
20use crate::dom::layoutresult::LayoutResult;
21use crate::dom::types::AccessibilityUpdateResult;
22
23#[dom_struct]
24pub(crate) struct ServoTestUtils {
25    reflector_: Reflector,
26}
27
28impl ServoTestUtilsMethods<crate::DomTypeHolder> for ServoTestUtils {
29    fn AdvanceClock(global: &GlobalScope, ms: i32) {
30        global
31            .as_window()
32            .advance_animation_clock(Duration::milliseconds(ms as i64));
33    }
34
35    #[expect(unsafe_code)]
36    fn CrashHard(_: &GlobalScope) {
37        unsafe { std::ptr::null_mut::<i32>().write(42) }
38    }
39
40    fn ForceLayout(cx: &mut JSContext, global: &GlobalScope) -> DomRoot<LayoutResult> {
41        let (phases_run, statistics) = global.as_window().Document().update_the_rendering(cx);
42
43        let mut phases = Vec::new();
44        if phases_run.contains(ReflowPhasesRun::RanLayout) {
45            phases.push(DOMString::from("RanLayout"))
46        }
47        if phases_run.contains(ReflowPhasesRun::BuiltStackingContextTree) {
48            phases.push(DOMString::from("BuiltStackingContextTree"))
49        }
50        if phases_run.contains(ReflowPhasesRun::BuiltDisplayList) {
51            phases.push(DOMString::from("BuiltDisplayList"))
52        }
53        if phases_run.contains(ReflowPhasesRun::UpdatedScrollNodeOffset) {
54            phases.push(DOMString::from("UpdatedScrollNodeOffset"))
55        }
56        if phases_run.contains(ReflowPhasesRun::UpdatedImageData) {
57            phases.push(DOMString::from("UpdatedImageData"))
58        }
59
60        LayoutResult::new(
61            cx,
62            global,
63            phases,
64            statistics.rebuilt_fragment_count,
65            statistics.restyle_fragment_count,
66            statistics.only_descendants_changed_count,
67        )
68    }
69
70    fn Js_backtrace(_: &GlobalScope) {
71        println!("Current JS stack:");
72        let rust_stack = Backtrace::new();
73        println!("Current Rust stack:\n{:?}", rust_stack);
74    }
75
76    fn Panic(_: &GlobalScope) {
77        panic!("explicit panic from script")
78    }
79
80    fn EnsureAccessibilityActive(global: &GlobalScope) {
81        let window = global.as_window();
82        window
83            .layout()
84            .set_accessibility_active(true, Epoch::default());
85    }
86
87    fn ForceAccessibilityUpdate(
88        cx: &mut JSContext,
89        global: &GlobalScope,
90    ) -> DomRoot<AccessibilityUpdateResult> {
91        let window = global.as_window();
92        window.layout().set_needs_accessibility_update();
93        let (_, statistics) = window.Document().update_the_rendering(cx);
94
95        AccessibilityUpdateResult::new(
96            cx,
97            global,
98            statistics.nodes_updated_from_dom,
99            statistics.nodes_updated_from_tree,
100            statistics.nodes_in_tree_update,
101        )
102    }
103}