mirror of
https://github.com/servo/servo.git
synced 2025-09-27 23:30:08 +01:00
script: Chain up keyboard scrolling to parent <iframe>
s (#39469)
When an `<iframe>` cannot scroll because the size of the frame is greater than or equal to the size of page contents, chain up the keyboard scroll operation to the parent frame. Testing: A new Servo-only WPT tests is added, though needs to be manually run with `--product servodriver`. Signed-off-by: Martin Robinson <mrobinson@igalia.com> Co-authored-by: Delan Azabani <dazabani@igalia.com>
This commit is contained in:
parent
75e32ba5a4
commit
ffdb7d3663
23 changed files with 406 additions and 132 deletions
|
@ -33,7 +33,10 @@ use euclid::default::{Rect, Size2D};
|
|||
use html5ever::{LocalName, Namespace, QualName, local_name, ns};
|
||||
use hyper_serde::Serde;
|
||||
use js::rust::{HandleObject, HandleValue, MutableHandleValue};
|
||||
use layout_api::{PendingRestyle, ReflowGoal, ReflowPhasesRun, RestyleReason, TrustedNodeAddress};
|
||||
use layout_api::{
|
||||
PendingRestyle, ReflowGoal, ReflowPhasesRun, RestyleReason, ScrollContainerQueryFlags,
|
||||
TrustedNodeAddress,
|
||||
};
|
||||
use metrics::{InteractiveFlag, InteractiveWindow, ProgressiveWebMetrics};
|
||||
use net_traits::CookieSource::NonHTTP;
|
||||
use net_traits::CoreResourceMsg::{GetCookiesForUrl, SetCookiesForUrl};
|
||||
|
@ -173,7 +176,7 @@ use crate::dom::processinginstruction::ProcessingInstruction;
|
|||
use crate::dom::promise::Promise;
|
||||
use crate::dom::range::Range;
|
||||
use crate::dom::resizeobserver::{ResizeObservationDepth, ResizeObserver};
|
||||
use crate::dom::scrolling_box::{ScrollingBox, ScrollingBoxSource};
|
||||
use crate::dom::scrolling_box::ScrollingBox;
|
||||
use crate::dom::selection::Selection;
|
||||
use crate::dom::servoparser::ServoParser;
|
||||
use crate::dom::shadowroot::ShadowRoot;
|
||||
|
@ -4447,8 +4450,10 @@ impl Document {
|
|||
self.active_sandboxing_flag_set.set(flags)
|
||||
}
|
||||
|
||||
pub(crate) fn viewport_scrolling_box(&self) -> ScrollingBox {
|
||||
ScrollingBox::new(ScrollingBoxSource::Viewport(DomRoot::from_ref(self)))
|
||||
pub(crate) fn viewport_scrolling_box(&self, flags: ScrollContainerQueryFlags) -> ScrollingBox {
|
||||
self.window()
|
||||
.scrolling_box_query(None, flags)
|
||||
.expect("We should always have a ScrollingBox for the Viewport")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ use std::rc::Rc;
|
|||
use std::time::{Duration, Instant};
|
||||
|
||||
use base::generic_channel;
|
||||
use constellation_traits::ScriptToConstellationMessage;
|
||||
use constellation_traits::{KeyboardScroll, ScriptToConstellationMessage};
|
||||
use embedder_traits::{
|
||||
Cursor, EditingActionEvent, EmbedderMsg, GamepadEvent as EmbedderGamepadEvent,
|
||||
GamepadSupportedHapticEffects, GamepadUpdateType, ImeEvent, InputEvent,
|
||||
|
@ -20,6 +20,7 @@ use embedder_traits::{
|
|||
};
|
||||
use euclid::{Point2D, Vector2D};
|
||||
use ipc_channel::ipc;
|
||||
use js::jsapi::JSAutoRealm;
|
||||
use keyboard_types::{Code, Key, KeyState, Modifiers, NamedKey};
|
||||
use layout_api::{ScrollContainerQueryFlags, node_id_from_scroll_id};
|
||||
use script_bindings::codegen::GenericBindings::DocumentBinding::DocumentMethods;
|
||||
|
@ -31,6 +32,7 @@ use script_bindings::codegen::GenericBindings::TouchBinding::TouchMethods;
|
|||
use script_bindings::codegen::GenericBindings::WindowBinding::{ScrollBehavior, WindowMethods};
|
||||
use script_bindings::inheritance::Castable;
|
||||
use script_bindings::num::Finite;
|
||||
use script_bindings::reflector::DomObject;
|
||||
use script_bindings::root::{Dom, DomRoot, DomSlice};
|
||||
use script_bindings::script_runtime::CanGc;
|
||||
use script_bindings::str::DOMString;
|
||||
|
@ -48,7 +50,7 @@ use crate::dom::event::{EventBubbles, EventCancelable, EventComposed, EventDefau
|
|||
use crate::dom::gamepad::gamepad::{Gamepad, contains_user_gesture};
|
||||
use crate::dom::gamepad::gamepadevent::GamepadEventType;
|
||||
use crate::dom::inputevent::HitTestResult;
|
||||
use crate::dom::node::{self, Node, ShadowIncluding};
|
||||
use crate::dom::node::{self, Node, NodeTraits, ShadowIncluding};
|
||||
use crate::dom::pointerevent::PointerId;
|
||||
use crate::dom::scrolling_box::ScrollingBoxAxis;
|
||||
use crate::dom::types::{
|
||||
|
@ -1486,60 +1488,94 @@ impl DocumentEventHandler {
|
|||
if !event.modifiers().is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
let scroll_axis = match event.key() {
|
||||
Key::Named(
|
||||
NamedKey::Home |
|
||||
NamedKey::End |
|
||||
NamedKey::PageDown |
|
||||
NamedKey::PageUp |
|
||||
NamedKey::ArrowUp |
|
||||
NamedKey::ArrowDown,
|
||||
) => ScrollingBoxAxis::Y,
|
||||
Key::Named(NamedKey::ArrowLeft | NamedKey::ArrowRight) => ScrollingBoxAxis::X,
|
||||
let scroll = match event.key() {
|
||||
Key::Named(NamedKey::ArrowDown) => KeyboardScroll::Down,
|
||||
Key::Named(NamedKey::ArrowLeft) => KeyboardScroll::Left,
|
||||
Key::Named(NamedKey::ArrowRight) => KeyboardScroll::Right,
|
||||
Key::Named(NamedKey::ArrowUp) => KeyboardScroll::Up,
|
||||
Key::Named(NamedKey::End) => KeyboardScroll::End,
|
||||
Key::Named(NamedKey::Home) => KeyboardScroll::Home,
|
||||
Key::Named(NamedKey::PageDown) => KeyboardScroll::PageDown,
|
||||
Key::Named(NamedKey::PageUp) => KeyboardScroll::PageUp,
|
||||
_ => return,
|
||||
};
|
||||
self.do_keyboard_scroll(scroll);
|
||||
}
|
||||
|
||||
pub(crate) fn do_keyboard_scroll(&self, scroll: KeyboardScroll) {
|
||||
let scroll_axis = match scroll {
|
||||
KeyboardScroll::Left | KeyboardScroll::Right => ScrollingBoxAxis::X,
|
||||
_ => ScrollingBoxAxis::Y,
|
||||
};
|
||||
|
||||
let document = self.window.Document();
|
||||
let mut scrolling_box = document
|
||||
.get_focused_element()
|
||||
.or(self.most_recently_clicked_element.get())
|
||||
.and_then(|element| element.scrolling_box(ScrollContainerQueryFlags::Inclusive))
|
||||
.unwrap_or_else(|| document.viewport_scrolling_box());
|
||||
.unwrap_or_else(|| {
|
||||
document.viewport_scrolling_box(ScrollContainerQueryFlags::Inclusive)
|
||||
});
|
||||
|
||||
while !scrolling_box.can_keyboard_scroll_in_axis(scroll_axis) {
|
||||
// Always fall back to trying to scroll the entire document.
|
||||
if scrolling_box.is_viewport() {
|
||||
break;
|
||||
}
|
||||
let parent = scrolling_box
|
||||
.parent()
|
||||
.unwrap_or_else(|| document.viewport_scrolling_box());
|
||||
let parent = scrolling_box.parent().unwrap_or_else(|| {
|
||||
document.viewport_scrolling_box(ScrollContainerQueryFlags::Inclusive)
|
||||
});
|
||||
scrolling_box = parent;
|
||||
}
|
||||
|
||||
// If this is the viewport and we cannot scroll, try to ask a parent viewport to scroll,
|
||||
// if we are inside an `<iframe>`.
|
||||
if !scrolling_box.can_keyboard_scroll_in_axis(scroll_axis) {
|
||||
assert!(scrolling_box.is_viewport());
|
||||
|
||||
let window_proxy = document.window().window_proxy();
|
||||
if let Some(iframe) = window_proxy.frame_element() {
|
||||
// When the `<iframe>` is local (in this ScriptThread), we can
|
||||
// synchronously chain up the keyboard scrolling event.
|
||||
let cx = GlobalScope::get_cx();
|
||||
let iframe_window = iframe.owner_window();
|
||||
let _ac = JSAutoRealm::new(*cx, iframe_window.reflector().get_jsobject().get());
|
||||
iframe_window
|
||||
.Document()
|
||||
.event_handler()
|
||||
.do_keyboard_scroll(scroll);
|
||||
} else if let Some(parent_pipeline) = self.window.parent_info() {
|
||||
// Otherwise, if we have a parent (presumably from a different origin)
|
||||
// asynchronously ask the Constellation to forward the event to the parent
|
||||
// pipeline, if we have one.
|
||||
document.window().send_to_constellation(
|
||||
ScriptToConstellationMessage::ForwardKeyboardScroll(parent_pipeline, scroll),
|
||||
);
|
||||
};
|
||||
return;
|
||||
}
|
||||
|
||||
const LINE_HEIGHT: f32 = 76.0;
|
||||
const LINE_WIDTH: f32 = 76.0;
|
||||
|
||||
let current_scroll_offset = scrolling_box.scroll_position();
|
||||
let delta = match event.key() {
|
||||
Key::Named(NamedKey::Home) => Vector2D::new(0.0, -current_scroll_offset.y),
|
||||
Key::Named(NamedKey::End) => Vector2D::new(
|
||||
let delta = match scroll {
|
||||
KeyboardScroll::Home => Vector2D::new(0.0, -current_scroll_offset.y),
|
||||
KeyboardScroll::End => Vector2D::new(
|
||||
0.0,
|
||||
-current_scroll_offset.y + scrolling_box.content_size().height -
|
||||
scrolling_box.size().height,
|
||||
),
|
||||
Key::Named(NamedKey::PageDown) => {
|
||||
KeyboardScroll::PageDown => {
|
||||
Vector2D::new(0.0, scrolling_box.size().height - 2.0 * LINE_HEIGHT)
|
||||
},
|
||||
Key::Named(NamedKey::PageUp) => {
|
||||
KeyboardScroll::PageUp => {
|
||||
Vector2D::new(0.0, 2.0 * LINE_HEIGHT - scrolling_box.size().height)
|
||||
},
|
||||
Key::Named(NamedKey::ArrowUp) => Vector2D::new(0.0, -LINE_HEIGHT),
|
||||
Key::Named(NamedKey::ArrowDown) => Vector2D::new(0.0, LINE_HEIGHT),
|
||||
Key::Named(NamedKey::ArrowLeft) => Vector2D::new(-LINE_WIDTH, 0.0),
|
||||
Key::Named(NamedKey::ArrowRight) => Vector2D::new(LINE_WIDTH, 0.0),
|
||||
_ => return,
|
||||
KeyboardScroll::Up => Vector2D::new(0.0, -LINE_HEIGHT),
|
||||
KeyboardScroll::Down => Vector2D::new(0.0, LINE_HEIGHT),
|
||||
KeyboardScroll::Left => Vector2D::new(-LINE_WIDTH, 0.0),
|
||||
KeyboardScroll::Right => Vector2D::new(LINE_WIDTH, 0.0),
|
||||
};
|
||||
|
||||
scrolling_box.scroll_to(delta + current_scroll_offset, ScrollBehavior::Auto);
|
||||
|
|
|
@ -25,7 +25,7 @@ use html5ever::{LocalName, Namespace, Prefix, QualName, local_name, namespace_pr
|
|||
use js::jsapi::Heap;
|
||||
use js::jsval::JSVal;
|
||||
use js::rust::HandleObject;
|
||||
use layout_api::{LayoutDamage, ScrollContainerQueryFlags, ScrollContainerResponse};
|
||||
use layout_api::{LayoutDamage, ScrollContainerQueryFlags};
|
||||
use net_traits::ReferrerPolicy;
|
||||
use net_traits::request::CorsSettings;
|
||||
use selectors::Element as SelectorsElement;
|
||||
|
@ -161,7 +161,7 @@ use crate::dom::mutationobserver::{Mutation, MutationObserver};
|
|||
use crate::dom::namednodemap::NamedNodeMap;
|
||||
use crate::dom::node::{
|
||||
BindContext, ChildrenMutation, CloneChildrenFlag, LayoutNodeHelpers, Node, NodeDamage,
|
||||
NodeFlags, NodeTraits, ShadowIncluding, UnbindContext, from_untrusted_node_address,
|
||||
NodeFlags, NodeTraits, ShadowIncluding, UnbindContext,
|
||||
};
|
||||
use crate::dom::nodelist::NodeList;
|
||||
use crate::dom::promise::Promise;
|
||||
|
@ -822,22 +822,11 @@ impl Element {
|
|||
.retain(|reg_obs| *reg_obs.observer != *observer)
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
/// Get the [`ScrollingBox`] that contains this element, if one does. `position:
|
||||
/// fixed` elements do not have a containing [`ScrollingBox`].
|
||||
pub(crate) fn scrolling_box(&self, flags: ScrollContainerQueryFlags) -> Option<ScrollingBox> {
|
||||
self.owner_window()
|
||||
.scroll_container_query(self.upcast(), flags)
|
||||
.and_then(|response| match response {
|
||||
ScrollContainerResponse::Viewport => Some(ScrollingBox::new(
|
||||
ScrollingBoxSource::Viewport(self.owner_document()),
|
||||
)),
|
||||
ScrollContainerResponse::Element(parent_node_address, axes_overflow) => {
|
||||
let node = unsafe { from_untrusted_node_address(parent_node_address) };
|
||||
Some(ScrollingBox::new(ScrollingBoxSource::Element(
|
||||
DomRoot::downcast(node)?,
|
||||
axes_overflow,
|
||||
)))
|
||||
},
|
||||
})
|
||||
.scrolling_box_query(Some(self.upcast()), flags)
|
||||
}
|
||||
|
||||
/// <https://drafts.csswg.org/cssom-view/#scroll-a-target-into-view>
|
||||
|
@ -927,7 +916,7 @@ impl Element {
|
|||
let (adjusted_element_top_left, adjusted_element_bottom_right) =
|
||||
match scrolling_box.target() {
|
||||
ScrollingBoxSource::Viewport(_) => (target_top_left, target_bottom_right),
|
||||
ScrollingBoxSource::Element(scrolling_element, _) => {
|
||||
ScrollingBoxSource::Element(scrolling_element) => {
|
||||
let scrolling_padding_rect_top_left = scrolling_element
|
||||
.upcast::<Node>()
|
||||
.padding_box()
|
||||
|
|
|
@ -450,9 +450,12 @@ impl HTMLElementMethods<crate::DomTypeHolder> for HTMLElement {
|
|||
#[allow(unsafe_code)]
|
||||
fn GetScrollParent(&self) -> Option<DomRoot<Element>> {
|
||||
self.owner_window()
|
||||
.scroll_container_query(self.upcast(), ScrollContainerQueryFlags::ForScrollParent)
|
||||
.scroll_container_query(
|
||||
Some(self.upcast()),
|
||||
ScrollContainerQueryFlags::ForScrollParent,
|
||||
)
|
||||
.and_then(|response| match response {
|
||||
ScrollContainerResponse::Viewport => self.owner_document().GetScrollingElement(),
|
||||
ScrollContainerResponse::Viewport(_) => self.owner_document().GetScrollingElement(),
|
||||
ScrollContainerResponse::Element(parent_node_address, _) => {
|
||||
let node = unsafe { from_untrusted_node_address(parent_node_address) };
|
||||
DomRoot::downcast(node)
|
||||
|
|
|
@ -16,6 +16,7 @@ use crate::dom::types::{Document, Element};
|
|||
|
||||
pub(crate) struct ScrollingBox {
|
||||
target: ScrollingBoxSource,
|
||||
overflow: AxesOverflow,
|
||||
cached_content_size: Cell<Option<LayoutSize>>,
|
||||
cached_size: Cell<Option<LayoutSize>>,
|
||||
}
|
||||
|
@ -23,7 +24,7 @@ pub(crate) struct ScrollingBox {
|
|||
/// Represents a scrolling box that can be either an element or the viewport
|
||||
/// <https://drafts.csswg.org/cssom-view/#scrolling-box>
|
||||
pub(crate) enum ScrollingBoxSource {
|
||||
Element(DomRoot<Element>, AxesOverflow),
|
||||
Element(DomRoot<Element>),
|
||||
Viewport(DomRoot<Document>),
|
||||
}
|
||||
|
||||
|
@ -34,9 +35,10 @@ pub(crate) enum ScrollingBoxAxis {
|
|||
}
|
||||
|
||||
impl ScrollingBox {
|
||||
pub(crate) fn new(target: ScrollingBoxSource) -> Self {
|
||||
pub(crate) fn new(target: ScrollingBoxSource, overflow: AxesOverflow) -> Self {
|
||||
Self {
|
||||
target,
|
||||
overflow,
|
||||
cached_content_size: Default::default(),
|
||||
cached_size: Default::default(),
|
||||
}
|
||||
|
@ -52,7 +54,7 @@ impl ScrollingBox {
|
|||
|
||||
pub(crate) fn scroll_position(&self) -> LayoutVector2D {
|
||||
match &self.target {
|
||||
ScrollingBoxSource::Element(element, _) => element
|
||||
ScrollingBoxSource::Element(element) => element
|
||||
.owner_window()
|
||||
.scroll_offset_query(element.upcast::<Node>()),
|
||||
ScrollingBoxSource::Viewport(document) => document.window().scroll_offset(),
|
||||
|
@ -65,7 +67,7 @@ impl ScrollingBox {
|
|||
}
|
||||
|
||||
let (document, node_to_query) = match &self.target {
|
||||
ScrollingBoxSource::Element(element, _) => {
|
||||
ScrollingBoxSource::Element(element) => {
|
||||
(element.owner_document(), Some(element.upcast()))
|
||||
},
|
||||
ScrollingBoxSource::Viewport(document) => (document.clone(), None),
|
||||
|
@ -87,9 +89,7 @@ impl ScrollingBox {
|
|||
}
|
||||
|
||||
let size = match &self.target {
|
||||
ScrollingBoxSource::Element(element, _) => {
|
||||
element.client_rect().size.to_f32().cast_unit()
|
||||
},
|
||||
ScrollingBoxSource::Element(element) => element.client_rect().size.to_f32().cast_unit(),
|
||||
ScrollingBoxSource::Viewport(document) => {
|
||||
document.window().viewport_details().size.cast_unit()
|
||||
},
|
||||
|
@ -100,7 +100,7 @@ impl ScrollingBox {
|
|||
|
||||
pub(crate) fn parent(&self) -> Option<ScrollingBox> {
|
||||
match &self.target {
|
||||
ScrollingBoxSource::Element(element, _) => {
|
||||
ScrollingBoxSource::Element(element) => {
|
||||
element.scrolling_box(ScrollContainerQueryFlags::empty())
|
||||
},
|
||||
ScrollingBoxSource::Viewport(_) => None,
|
||||
|
@ -109,14 +109,14 @@ impl ScrollingBox {
|
|||
|
||||
pub(crate) fn node(&self) -> &Node {
|
||||
match &self.target {
|
||||
ScrollingBoxSource::Element(element, _) => element.upcast(),
|
||||
ScrollingBoxSource::Element(element) => element.upcast(),
|
||||
ScrollingBoxSource::Viewport(document) => document.upcast(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn scroll_to(&self, position: LayoutVector2D, behavior: ScrollBehavior) {
|
||||
match &self.target {
|
||||
ScrollingBoxSource::Element(element, _) => {
|
||||
ScrollingBoxSource::Element(element) => {
|
||||
element
|
||||
.owner_window()
|
||||
.scroll_an_element(element, position.x, position.y, behavior);
|
||||
|
@ -128,15 +128,11 @@ impl ScrollingBox {
|
|||
}
|
||||
|
||||
pub(crate) fn can_keyboard_scroll_in_axis(&self, axis: ScrollingBoxAxis) -> bool {
|
||||
let axes_overflow = match &self.target {
|
||||
ScrollingBoxSource::Element(_, axes_overflow) => axes_overflow,
|
||||
ScrollingBoxSource::Viewport(_) => return true,
|
||||
};
|
||||
let overflow = match axis {
|
||||
ScrollingBoxAxis::X => axes_overflow.x,
|
||||
ScrollingBoxAxis::Y => axes_overflow.x,
|
||||
ScrollingBoxAxis::X => self.overflow.x,
|
||||
ScrollingBoxAxis::Y => self.overflow.y,
|
||||
};
|
||||
if !overflow.is_scrollable() || overflow == Overflow::Hidden {
|
||||
if overflow == Overflow::Hidden {
|
||||
return false;
|
||||
}
|
||||
match axis {
|
||||
|
|
|
@ -157,6 +157,7 @@ use crate::dom::promise::Promise;
|
|||
use crate::dom::reportingendpoint::{ReportingEndpoint, SendReportsToEndpoints};
|
||||
use crate::dom::reportingobserver::ReportingObserver;
|
||||
use crate::dom::screen::Screen;
|
||||
use crate::dom::scrolling_box::{ScrollingBox, ScrollingBoxSource};
|
||||
use crate::dom::selection::Selection;
|
||||
use crate::dom::shadowroot::ShadowRoot;
|
||||
use crate::dom::storage::Storage;
|
||||
|
@ -2628,13 +2629,37 @@ impl Window {
|
|||
|
||||
pub(crate) fn scroll_container_query(
|
||||
&self,
|
||||
node: &Node,
|
||||
node: Option<&Node>,
|
||||
flags: ScrollContainerQueryFlags,
|
||||
) -> Option<ScrollContainerResponse> {
|
||||
self.layout_reflow(QueryMsg::ScrollParentQuery);
|
||||
self.layout
|
||||
.borrow()
|
||||
.query_scroll_container(node.to_trusted_node_address(), flags)
|
||||
.query_scroll_container(node.map(Node::to_trusted_node_address), flags)
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
pub(crate) fn scrolling_box_query(
|
||||
&self,
|
||||
node: Option<&Node>,
|
||||
flags: ScrollContainerQueryFlags,
|
||||
) -> Option<ScrollingBox> {
|
||||
self.scroll_container_query(node, flags)
|
||||
.and_then(|response| {
|
||||
Some(match response {
|
||||
ScrollContainerResponse::Viewport(overflow) => {
|
||||
(ScrollingBoxSource::Viewport(self.Document()), overflow)
|
||||
},
|
||||
ScrollContainerResponse::Element(parent_node_address, overflow) => {
|
||||
let node = unsafe { from_untrusted_node_address(parent_node_address) };
|
||||
(
|
||||
ScrollingBoxSource::Element(DomRoot::downcast(node)?),
|
||||
overflow,
|
||||
)
|
||||
},
|
||||
})
|
||||
})
|
||||
.map(|(source, overflow)| ScrollingBox::new(source, overflow))
|
||||
}
|
||||
|
||||
pub(crate) fn text_index_query(
|
||||
|
|
|
@ -107,7 +107,9 @@ pub(crate) struct WindowProxy {
|
|||
/// <https://html.spec.whatwg.org/multipage/#is-closing>
|
||||
is_closing: Cell<bool>,
|
||||
|
||||
/// The containing iframe element, if this is a same-origin iframe
|
||||
/// If the containing `<iframe>` of this [`WindowProxy`] is from a same-origin page,
|
||||
/// this will be the [`Element`] of the `<iframe>` element in the realm of the
|
||||
/// parent page. Otherwise, it is `None`.
|
||||
frame_element: Option<Dom<Element>>,
|
||||
|
||||
/// The parent browsing context's window proxy, if this is a nested browsing context
|
||||
|
@ -630,6 +632,9 @@ impl WindowProxy {
|
|||
self.webview_id
|
||||
}
|
||||
|
||||
/// If the containing `<iframe>` of this [`WindowProxy`] is from a same-origin page,
|
||||
/// this will return an [`Element`] of the `<iframe>` element in the realm of the parent
|
||||
/// page.
|
||||
pub(crate) fn frame_element(&self) -> Option<&Element> {
|
||||
self.frame_element.as_deref()
|
||||
}
|
||||
|
|
|
@ -101,6 +101,7 @@ impl MixedMessage {
|
|||
ScriptThreadMessage::SendImageKeysBatch(..) => None,
|
||||
ScriptThreadMessage::PreferencesUpdated(..) => None,
|
||||
ScriptThreadMessage::NoLongerWaitingOnAsychronousImageUpdates(_) => None,
|
||||
ScriptThreadMessage::ForwardKeyboardScroll(id, _) => Some(*id),
|
||||
},
|
||||
MixedMessage::FromScript(inner_msg) => match inner_msg {
|
||||
MainThreadScriptMsg::Common(CommonScriptMsg::Task(_, _, pipeline_id, _)) => {
|
||||
|
|
|
@ -1911,6 +1911,11 @@ impl ScriptThread {
|
|||
}
|
||||
prefs::set(current_preferences);
|
||||
},
|
||||
ScriptThreadMessage::ForwardKeyboardScroll(pipeline_id, scroll) => {
|
||||
if let Some(document) = self.documents.borrow().find_document(pipeline_id) {
|
||||
document.event_handler().do_keyboard_scroll(scroll);
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue