mirror of
https://github.com/servo/servo.git
synced 2025-06-20 07:08:59 +01:00
In order to properly handle CSS clipping, we need to keep track of what the different kinds of clips that we have. On one hand, clipping due to overflow rules should respect the containing block hierarchy, while CSS clipping should respect the flow tree hierarchy. In order to represent the complexity of items that are scrolled via one clip/scroll frame and clipped by another we keep track of that status with a ClipAndScrollInfo.
350 lines
8.9 KiB
Rust
350 lines
8.9 KiB
Rust
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
//! The high-level interface from script to constellation. Using this abstract interface helps
|
|
//! reduce coupling between these two components.
|
|
|
|
use std::cell::Cell;
|
|
use std::fmt;
|
|
use webrender_api;
|
|
|
|
#[derive(PartialEq, Eq, Copy, Clone, Debug, Deserialize, Serialize)]
|
|
pub enum KeyState {
|
|
Pressed,
|
|
Released,
|
|
Repeated,
|
|
}
|
|
|
|
//N.B. Based on the glutin key enum
|
|
#[derive(Debug, PartialEq, Eq, Copy, Clone, Deserialize, Serialize, HeapSizeOf)]
|
|
pub enum Key {
|
|
Space,
|
|
Apostrophe,
|
|
Comma,
|
|
Minus,
|
|
Period,
|
|
Slash,
|
|
Num0,
|
|
Num1,
|
|
Num2,
|
|
Num3,
|
|
Num4,
|
|
Num5,
|
|
Num6,
|
|
Num7,
|
|
Num8,
|
|
Num9,
|
|
Semicolon,
|
|
Equal,
|
|
A,
|
|
B,
|
|
C,
|
|
D,
|
|
E,
|
|
F,
|
|
G,
|
|
H,
|
|
I,
|
|
J,
|
|
K,
|
|
L,
|
|
M,
|
|
N,
|
|
O,
|
|
P,
|
|
Q,
|
|
R,
|
|
S,
|
|
T,
|
|
U,
|
|
V,
|
|
W,
|
|
X,
|
|
Y,
|
|
Z,
|
|
LeftBracket,
|
|
Backslash,
|
|
RightBracket,
|
|
GraveAccent,
|
|
World1,
|
|
World2,
|
|
|
|
Escape,
|
|
Enter,
|
|
Tab,
|
|
Backspace,
|
|
Insert,
|
|
Delete,
|
|
Right,
|
|
Left,
|
|
Down,
|
|
Up,
|
|
PageUp,
|
|
PageDown,
|
|
Home,
|
|
End,
|
|
CapsLock,
|
|
ScrollLock,
|
|
NumLock,
|
|
PrintScreen,
|
|
Pause,
|
|
F1,
|
|
F2,
|
|
F3,
|
|
F4,
|
|
F5,
|
|
F6,
|
|
F7,
|
|
F8,
|
|
F9,
|
|
F10,
|
|
F11,
|
|
F12,
|
|
F13,
|
|
F14,
|
|
F15,
|
|
F16,
|
|
F17,
|
|
F18,
|
|
F19,
|
|
F20,
|
|
F21,
|
|
F22,
|
|
F23,
|
|
F24,
|
|
F25,
|
|
Kp0,
|
|
Kp1,
|
|
Kp2,
|
|
Kp3,
|
|
Kp4,
|
|
Kp5,
|
|
Kp6,
|
|
Kp7,
|
|
Kp8,
|
|
Kp9,
|
|
KpDecimal,
|
|
KpDivide,
|
|
KpMultiply,
|
|
KpSubtract,
|
|
KpAdd,
|
|
KpEnter,
|
|
KpEqual,
|
|
LeftShift,
|
|
LeftControl,
|
|
LeftAlt,
|
|
LeftSuper,
|
|
RightShift,
|
|
RightControl,
|
|
RightAlt,
|
|
RightSuper,
|
|
Menu,
|
|
|
|
NavigateBackward,
|
|
NavigateForward,
|
|
}
|
|
|
|
bitflags! {
|
|
#[derive(Deserialize, Serialize)]
|
|
pub flags KeyModifiers: u8 {
|
|
const NONE = 0x00,
|
|
const SHIFT = 0x01,
|
|
const CONTROL = 0x02,
|
|
const ALT = 0x04,
|
|
const SUPER = 0x08,
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, PartialEq, Eq, Copy, Hash, Debug, Deserialize, Serialize)]
|
|
pub enum TraversalDirection {
|
|
Forward(usize),
|
|
Back(usize),
|
|
}
|
|
|
|
/// Each pipeline ID needs to be unique. However, it also needs to be possible to
|
|
/// generate the pipeline ID from an iframe element (this simplifies a lot of other
|
|
/// code that makes use of pipeline IDs).
|
|
///
|
|
/// To achieve this, each pipeline index belongs to a particular namespace. There is
|
|
/// a namespace for the constellation thread, and also one for every script thread.
|
|
/// This allows pipeline IDs to be generated by any of those threads without conflicting
|
|
/// with pipeline IDs created by other script threads or the constellation. The
|
|
/// constellation is the only code that is responsible for creating new *namespaces*.
|
|
/// This ensures that namespaces are always unique, even when using multi-process mode.
|
|
///
|
|
/// It may help conceptually to think of the namespace ID as an identifier for the
|
|
/// thread that created this pipeline ID - however this is really an implementation
|
|
/// detail so shouldn't be relied upon in code logic. It's best to think of the
|
|
/// pipeline ID as a simple unique identifier that doesn't convey any more information.
|
|
#[derive(Clone, Copy)]
|
|
pub struct PipelineNamespace {
|
|
id: PipelineNamespaceId,
|
|
index: u32,
|
|
}
|
|
|
|
impl PipelineNamespace {
|
|
pub fn install(namespace_id: PipelineNamespaceId) {
|
|
PIPELINE_NAMESPACE.with(|tls| {
|
|
assert!(tls.get().is_none());
|
|
tls.set(Some(PipelineNamespace {
|
|
id: namespace_id,
|
|
index: 0,
|
|
}));
|
|
});
|
|
}
|
|
|
|
fn next_index(&mut self) -> u32 {
|
|
let result = self.index;
|
|
self.index = result + 1;
|
|
result
|
|
}
|
|
|
|
fn next_pipeline_id(&mut self) -> PipelineId {
|
|
PipelineId {
|
|
namespace_id: self.id,
|
|
index: PipelineIndex(self.next_index()),
|
|
}
|
|
}
|
|
|
|
fn next_browsing_context_id(&mut self) -> BrowsingContextId {
|
|
BrowsingContextId {
|
|
namespace_id: self.id,
|
|
index: BrowsingContextIndex(self.next_index()),
|
|
}
|
|
}
|
|
}
|
|
|
|
thread_local!(pub static PIPELINE_NAMESPACE: Cell<Option<PipelineNamespace>> = Cell::new(None));
|
|
|
|
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Copy, Hash, Debug, Deserialize, Serialize, HeapSizeOf)]
|
|
pub struct PipelineNamespaceId(pub u32);
|
|
|
|
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Copy, Hash, Debug, Deserialize, Serialize, HeapSizeOf)]
|
|
pub struct PipelineIndex(pub u32);
|
|
|
|
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Copy, Hash, Debug, Deserialize, Serialize, HeapSizeOf)]
|
|
pub struct PipelineId {
|
|
pub namespace_id: PipelineNamespaceId,
|
|
pub index: PipelineIndex
|
|
}
|
|
|
|
impl PipelineId {
|
|
pub fn new() -> PipelineId {
|
|
PIPELINE_NAMESPACE.with(|tls| {
|
|
let mut namespace = tls.get().expect("No namespace set for this thread!");
|
|
let new_pipeline_id = namespace.next_pipeline_id();
|
|
tls.set(Some(namespace));
|
|
new_pipeline_id
|
|
})
|
|
}
|
|
|
|
pub fn to_webrender(&self) -> webrender_api::PipelineId {
|
|
let PipelineNamespaceId(namespace_id) = self.namespace_id;
|
|
let PipelineIndex(index) = self.index;
|
|
webrender_api::PipelineId(namespace_id, index)
|
|
}
|
|
|
|
pub fn root_scroll_node(&self) -> webrender_api::ClipId {
|
|
webrender_api::ClipId::root_scroll_node(self.to_webrender())
|
|
}
|
|
|
|
pub fn root_clip_and_scroll_info(&self) -> webrender_api::ClipAndScrollInfo {
|
|
webrender_api::ClipAndScrollInfo::simple(self.root_scroll_node())
|
|
}
|
|
}
|
|
|
|
impl fmt::Display for PipelineId {
|
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
|
let PipelineNamespaceId(namespace_id) = self.namespace_id;
|
|
let PipelineIndex(index) = self.index;
|
|
write!(fmt, "({},{})", namespace_id, index)
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Copy, Hash, Debug, Deserialize, Serialize, HeapSizeOf)]
|
|
pub struct BrowsingContextIndex(pub u32);
|
|
|
|
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Copy, Hash, Debug, Deserialize, Serialize, HeapSizeOf)]
|
|
pub struct BrowsingContextId {
|
|
pub namespace_id: PipelineNamespaceId,
|
|
pub index: BrowsingContextIndex
|
|
}
|
|
|
|
impl BrowsingContextId {
|
|
pub fn new() -> BrowsingContextId {
|
|
PIPELINE_NAMESPACE.with(|tls| {
|
|
let mut namespace = tls.get().expect("No namespace set for this thread!");
|
|
let new_browsing_context_id = namespace.next_browsing_context_id();
|
|
tls.set(Some(namespace));
|
|
new_browsing_context_id
|
|
})
|
|
}
|
|
}
|
|
|
|
impl fmt::Display for BrowsingContextId {
|
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
|
let PipelineNamespaceId(namespace_id) = self.namespace_id;
|
|
let BrowsingContextIndex(index) = self.index;
|
|
write!(fmt, "({},{})", namespace_id, index)
|
|
}
|
|
}
|
|
|
|
thread_local!(pub static TOP_LEVEL_BROWSING_CONTEXT_ID: Cell<Option<TopLevelBrowsingContextId>> = Cell::new(None));
|
|
|
|
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Copy, Hash, Debug, Deserialize, Serialize, HeapSizeOf)]
|
|
pub struct TopLevelBrowsingContextId(BrowsingContextId);
|
|
|
|
impl TopLevelBrowsingContextId {
|
|
pub fn new() -> TopLevelBrowsingContextId {
|
|
TopLevelBrowsingContextId(BrowsingContextId::new())
|
|
}
|
|
/// Each script and layout thread should have the top-level browsing context id installed,
|
|
/// since it is used by crash reporting.
|
|
pub fn install(id: TopLevelBrowsingContextId) {
|
|
TOP_LEVEL_BROWSING_CONTEXT_ID.with(|tls| tls.set(Some(id)))
|
|
}
|
|
|
|
pub fn installed() -> Option<TopLevelBrowsingContextId> {
|
|
TOP_LEVEL_BROWSING_CONTEXT_ID.with(|tls| tls.get())
|
|
}
|
|
}
|
|
|
|
impl fmt::Display for TopLevelBrowsingContextId {
|
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
|
self.0.fmt(fmt)
|
|
}
|
|
}
|
|
|
|
impl From<TopLevelBrowsingContextId> for BrowsingContextId {
|
|
fn from(id: TopLevelBrowsingContextId) -> BrowsingContextId {
|
|
id.0
|
|
}
|
|
}
|
|
|
|
impl PartialEq<TopLevelBrowsingContextId> for BrowsingContextId {
|
|
fn eq(&self, rhs: &TopLevelBrowsingContextId) -> bool {
|
|
self.eq(&rhs.0)
|
|
}
|
|
}
|
|
|
|
impl PartialEq<BrowsingContextId> for TopLevelBrowsingContextId {
|
|
fn eq(&self, rhs: &BrowsingContextId) -> bool {
|
|
self.0.eq(rhs)
|
|
}
|
|
}
|
|
|
|
// We provide ids just for unit testing.
|
|
pub const TEST_NAMESPACE: PipelineNamespaceId = PipelineNamespaceId(1234);
|
|
pub const TEST_PIPELINE_INDEX: PipelineIndex = PipelineIndex(5678);
|
|
pub const TEST_PIPELINE_ID: PipelineId = PipelineId { namespace_id: TEST_NAMESPACE, index: TEST_PIPELINE_INDEX };
|
|
pub const TEST_BROWSING_CONTEXT_INDEX: BrowsingContextIndex = BrowsingContextIndex(8765);
|
|
pub const TEST_BROWSING_CONTEXT_ID: BrowsingContextId =
|
|
BrowsingContextId { namespace_id: TEST_NAMESPACE, index: TEST_BROWSING_CONTEXT_INDEX };
|
|
|
|
#[derive(Clone, PartialEq, Eq, Copy, Hash, Debug, Deserialize, Serialize, HeapSizeOf)]
|
|
pub enum FrameType {
|
|
IFrame,
|
|
MozBrowserIFrame,
|
|
}
|
|
|