/* 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 nonzero::NonZero; use std::cell::Cell; use std::fmt; use webrender_api; #[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)] pub enum KeyState { Pressed, Released, Repeated, } //N.B. Based on the glutin key enum #[derive(Clone, Copy, Debug, Deserialize, Eq, MallocSizeOf, PartialEq, Serialize)] 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, Copy, Debug, Deserialize, Eq, Hash, PartialEq, 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) -> NonZero { self.index += 1; NonZero::new(self.index).expect("pipeline id index wrapped!") } 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> = Cell::new(None)); #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, Ord, PartialEq, PartialOrd, Serialize)] pub struct PipelineNamespaceId(pub u32); #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)] pub struct PipelineIndex(pub NonZero); malloc_size_of_is_0!(PipelineIndex); #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, Ord, PartialEq, PartialOrd, Serialize)] 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.get()) } #[allow(unsafe_code)] pub fn from_webrender(pipeline: webrender_api::PipelineId) -> PipelineId { let webrender_api::PipelineId(namespace_id, index) = pipeline; unsafe { PipelineId { namespace_id: PipelineNamespaceId(namespace_id), index: PipelineIndex(NonZero::new_unchecked(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.get()) } } #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)] pub struct BrowsingContextIndex(pub NonZero); malloc_size_of_is_0!(BrowsingContextIndex); #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, Ord, PartialEq, PartialOrd, Serialize)] 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.get()) } } thread_local!(pub static TOP_LEVEL_BROWSING_CONTEXT_ID: Cell> = Cell::new(None)); #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, Ord, PartialEq, PartialOrd, Serialize)] 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 { 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 for BrowsingContextId { fn from(id: TopLevelBrowsingContextId) -> BrowsingContextId { id.0 } } impl PartialEq for BrowsingContextId { fn eq(&self, rhs: &TopLevelBrowsingContextId) -> bool { self.eq(&rhs.0) } } impl PartialEq 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); #[allow(unsafe_code)] #[cfg(feature = "unstable")] pub const TEST_PIPELINE_INDEX: PipelineIndex = unsafe { PipelineIndex(NonZero::new_unchecked(5678)) }; #[cfg(feature = "unstable")] pub const TEST_PIPELINE_ID: PipelineId = PipelineId { namespace_id: TEST_NAMESPACE, index: TEST_PIPELINE_INDEX }; #[allow(unsafe_code)] #[cfg(feature = "unstable")] pub const TEST_BROWSING_CONTEXT_INDEX: BrowsingContextIndex = unsafe { BrowsingContextIndex(NonZero::new_unchecked(8765)) }; #[cfg(feature = "unstable")] pub const TEST_BROWSING_CONTEXT_ID: BrowsingContextId = BrowsingContextId { namespace_id: TEST_NAMESPACE, index: TEST_BROWSING_CONTEXT_INDEX }; #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)] pub enum FrameType { IFrame, MozBrowserIFrame, }