1#![allow(clippy::new_without_default)]
8
9use std::cell::Cell;
10use std::fmt;
11use std::marker::PhantomData;
12use std::num::NonZeroU32;
13use std::sync::{Arc, LazyLock};
14
15use malloc_size_of::MallocSizeOfOps;
16use malloc_size_of_derive::MallocSizeOf;
17use parking_lot::Mutex;
18use serde::{Deserialize, Serialize};
19use webrender_api::{ExternalScrollId, PipelineId as WebRenderPipelineId};
20
21use crate::generic_channel::{self, GenericReceiver, GenericSender};
22
23macro_rules! size_of_test {
25 ($t: ty, $expected_size: expr) => {
26 const _: () = assert!(std::mem::size_of::<$t>() == $expected_size);
27 };
28}
29
30pub trait Indexable {
33 const DISPLAY_PREFIX: &'static str;
36}
37
38#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
39pub struct Index<T>(pub NonZeroU32, pub PhantomData<T>);
41
42#[derive(Debug)]
43pub struct ZeroIndex;
46
47impl<T> Index<T> {
48 pub fn new(value: u32) -> Result<Index<T>, ZeroIndex> {
51 Ok(Index(NonZeroU32::new(value).ok_or(ZeroIndex)?, PhantomData))
52 }
53}
54
55impl<T> malloc_size_of::MallocSizeOf for Index<T> {
56 fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
57 0
58 }
59}
60
61#[derive(
62 Clone, Copy, Deserialize, Eq, Hash, MallocSizeOf, Ord, PartialEq, PartialOrd, Serialize,
63)]
64pub struct NamespaceIndex<T> {
66 pub namespace_id: PipelineNamespaceId,
67 pub index: Index<T>,
68}
69
70impl<T> fmt::Debug for NamespaceIndex<T> {
71 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
72 let PipelineNamespaceId(namespace_id) = self.namespace_id;
73 let Index(index, _) = self.index;
74 write!(fmt, "({},{})", namespace_id, index.get())
75 }
76}
77
78impl<T: Indexable> fmt::Display for NamespaceIndex<T> {
79 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
80 write!(fmt, "{}{:?}", T::DISPLAY_PREFIX, self)
81 }
82}
83
84macro_rules! namespace_id {
85 ($id_name:ident, $index_name:ident, $display_prefix:literal) => {
86 #[derive(
87 Clone,
88 Copy,
89 Debug,
90 Deserialize,
91 Eq,
92 Hash,
93 Ord,
94 PartialEq,
95 PartialOrd,
96 Serialize,
97 MallocSizeOf,
98 )]
99 pub struct $index_name;
100 impl Indexable for $index_name {
101 const DISPLAY_PREFIX: &'static str = $display_prefix;
102 }
103 pub type $id_name = NamespaceIndex<$index_name>;
104 impl $id_name {
105 pub fn new() -> $id_name {
106 PIPELINE_NAMESPACE.with(|tls| {
107 let mut namespace = tls.get().expect("No namespace set for this thread!");
108 let next_id = namespace.next_namespace_index();
109 tls.set(Some(namespace));
110 next_id
111 })
112 }
113 }
114 };
115}
116
117#[derive(Debug, Deserialize, Serialize)]
118pub struct PipelineNamespaceRequest(pub GenericSender<PipelineNamespaceId>);
120
121pub struct PipelineNamespaceInstaller {
123 request_sender: Option<GenericSender<PipelineNamespaceRequest>>,
124 namespace_sender: GenericSender<PipelineNamespaceId>,
125 namespace_receiver: GenericReceiver<PipelineNamespaceId>,
126}
127
128impl Default for PipelineNamespaceInstaller {
129 fn default() -> Self {
130 let (namespace_sender, namespace_receiver) =
131 generic_channel::channel().expect("PipelineNamespaceInstaller channel failure");
132 Self {
133 request_sender: None,
134 namespace_sender,
135 namespace_receiver,
136 }
137 }
138}
139
140impl PipelineNamespaceInstaller {
141 pub fn set_sender(&mut self, sender: GenericSender<PipelineNamespaceRequest>) {
143 self.request_sender = Some(sender);
144 }
145
146 pub fn install_namespace(&self) {
148 match self.request_sender.as_ref() {
149 Some(sender) => {
150 let _ = sender.send(PipelineNamespaceRequest(self.namespace_sender.clone()));
151 let namespace_id = self
152 .namespace_receiver
153 .recv()
154 .expect("The constellation to make a pipeline namespace id available");
155 PipelineNamespace::install(namespace_id);
156 },
157 None => unreachable!("PipelineNamespaceInstaller should have a request_sender setup"),
158 }
159 }
160}
161
162static PIPELINE_NAMESPACE_INSTALLER: LazyLock<Arc<Mutex<PipelineNamespaceInstaller>>> =
170 LazyLock::new(|| Arc::new(Mutex::new(PipelineNamespaceInstaller::default())));
171
172#[derive(Clone, Copy)]
192pub struct PipelineNamespace {
193 id: PipelineNamespaceId,
194 index: u32,
195}
196
197impl PipelineNamespace {
198 pub fn install(namespace_id: PipelineNamespaceId) {
200 PIPELINE_NAMESPACE.with(|tls| {
201 assert!(tls.get().is_none());
202 tls.set(Some(PipelineNamespace {
203 id: namespace_id,
204 index: 0,
205 }));
206 });
207 }
208
209 pub fn set_installer_sender(sender: GenericSender<PipelineNamespaceRequest>) {
212 PIPELINE_NAMESPACE_INSTALLER.lock().set_sender(sender);
213 }
214
215 pub fn auto_install() {
218 PIPELINE_NAMESPACE_INSTALLER.lock().install_namespace();
226 }
227
228 fn next_index(&mut self) -> NonZeroU32 {
229 self.index += 1;
230 NonZeroU32::new(self.index).expect("pipeline id index wrapped!")
231 }
232
233 fn next_namespace_index<T>(&mut self) -> NamespaceIndex<T> {
234 NamespaceIndex {
235 namespace_id: self.id,
236 index: Index(self.next_index(), PhantomData),
237 }
238 }
239}
240
241thread_local!(pub static PIPELINE_NAMESPACE: Cell<Option<PipelineNamespace>> = const { Cell::new(None) });
242
243#[derive(
244 Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, Ord, PartialEq, PartialOrd, Serialize,
245)]
246pub struct PipelineNamespaceId(pub u32);
247
248namespace_id! {PipelineId, PipelineIndex, "Pipeline"}
249
250size_of_test!(PipelineId, 8);
251size_of_test!(Option<PipelineId>, 8);
252
253impl PipelineId {
254 pub fn root_scroll_id(&self) -> webrender_api::ExternalScrollId {
255 ExternalScrollId(0, self.into())
256 }
257}
258
259impl From<WebRenderPipelineId> for PipelineId {
260 #[allow(unsafe_code)]
261 fn from(pipeline: WebRenderPipelineId) -> Self {
262 let WebRenderPipelineId(namespace_id, index) = pipeline;
263 unsafe {
264 PipelineId {
265 namespace_id: PipelineNamespaceId(namespace_id),
266 index: Index(NonZeroU32::new_unchecked(index), PhantomData),
267 }
268 }
269 }
270}
271
272impl From<PipelineId> for WebRenderPipelineId {
273 fn from(value: PipelineId) -> Self {
274 let PipelineNamespaceId(namespace_id) = value.namespace_id;
275 let Index(index, _) = value.index;
276 WebRenderPipelineId(namespace_id, index.get())
277 }
278}
279
280impl From<&PipelineId> for WebRenderPipelineId {
281 fn from(value: &PipelineId) -> Self {
282 (*value).into()
283 }
284}
285
286namespace_id! {BrowsingContextId, BrowsingContextIndex, "BrowsingContext"}
287
288size_of_test!(BrowsingContextId, 8);
289size_of_test!(Option<BrowsingContextId>, 8);
290
291#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
292pub struct BrowsingContextGroupId(pub u32);
293impl fmt::Display for BrowsingContextGroupId {
294 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
295 write!(f, "BrowsingContextGroup{:?}", self)
296 }
297}
298
299thread_local!(pub static WEBVIEW_ID: Cell<Option<WebViewId>> =
300 const { Cell::new(None) });
301
302#[derive(
303 Clone, Copy, Deserialize, Eq, Hash, MallocSizeOf, Ord, PartialEq, PartialOrd, Serialize,
304)]
305pub struct WebViewId(BrowsingContextId);
306
307size_of_test!(WebViewId, 8);
308size_of_test!(Option<WebViewId>, 8);
309
310impl fmt::Debug for WebViewId {
311 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
312 write!(f, "TopLevel{:?}", self.0)
313 }
314}
315
316impl fmt::Display for WebViewId {
317 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
318 write!(f, "TopLevel{}", self.0)
319 }
320}
321
322impl WebViewId {
323 pub fn new() -> WebViewId {
324 WebViewId(BrowsingContextId::new())
325 }
326
327 pub fn install(id: WebViewId) {
330 WEBVIEW_ID.with(|tls| tls.set(Some(id)))
331 }
332
333 pub fn installed() -> Option<WebViewId> {
334 WEBVIEW_ID.with(|tls| tls.get())
335 }
336
337 pub fn mock_for_testing(browsing_context_id: BrowsingContextId) -> WebViewId {
338 WebViewId(browsing_context_id)
339 }
340}
341
342impl From<WebViewId> for BrowsingContextId {
343 fn from(id: WebViewId) -> BrowsingContextId {
344 id.0
345 }
346}
347
348impl PartialEq<WebViewId> for BrowsingContextId {
349 fn eq(&self, rhs: &WebViewId) -> bool {
350 self.eq(&rhs.0)
351 }
352}
353
354impl PartialEq<BrowsingContextId> for WebViewId {
355 fn eq(&self, rhs: &BrowsingContextId) -> bool {
356 self.0.eq(rhs)
357 }
358}
359
360namespace_id! {MessagePortId, MessagePortIndex, "MessagePort"}
361
362namespace_id! {MessagePortRouterId, MessagePortRouterIndex, "MessagePortRouter"}
363
364namespace_id! {BroadcastChannelRouterId, BroadcastChannelRouterIndex, "BroadcastChannelRouter"}
365
366namespace_id! {ServiceWorkerId, ServiceWorkerIndex, "ServiceWorker"}
367
368namespace_id! {ServiceWorkerRegistrationId, ServiceWorkerRegistrationIndex, "ServiceWorkerRegistration"}
369
370namespace_id! {BlobId, BlobIndex, "Blob"}
371
372namespace_id! {DomPointId, DomPointIndex, "DomPoint"}
373
374namespace_id! {DomRectId, DomRectIndex, "DomRect"}
375
376namespace_id! {DomQuadId, DomQuadIndex, "DomQuad"}
377
378namespace_id! {DomMatrixId, DomMatrixIndex, "DomMatrix"}
379
380namespace_id! {DomExceptionId, DomExceptionIndex, "DomException"}
381
382namespace_id! {QuotaExceededErrorId, QuotaExceededErrorIndex, "QuotaExceededError"}
383
384namespace_id! {HistoryStateId, HistoryStateIndex, "HistoryState"}
385
386namespace_id! {ImageBitmapId, ImageBitmapIndex, "ImageBitmap"}
387
388namespace_id! {OffscreenCanvasId, OffscreenCanvasIndex, "OffscreenCanvas"}
389
390namespace_id! {CookieStoreId, CookieStoreIndex, "CookieStore"}
391
392pub const TEST_NAMESPACE: PipelineNamespaceId = PipelineNamespaceId(1234);
394pub const TEST_PIPELINE_INDEX: Index<PipelineIndex> =
395 Index(NonZeroU32::new(5678).unwrap(), PhantomData);
396pub const TEST_PIPELINE_ID: PipelineId = PipelineId {
397 namespace_id: TEST_NAMESPACE,
398 index: TEST_PIPELINE_INDEX,
399};
400pub const TEST_BROWSING_CONTEXT_INDEX: Index<BrowsingContextIndex> =
401 Index(NonZeroU32::new(8765).unwrap(), PhantomData);
402pub const TEST_BROWSING_CONTEXT_ID: BrowsingContextId = BrowsingContextId {
403 namespace_id: TEST_NAMESPACE,
404 index: TEST_BROWSING_CONTEXT_INDEX,
405};
406
407pub const TEST_WEBVIEW_ID: WebViewId = WebViewId(TEST_BROWSING_CONTEXT_ID);
408
409#[derive(Clone, Copy, Debug, Default, Deserialize, MallocSizeOf, PartialEq, Serialize)]
413pub struct ScrollTreeNodeId {
414 pub index: usize,
416}