zng_webrender_api/
display_list.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 http://mozilla.org/MPL/2.0/. */
4
5use euclid::SideOffsets2D;
6use peek_poke::{ensure_red_zone, peek_from_slice, poke_extend_vec, strip_red_zone};
7use peek_poke::{poke_inplace_slice, poke_into_vec, Poke};
8#[cfg(feature = "deserialize")]
9use serde::de::Deserializer;
10#[cfg(feature = "serialize")]
11use serde::ser::Serializer;
12use serde::{Deserialize, Serialize};
13use std::io::Write;
14use std::marker::PhantomData;
15use std::ops::Range;
16use std::mem;
17use std::collections::HashMap;
18
19use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
20// local imports
21use crate::display_item as di;
22use crate::display_item_cache::*;
23use crate::{APZScrollGeneration, HasScrollLinkedEffect, PipelineId, PropertyBinding};
24use crate::gradient_builder::GradientBuilder;
25use crate::color::ColorF;
26use crate::font::{FontInstanceKey, GlyphInstance, GlyphOptions};
27use crate::image::{ColorDepth, ImageKey};
28use crate::units::*;
29
30fn precise_time_ns() -> u64 {
31    std::time::SystemTime::UNIX_EPOCH
32        .elapsed()
33        .unwrap()
34        .as_nanos() as u64
35}
36
37// We don't want to push a long text-run. If a text-run is too long, split it into several parts.
38// This needs to be set to (renderer::MAX_VERTEX_TEXTURE_WIDTH - VECS_PER_TEXT_RUN) * 2
39pub const MAX_TEXT_RUN_LENGTH: usize = 2040;
40
41// See ROOT_REFERENCE_FRAME_SPATIAL_ID and ROOT_SCROLL_NODE_SPATIAL_ID
42// TODO(mrobinson): It would be a good idea to eliminate the root scroll frame which is only
43// used by Servo.
44const FIRST_SPATIAL_NODE_INDEX: usize = 2;
45
46// See ROOT_SCROLL_NODE_SPATIAL_ID
47const FIRST_CLIP_NODE_INDEX: usize = 1;
48
49#[derive(Debug, Copy, Clone, PartialEq)]
50enum BuildState {
51    Idle,
52    Build,
53}
54
55#[repr(C)]
56#[derive(Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
57pub struct ItemRange<'a, T> {
58    bytes: &'a [u8],
59    _boo: PhantomData<T>,
60}
61
62impl<'a, T> Copy for ItemRange<'a, T> {}
63impl<'a, T> Clone for ItemRange<'a, T> {
64    fn clone(&self) -> Self {
65        *self
66    }
67}
68
69impl<'a, T> Default for ItemRange<'a, T> {
70    fn default() -> Self {
71        ItemRange {
72            bytes: Default::default(),
73            _boo: PhantomData,
74        }
75    }
76}
77
78impl<'a, T> ItemRange<'a, T> {
79    pub fn new(bytes: &'a [u8]) -> Self {
80        Self {
81            bytes,
82            _boo: PhantomData,
83        }
84    }
85
86    pub fn is_empty(&self) -> bool {
87        // Nothing more than space for a length (0).
88        self.bytes.len() <= mem::size_of::<usize>()
89    }
90
91    pub fn bytes(&self) -> &[u8] {
92        &self.bytes
93    }
94}
95
96impl<'a, T: Default> ItemRange<'a, T> {
97    pub fn iter(&self) -> AuxIter<'a, T> {
98        AuxIter::new(T::default(), self.bytes)
99    }
100}
101
102impl<'a, T> IntoIterator for ItemRange<'a, T>
103where
104    T: Copy + Default + peek_poke::Peek,
105{
106    type Item = T;
107    type IntoIter = AuxIter<'a, T>;
108    fn into_iter(self) -> Self::IntoIter {
109        self.iter()
110    }
111}
112
113#[derive(Copy, Clone)]
114pub struct TempFilterData<'a> {
115    pub func_types: ItemRange<'a, di::ComponentTransferFuncType>,
116    pub r_values: ItemRange<'a, f32>,
117    pub g_values: ItemRange<'a, f32>,
118    pub b_values: ItemRange<'a, f32>,
119    pub a_values: ItemRange<'a, f32>,
120}
121
122#[derive(Default, Clone)]
123pub struct DisplayListPayload {
124    /// Serde encoded bytes. Mostly DisplayItems, but some mixed in slices.
125    pub items_data: Vec<u8>,
126
127    /// Serde encoded DisplayItemCache structs
128    pub cache_data: Vec<u8>,
129
130    /// Serde encoded SpatialTreeItem structs
131    pub spatial_tree: Vec<u8>,
132}
133
134impl DisplayListPayload {
135    fn default() -> Self {
136        DisplayListPayload {
137            items_data: Vec::new(),
138            cache_data: Vec::new(),
139            spatial_tree: Vec::new(),
140        }
141    }
142
143    fn new(capacity: DisplayListCapacity) -> Self {
144        let mut payload = Self::default();
145
146        // We can safely ignore the preallocations failing, since we aren't
147        // certain about how much memory we need, and this gives a chance for
148        // the memory pressure events to run.
149        if let Err(_) = payload.items_data.try_reserve(capacity.items_size) {
150            return Self::default();
151        }
152        if let Err(_) = payload.cache_data.try_reserve(capacity.cache_size) {
153            return Self::default();
154        }
155        if let Err(_) = payload.spatial_tree.try_reserve(capacity.spatial_tree_size) {
156            return Self::default();
157        }
158        payload
159    }
160
161    fn clear(&mut self) {
162        self.items_data.clear();
163        self.cache_data.clear();
164        self.spatial_tree.clear();
165    }
166
167    fn size_in_bytes(&self) -> usize {
168        self.items_data.len() + self.cache_data.len() + self.spatial_tree.len()
169    }
170
171    #[cfg(feature = "serialize")]
172    fn create_debug_spatial_tree_items(&self) -> Vec<di::SpatialTreeItem> {
173        let mut items = Vec::new();
174
175        iter_spatial_tree(&self.spatial_tree, |item| {
176            items.push(*item);
177        });
178
179        items
180    }
181}
182
183impl MallocSizeOf for DisplayListPayload {
184    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
185        self.items_data.size_of(ops) + self.cache_data.size_of(ops) + self.spatial_tree.size_of(ops)
186    }
187}
188
189/// A display list.
190#[derive(Default, Clone)]
191pub struct BuiltDisplayList {
192    payload: DisplayListPayload,
193    descriptor: BuiltDisplayListDescriptor,
194}
195
196#[repr(C)]
197#[derive(Copy, Clone, Deserialize, Serialize)]
198pub enum GeckoDisplayListType {
199    None,
200    Partial(f64),
201    Full(f64),
202}
203
204impl Default for GeckoDisplayListType {
205    fn default() -> Self {
206        GeckoDisplayListType::None
207    }
208}
209
210/// Describes the memory layout of a display list.
211///
212/// A display list consists of some number of display list items, followed by a number of display
213/// items.
214#[repr(C)]
215#[derive(Copy, Clone, Default, Deserialize, Serialize)]
216pub struct BuiltDisplayListDescriptor {
217    /// Gecko specific information about the display list.
218    gecko_display_list_type: GeckoDisplayListType,
219    /// The first IPC time stamp: before any work has been done
220    builder_start_time: u64,
221    /// The second IPC time stamp: after serialization
222    builder_finish_time: u64,
223    /// The third IPC time stamp: just before sending
224    send_start_time: u64,
225    /// The amount of clipping nodes created while building this display list.
226    total_clip_nodes: usize,
227    /// The amount of spatial nodes created while building this display list.
228    total_spatial_nodes: usize,
229    /// The size of the cache for this display list.
230    cache_size: usize,
231}
232
233#[derive(Clone)]
234pub struct DisplayListWithCache {
235    pub display_list: BuiltDisplayList,
236    cache: DisplayItemCache,
237}
238
239impl DisplayListWithCache {
240    pub fn iter(&self) -> BuiltDisplayListIter {
241        self.display_list.iter_with_cache(&self.cache)
242    }
243
244    pub fn new_from_list(display_list: BuiltDisplayList) -> Self {
245        let mut cache = DisplayItemCache::new();
246        cache.update(&display_list);
247
248        DisplayListWithCache {
249            display_list,
250            cache,
251        }
252    }
253
254    pub fn update(&mut self, display_list: BuiltDisplayList) {
255        self.cache.update(&display_list);
256        self.display_list = display_list;
257    }
258
259    pub fn descriptor(&self) -> &BuiltDisplayListDescriptor {
260        self.display_list.descriptor()
261    }
262
263    pub fn times(&self) -> (u64, u64, u64) {
264        self.display_list.times()
265    }
266
267    pub fn items_data(&self) -> &[u8] {
268        self.display_list.items_data()
269    }
270}
271
272impl MallocSizeOf for DisplayListWithCache {
273    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
274        self.display_list.payload.size_of(ops) + self.cache.size_of(ops)
275    }
276}
277
278/// A debug (human-readable) representation of a built display list that
279/// can be used for capture and replay.
280#[cfg(any(feature = "serialize", feature = "deserialize"))]
281#[cfg_attr(feature = "serialize", derive(Serialize))]
282#[cfg_attr(feature = "deserialize", derive(Deserialize))]
283struct DisplayListCapture {
284    display_items: Vec<di::DebugDisplayItem>,
285    spatial_tree_items: Vec<di::SpatialTreeItem>,
286    descriptor: BuiltDisplayListDescriptor,
287}
288
289#[cfg(feature = "serialize")]
290impl Serialize for DisplayListWithCache {
291    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
292        let display_items = BuiltDisplayList::create_debug_display_items(self.iter());
293        let spatial_tree_items = self.display_list.payload.create_debug_spatial_tree_items();
294
295        let dl = DisplayListCapture {
296            display_items,
297            spatial_tree_items,
298            descriptor: self.display_list.descriptor,
299        };
300
301        dl.serialize(serializer)
302    }
303}
304
305#[cfg(feature = "deserialize")]
306impl<'de> Deserialize<'de> for DisplayListWithCache {
307    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
308    where
309        D: Deserializer<'de>,
310    {
311        use crate::display_item::DisplayItem as Real;
312        use crate::display_item::DebugDisplayItem as Debug;
313
314        let capture = DisplayListCapture::deserialize(deserializer)?;
315
316        let mut spatial_tree = Vec::new();
317        for item in capture.spatial_tree_items {
318            poke_into_vec(&item, &mut spatial_tree);
319        }
320        ensure_red_zone::<di::SpatialTreeItem>(&mut spatial_tree);
321
322        let mut items_data = Vec::new();
323        let mut temp = Vec::new();
324        for complete in capture.display_items {
325            let item = match complete {
326                Debug::ClipChain(v, clip_chain_ids) => {
327                    DisplayListBuilder::push_iter_impl(&mut temp, clip_chain_ids);
328                    Real::ClipChain(v)
329                }
330                Debug::Text(v, glyphs) => {
331                    DisplayListBuilder::push_iter_impl(&mut temp, glyphs);
332                    Real::Text(v)
333                }
334                Debug::Iframe(v) => Real::Iframe(v),
335                Debug::PushReferenceFrame(v) => Real::PushReferenceFrame(v),
336                Debug::SetFilterOps(filters) => {
337                    DisplayListBuilder::push_iter_impl(&mut temp, filters);
338                    Real::SetFilterOps
339                }
340                Debug::SetFilterData(filter_data) => {
341                    let func_types: Vec<di::ComponentTransferFuncType> = [
342                        filter_data.func_r_type,
343                        filter_data.func_g_type,
344                        filter_data.func_b_type,
345                        filter_data.func_a_type,
346                    ]
347                    .to_vec();
348                    DisplayListBuilder::push_iter_impl(&mut temp, func_types);
349                    DisplayListBuilder::push_iter_impl(&mut temp, filter_data.r_values);
350                    DisplayListBuilder::push_iter_impl(&mut temp, filter_data.g_values);
351                    DisplayListBuilder::push_iter_impl(&mut temp, filter_data.b_values);
352                    DisplayListBuilder::push_iter_impl(&mut temp, filter_data.a_values);
353                    Real::SetFilterData
354                }
355                Debug::SetFilterPrimitives(filter_primitives) => {
356                    DisplayListBuilder::push_iter_impl(&mut temp, filter_primitives);
357                    Real::SetFilterPrimitives
358                }
359                Debug::SetGradientStops(stops) => {
360                    DisplayListBuilder::push_iter_impl(&mut temp, stops);
361                    Real::SetGradientStops
362                }
363                Debug::SetPoints(points) => {
364                    DisplayListBuilder::push_iter_impl(&mut temp, points);
365                    Real::SetPoints
366                }
367                Debug::RectClip(v) => Real::RectClip(v),
368                Debug::RoundedRectClip(v) => Real::RoundedRectClip(v),
369                Debug::ImageMaskClip(v) => Real::ImageMaskClip(v),
370                Debug::Rectangle(v) => Real::Rectangle(v),
371                Debug::ClearRectangle(v) => Real::ClearRectangle(v),
372                Debug::HitTest(v) => Real::HitTest(v),
373                Debug::Line(v) => Real::Line(v),
374                Debug::Image(v) => Real::Image(v),
375                Debug::RepeatingImage(v) => Real::RepeatingImage(v),
376                Debug::YuvImage(v) => Real::YuvImage(v),
377                Debug::Border(v) => Real::Border(v),
378                Debug::BoxShadow(v) => Real::BoxShadow(v),
379                Debug::Gradient(v) => Real::Gradient(v),
380                Debug::RadialGradient(v) => Real::RadialGradient(v),
381                Debug::ConicGradient(v) => Real::ConicGradient(v),
382                Debug::PushStackingContext(v) => Real::PushStackingContext(v),
383                Debug::PushShadow(v) => Real::PushShadow(v),
384                Debug::BackdropFilter(v) => Real::BackdropFilter(v),
385
386                Debug::PopStackingContext => Real::PopStackingContext,
387                Debug::PopReferenceFrame => Real::PopReferenceFrame,
388                Debug::PopAllShadows => Real::PopAllShadows,
389            };
390            poke_into_vec(&item, &mut items_data);
391            // the aux data is serialized after the item, hence the temporary
392            items_data.extend(temp.drain(..));
393        }
394
395        // Add `DisplayItem::max_size` zone of zeroes to the end of display list
396        // so there is at least this amount available in the display list during
397        // serialization.
398        ensure_red_zone::<di::DisplayItem>(&mut items_data);
399
400        Ok(DisplayListWithCache {
401            display_list: BuiltDisplayList {
402                descriptor: capture.descriptor,
403                payload: DisplayListPayload {
404                    cache_data: Vec::new(),
405                    items_data,
406                    spatial_tree,
407                },
408            },
409            cache: DisplayItemCache::new(),
410        })
411    }
412}
413
414pub struct BuiltDisplayListIter<'a> {
415    data: &'a [u8],
416    cache: Option<&'a DisplayItemCache>,
417    pending_items: std::slice::Iter<'a, CachedDisplayItem>,
418    cur_cached_item: Option<&'a CachedDisplayItem>,
419    cur_item: di::DisplayItem,
420    cur_stops: ItemRange<'a, di::GradientStop>,
421    cur_glyphs: ItemRange<'a, GlyphInstance>,
422    cur_filters: ItemRange<'a, di::FilterOp>,
423    cur_filter_data: Vec<TempFilterData<'a>>,
424    cur_filter_primitives: ItemRange<'a, di::FilterPrimitive>,
425    cur_clip_chain_items: ItemRange<'a, di::ClipId>,
426    cur_points: ItemRange<'a, LayoutPoint>,
427    peeking: Peek,
428    /// Should just be initialized but never populated in release builds
429    debug_stats: DebugStats,
430}
431
432/// Internal info used for more detailed analysis of serialized display lists
433#[allow(dead_code)]
434struct DebugStats {
435    /// Last address in the buffer we pointed to, for computing serialized sizes
436    last_addr: usize,
437    stats: HashMap<&'static str, ItemStats>,
438}
439
440impl DebugStats {
441    #[cfg(feature = "display_list_stats")]
442    fn _update_entry(&mut self, name: &'static str, item_count: usize, byte_count: usize) {
443        let entry = self.stats.entry(name).or_default();
444        entry.total_count += item_count;
445        entry.num_bytes += byte_count;
446    }
447
448    /// Computes the number of bytes we've processed since we last called
449    /// this method, so we can compute the serialized size of a display item.
450    #[cfg(feature = "display_list_stats")]
451    fn debug_num_bytes(&mut self, data: &[u8]) -> usize {
452        let old_addr = self.last_addr;
453        let new_addr = data.as_ptr() as usize;
454        let delta = new_addr - old_addr;
455        self.last_addr = new_addr;
456
457        delta
458    }
459
460    /// Logs stats for the last deserialized display item
461    #[cfg(feature = "display_list_stats")]
462    fn log_item(&mut self, data: &[u8], item: &di::DisplayItem) {
463        let num_bytes = self.debug_num_bytes(data);
464        self._update_entry(item.debug_name(), 1, num_bytes);
465    }
466
467    /// Logs the stats for the given serialized slice
468    #[cfg(feature = "display_list_stats")]
469    fn log_slice<T: Copy + Default + peek_poke::Peek>(
470        &mut self,
471        slice_name: &'static str,
472        range: &ItemRange<T>,
473    ) {
474        // Run this so log_item_stats is accurate, but ignore its result
475        // because log_slice_stats may be called after multiple slices have been
476        // processed, and the `range` has everything we need.
477        self.last_addr = range.bytes.as_ptr() as usize + range.bytes.len();
478
479        self._update_entry(slice_name, range.iter().len(), range.bytes.len());
480    }
481
482    #[cfg(not(feature = "display_list_stats"))]
483    fn log_slice<T>(&mut self, _slice_name: &str, _range: &ItemRange<T>) {
484        /* no-op */
485    }
486}
487
488/// Stats for an individual item
489#[derive(Copy, Clone, Debug, Default)]
490pub struct ItemStats {
491    /// How many instances of this kind of item we deserialized
492    pub total_count: usize,
493    /// How many bytes we processed for this kind of item
494    pub num_bytes: usize,
495}
496
497pub struct DisplayItemRef<'a: 'b, 'b> {
498    iter: &'b BuiltDisplayListIter<'a>,
499}
500
501// Some of these might just become ItemRanges
502impl<'a, 'b> DisplayItemRef<'a, 'b> {
503    // Creates a new iterator where this element's iterator is, to hack around borrowck.
504    pub fn sub_iter(&self) -> BuiltDisplayListIter<'a> {
505        self.iter.sub_iter()
506    }
507
508    pub fn item(&self) -> &di::DisplayItem {
509        self.iter.current_item()
510    }
511
512    pub fn clip_chain_items(&self) -> ItemRange<di::ClipId> {
513        self.iter.cur_clip_chain_items
514    }
515
516    pub fn points(&self) -> ItemRange<LayoutPoint> {
517        self.iter.cur_points
518    }
519
520    pub fn glyphs(&self) -> ItemRange<GlyphInstance> {
521        self.iter.glyphs()
522    }
523
524    pub fn gradient_stops(&self) -> ItemRange<di::GradientStop> {
525        self.iter.gradient_stops()
526    }
527
528    pub fn filters(&self) -> ItemRange<di::FilterOp> {
529        self.iter.cur_filters
530    }
531
532    pub fn filter_datas(&self) -> &Vec<TempFilterData> {
533        &self.iter.cur_filter_data
534    }
535
536    pub fn filter_primitives(&self) -> ItemRange<di::FilterPrimitive> {
537        self.iter.cur_filter_primitives
538    }
539}
540
541#[derive(PartialEq)]
542enum Peek {
543    StartPeeking,
544    IsPeeking,
545    NotPeeking,
546}
547
548#[derive(Clone)]
549pub struct AuxIter<'a, T> {
550    item: T,
551    data: &'a [u8],
552    size: usize,
553    //    _boo: PhantomData<T>,
554}
555
556impl BuiltDisplayList {
557    pub fn from_data(payload: DisplayListPayload, descriptor: BuiltDisplayListDescriptor) -> Self {
558        BuiltDisplayList {
559            payload,
560            descriptor,
561        }
562    }
563
564    pub fn into_data(self) -> (DisplayListPayload, BuiltDisplayListDescriptor) {
565        (self.payload, self.descriptor)
566    }
567
568    pub fn items_data(&self) -> &[u8] {
569        &self.payload.items_data
570    }
571
572    pub fn cache_data(&self) -> &[u8] {
573        &self.payload.cache_data
574    }
575
576    pub fn descriptor(&self) -> &BuiltDisplayListDescriptor {
577        &self.descriptor
578    }
579
580    pub fn set_send_time_ns(&mut self, time: u64) {
581        self.descriptor.send_start_time = time;
582    }
583
584    pub fn times(&self) -> (u64, u64, u64) {
585        (
586            self.descriptor.builder_start_time,
587            self.descriptor.builder_finish_time,
588            self.descriptor.send_start_time,
589        )
590    }
591
592    pub fn gecko_display_list_stats(&self) -> (f64, bool) {
593        match self.descriptor.gecko_display_list_type {
594            GeckoDisplayListType::Full(duration) => (duration, true),
595            GeckoDisplayListType::Partial(duration) => (duration, false),
596            _ => (0.0, false),
597        }
598    }
599
600    pub fn total_clip_nodes(&self) -> usize {
601        self.descriptor.total_clip_nodes
602    }
603
604    pub fn total_spatial_nodes(&self) -> usize {
605        self.descriptor.total_spatial_nodes
606    }
607
608    pub fn iter(&self) -> BuiltDisplayListIter {
609        BuiltDisplayListIter::new(self.items_data(), None)
610    }
611
612    pub fn cache_data_iter(&self) -> BuiltDisplayListIter {
613        BuiltDisplayListIter::new(self.cache_data(), None)
614    }
615
616    pub fn iter_with_cache<'a>(&'a self, cache: &'a DisplayItemCache) -> BuiltDisplayListIter<'a> {
617        BuiltDisplayListIter::new(self.items_data(), Some(cache))
618    }
619
620    pub fn cache_size(&self) -> usize {
621        self.descriptor.cache_size
622    }
623
624    pub fn size_in_bytes(&self) -> usize {
625        self.payload.size_in_bytes()
626    }
627
628    pub fn iter_spatial_tree<F>(&self, f: F)
629    where
630        F: FnMut(&di::SpatialTreeItem),
631    {
632        iter_spatial_tree(&self.payload.spatial_tree, f)
633    }
634
635    #[cfg(feature = "serialize")]
636    pub fn create_debug_display_items(
637        mut iterator: BuiltDisplayListIter,
638    ) -> Vec<di::DebugDisplayItem> {
639        use di::DisplayItem as Real;
640        use di::DebugDisplayItem as Debug;
641        let mut debug_items = Vec::new();
642
643        while let Some(item) = iterator.next_raw() {
644            let serial_di = match *item.item() {
645                Real::ClipChain(v) => {
646                    Debug::ClipChain(v, item.iter.cur_clip_chain_items.iter().collect())
647                }
648                Real::Text(v) => Debug::Text(v, item.iter.cur_glyphs.iter().collect()),
649                Real::SetFilterOps => Debug::SetFilterOps(item.iter.cur_filters.iter().collect()),
650                Real::SetFilterData => {
651                    debug_assert!(
652                        !item.iter.cur_filter_data.is_empty(),
653                        "next_raw should have populated cur_filter_data"
654                    );
655                    let temp_filter_data =
656                        &item.iter.cur_filter_data[item.iter.cur_filter_data.len() - 1];
657
658                    let func_types: Vec<di::ComponentTransferFuncType> =
659                        temp_filter_data.func_types.iter().collect();
660                    debug_assert!(
661                        func_types.len() == 4,
662                        "someone changed the number of filter funcs without updating this code"
663                    );
664                    Debug::SetFilterData(di::FilterData {
665                        func_r_type: func_types[0],
666                        r_values: temp_filter_data.r_values.iter().collect(),
667                        func_g_type: func_types[1],
668                        g_values: temp_filter_data.g_values.iter().collect(),
669                        func_b_type: func_types[2],
670                        b_values: temp_filter_data.b_values.iter().collect(),
671                        func_a_type: func_types[3],
672                        a_values: temp_filter_data.a_values.iter().collect(),
673                    })
674                }
675                Real::SetFilterPrimitives => {
676                    Debug::SetFilterPrimitives(item.iter.cur_filter_primitives.iter().collect())
677                }
678                Real::SetGradientStops => {
679                    Debug::SetGradientStops(item.iter.cur_stops.iter().collect())
680                }
681                Real::SetPoints => Debug::SetPoints(item.iter.cur_points.iter().collect()),
682                Real::RectClip(v) => Debug::RectClip(v),
683                Real::RoundedRectClip(v) => Debug::RoundedRectClip(v),
684                Real::ImageMaskClip(v) => Debug::ImageMaskClip(v),
685                Real::Rectangle(v) => Debug::Rectangle(v),
686                Real::ClearRectangle(v) => Debug::ClearRectangle(v),
687                Real::HitTest(v) => Debug::HitTest(v),
688                Real::Line(v) => Debug::Line(v),
689                Real::Image(v) => Debug::Image(v),
690                Real::RepeatingImage(v) => Debug::RepeatingImage(v),
691                Real::YuvImage(v) => Debug::YuvImage(v),
692                Real::Border(v) => Debug::Border(v),
693                Real::BoxShadow(v) => Debug::BoxShadow(v),
694                Real::Gradient(v) => Debug::Gradient(v),
695                Real::RadialGradient(v) => Debug::RadialGradient(v),
696                Real::ConicGradient(v) => Debug::ConicGradient(v),
697                Real::Iframe(v) => Debug::Iframe(v),
698                Real::PushReferenceFrame(v) => Debug::PushReferenceFrame(v),
699                Real::PushStackingContext(v) => Debug::PushStackingContext(v),
700                Real::PushShadow(v) => Debug::PushShadow(v),
701                Real::BackdropFilter(v) => Debug::BackdropFilter(v),
702
703                Real::PopReferenceFrame => Debug::PopReferenceFrame,
704                Real::PopStackingContext => Debug::PopStackingContext,
705                Real::PopAllShadows => Debug::PopAllShadows,
706                Real::ReuseItems(_) | Real::RetainedItems(_) => unreachable!("Unexpected item"),
707            };
708            debug_items.push(serial_di);
709        }
710
711        debug_items
712    }
713}
714
715/// Returns the byte-range the slice occupied.
716fn skip_slice<'a, T: peek_poke::Peek>(data: &mut &'a [u8]) -> ItemRange<'a, T> {
717    let mut skip_offset = 0usize;
718    *data = peek_from_slice(data, &mut skip_offset);
719    let (skip, rest) = data.split_at(skip_offset);
720
721    // Adjust data pointer to skip read values
722    *data = rest;
723
724    ItemRange {
725        bytes: skip,
726        _boo: PhantomData,
727    }
728}
729
730impl<'a> BuiltDisplayListIter<'a> {
731    pub fn new(data: &'a [u8], cache: Option<&'a DisplayItemCache>) -> Self {
732        Self {
733            data,
734            cache,
735            pending_items: [].iter(),
736            cur_cached_item: None,
737            cur_item: di::DisplayItem::PopStackingContext,
738            cur_stops: ItemRange::default(),
739            cur_glyphs: ItemRange::default(),
740            cur_filters: ItemRange::default(),
741            cur_filter_data: Vec::new(),
742            cur_filter_primitives: ItemRange::default(),
743            cur_clip_chain_items: ItemRange::default(),
744            cur_points: ItemRange::default(),
745            peeking: Peek::NotPeeking,
746            debug_stats: DebugStats {
747                last_addr: data.as_ptr() as usize,
748                stats: HashMap::default(),
749            },
750        }
751    }
752
753    pub fn sub_iter(&self) -> Self {
754        let mut iter = BuiltDisplayListIter::new(self.data, self.cache);
755        iter.pending_items = self.pending_items.clone();
756        iter
757    }
758
759    pub fn current_item(&self) -> &di::DisplayItem {
760        match self.cur_cached_item {
761            Some(cached_item) => cached_item.display_item(),
762            None => &self.cur_item,
763        }
764    }
765
766    fn cached_item_range_or<T>(&self, data: ItemRange<'a, T>) -> ItemRange<'a, T> {
767        match self.cur_cached_item {
768            Some(cached_item) => cached_item.data_as_item_range(),
769            None => data,
770        }
771    }
772
773    pub fn glyphs(&self) -> ItemRange<GlyphInstance> {
774        self.cached_item_range_or(self.cur_glyphs)
775    }
776
777    pub fn gradient_stops(&self) -> ItemRange<di::GradientStop> {
778        self.cached_item_range_or(self.cur_stops)
779    }
780
781    fn advance_pending_items(&mut self) -> bool {
782        self.cur_cached_item = self.pending_items.next();
783        self.cur_cached_item.is_some()
784    }
785
786    pub fn next<'b>(&'b mut self) -> Option<DisplayItemRef<'a, 'b>> {
787        use crate::DisplayItem::*;
788
789        match self.peeking {
790            Peek::IsPeeking => {
791                self.peeking = Peek::NotPeeking;
792                return Some(self.as_ref());
793            }
794            Peek::StartPeeking => {
795                self.peeking = Peek::IsPeeking;
796            }
797            Peek::NotPeeking => { /* do nothing */ }
798        }
799
800        // Don't let these bleed into another item
801        self.cur_stops = ItemRange::default();
802        self.cur_clip_chain_items = ItemRange::default();
803        self.cur_points = ItemRange::default();
804        self.cur_filters = ItemRange::default();
805        self.cur_filter_primitives = ItemRange::default();
806        self.cur_filter_data.clear();
807
808        loop {
809            self.next_raw()?;
810            match self.cur_item {
811                SetGradientStops | SetFilterOps | SetFilterData | SetFilterPrimitives
812                | SetPoints => {
813                    // These are marker items for populating other display items, don't yield them.
814                    continue;
815                }
816                _ => {
817                    break;
818                }
819            }
820        }
821
822        Some(self.as_ref())
823    }
824
825    /// Gets the next display item, even if it's a dummy. Also doesn't handle peeking
826    /// and may leave irrelevant ranges live (so a Clip may have GradientStops if
827    /// for some reason you ask).
828    pub fn next_raw<'b>(&'b mut self) -> Option<DisplayItemRef<'a, 'b>> {
829        use crate::DisplayItem::*;
830
831        if self.advance_pending_items() {
832            return Some(self.as_ref());
833        }
834
835        // A "red zone" of DisplayItem::max_size() bytes has been added to the
836        // end of the serialized display list. If this amount, or less, is
837        // remaining then we've reached the end of the display list.
838        if self.data.len() <= di::DisplayItem::max_size() {
839            return None;
840        }
841
842        self.data = peek_from_slice(self.data, &mut self.cur_item);
843        self.log_item_stats();
844
845        match self.cur_item {
846            SetGradientStops => {
847                self.cur_stops = skip_slice::<di::GradientStop>(&mut self.data);
848                self.debug_stats
849                    .log_slice("set_gradient_stops.stops", &self.cur_stops);
850            }
851            SetFilterOps => {
852                self.cur_filters = skip_slice::<di::FilterOp>(&mut self.data);
853                self.debug_stats
854                    .log_slice("set_filter_ops.ops", &self.cur_filters);
855            }
856            SetFilterData => {
857                self.cur_filter_data.push(TempFilterData {
858                    func_types: skip_slice::<di::ComponentTransferFuncType>(&mut self.data),
859                    r_values: skip_slice::<f32>(&mut self.data),
860                    g_values: skip_slice::<f32>(&mut self.data),
861                    b_values: skip_slice::<f32>(&mut self.data),
862                    a_values: skip_slice::<f32>(&mut self.data),
863                });
864
865                let data = *self.cur_filter_data.last().unwrap();
866                self.debug_stats
867                    .log_slice("set_filter_data.func_types", &data.func_types);
868                self.debug_stats
869                    .log_slice("set_filter_data.r_values", &data.r_values);
870                self.debug_stats
871                    .log_slice("set_filter_data.g_values", &data.g_values);
872                self.debug_stats
873                    .log_slice("set_filter_data.b_values", &data.b_values);
874                self.debug_stats
875                    .log_slice("set_filter_data.a_values", &data.a_values);
876            }
877            SetFilterPrimitives => {
878                self.cur_filter_primitives = skip_slice::<di::FilterPrimitive>(&mut self.data);
879                self.debug_stats.log_slice(
880                    "set_filter_primitives.primitives",
881                    &self.cur_filter_primitives,
882                );
883            }
884            SetPoints => {
885                self.cur_points = skip_slice::<LayoutPoint>(&mut self.data);
886                self.debug_stats
887                    .log_slice("set_points.points", &self.cur_points);
888            }
889            ClipChain(_) => {
890                self.cur_clip_chain_items = skip_slice::<di::ClipId>(&mut self.data);
891                self.debug_stats
892                    .log_slice("clip_chain.clip_ids", &self.cur_clip_chain_items);
893            }
894            Text(_) => {
895                self.cur_glyphs = skip_slice::<GlyphInstance>(&mut self.data);
896                self.debug_stats.log_slice("text.glyphs", &self.cur_glyphs);
897            }
898            ReuseItems(key) => match self.cache {
899                Some(cache) => {
900                    self.pending_items = cache.get_items(key).iter();
901                    self.advance_pending_items();
902                }
903                None => {
904                    unreachable!("Cache marker without cache!");
905                }
906            },
907            _ => { /* do nothing */ }
908        }
909
910        Some(self.as_ref())
911    }
912
913    pub fn as_ref<'b>(&'b self) -> DisplayItemRef<'a, 'b> {
914        DisplayItemRef { iter: self }
915    }
916
917    pub fn skip_current_stacking_context(&mut self) {
918        let mut depth = 0;
919        while let Some(item) = self.next() {
920            match *item.item() {
921                di::DisplayItem::PushStackingContext(..) => depth += 1,
922                di::DisplayItem::PopStackingContext if depth == 0 => return,
923                di::DisplayItem::PopStackingContext => depth -= 1,
924                _ => {}
925            }
926        }
927    }
928
929    pub fn current_stacking_context_empty(&mut self) -> bool {
930        match self.peek() {
931            Some(item) => *item.item() == di::DisplayItem::PopStackingContext,
932            None => true,
933        }
934    }
935
936    pub fn peek<'b>(&'b mut self) -> Option<DisplayItemRef<'a, 'b>> {
937        if self.peeking == Peek::NotPeeking {
938            self.peeking = Peek::StartPeeking;
939            self.next()
940        } else {
941            Some(self.as_ref())
942        }
943    }
944
945    /// Get the debug stats for what this iterator has deserialized.
946    /// Should always be empty in release builds.
947    pub fn debug_stats(&mut self) -> Vec<(&'static str, ItemStats)> {
948        let mut result = self.debug_stats.stats.drain().collect::<Vec<_>>();
949        result.sort_by_key(|stats| stats.0);
950        result
951    }
952
953    /// Adds the debug stats from another to our own, assuming we are a sub-iter of the other
954    /// (so we can ignore where they were in the traversal).
955    pub fn merge_debug_stats_from(&mut self, other: &mut Self) {
956        for (key, other_entry) in other.debug_stats.stats.iter() {
957            let entry = self.debug_stats.stats.entry(key).or_default();
958
959            entry.total_count += other_entry.total_count;
960            entry.num_bytes += other_entry.num_bytes;
961        }
962    }
963
964    /// Logs stats for the last deserialized display item
965    #[cfg(feature = "display_list_stats")]
966    fn log_item_stats(&mut self) {
967        self.debug_stats.log_item(self.data, &self.cur_item);
968    }
969
970    #[cfg(not(feature = "display_list_stats"))]
971    fn log_item_stats(&mut self) { /* no-op */
972    }
973}
974
975impl<'a, T> AuxIter<'a, T> {
976    pub fn new(item: T, mut data: &'a [u8]) -> Self {
977        let mut size = 0usize;
978        if !data.is_empty() {
979            data = peek_from_slice(data, &mut size);
980        };
981
982        AuxIter {
983            item,
984            data,
985            size,
986            //            _boo: PhantomData,
987        }
988    }
989}
990
991impl<'a, T: Copy + peek_poke::Peek> Iterator for AuxIter<'a, T> {
992    type Item = T;
993
994    fn next(&mut self) -> Option<Self::Item> {
995        if self.size == 0 {
996            None
997        } else {
998            self.size -= 1;
999            self.data = peek_from_slice(self.data, &mut self.item);
1000            Some(self.item)
1001        }
1002    }
1003
1004    fn size_hint(&self) -> (usize, Option<usize>) {
1005        (self.size, Some(self.size))
1006    }
1007}
1008
1009impl<'a, T: Copy + peek_poke::Peek> ::std::iter::ExactSizeIterator for AuxIter<'a, T> {}
1010
1011#[derive(Clone, Debug)]
1012pub struct SaveState {
1013    dl_items_len: usize,
1014    dl_cache_len: usize,
1015    next_clip_index: usize,
1016    next_spatial_index: usize,
1017    next_clip_chain_id: u64,
1018}
1019
1020/// DisplayListSection determines the target buffer for the display items.
1021pub enum DisplayListSection {
1022    /// The main/default buffer: contains item data and item group markers.
1023    Data,
1024    /// Auxiliary buffer: contains the item data for item groups.
1025    CacheData,
1026    /// Temporary buffer: contains the data for pending item group. Flushed to
1027    /// one of the buffers above, after item grouping finishes.
1028    Chunk,
1029}
1030
1031pub struct DisplayListBuilder {
1032    payload: DisplayListPayload,
1033    pub pipeline_id: PipelineId,
1034
1035    pending_chunk: Vec<u8>,
1036    writing_to_chunk: bool,
1037
1038    next_clip_index: usize,
1039    next_spatial_index: usize,
1040    next_clip_chain_id: u64,
1041    builder_start_time: u64,
1042
1043    save_state: Option<SaveState>,
1044
1045    cache_size: usize,
1046    serialized_content_buffer: Option<String>,
1047    state: BuildState,
1048
1049    /// Helper struct to map stacking context coords <-> reference frame coords.
1050    rf_mapper: ReferenceFrameMapper,
1051}
1052
1053#[repr(C)]
1054struct DisplayListCapacity {
1055    items_size: usize,
1056    cache_size: usize,
1057    spatial_tree_size: usize,
1058}
1059
1060impl DisplayListCapacity {
1061    fn empty() -> Self {
1062        DisplayListCapacity {
1063            items_size: 0,
1064            cache_size: 0,
1065            spatial_tree_size: 0,
1066        }
1067    }
1068}
1069
1070impl DisplayListBuilder {
1071    pub fn new(pipeline_id: PipelineId) -> Self {
1072        DisplayListBuilder {
1073            payload: DisplayListPayload::new(DisplayListCapacity::empty()),
1074            pipeline_id,
1075
1076            pending_chunk: Vec::new(),
1077            writing_to_chunk: false,
1078
1079            next_clip_index: FIRST_CLIP_NODE_INDEX,
1080            next_spatial_index: FIRST_SPATIAL_NODE_INDEX,
1081            next_clip_chain_id: 0,
1082            builder_start_time: 0,
1083            save_state: None,
1084            cache_size: 0,
1085            serialized_content_buffer: None,
1086            state: BuildState::Idle,
1087
1088            rf_mapper: ReferenceFrameMapper::new(),
1089        }
1090    }
1091
1092    fn reset(&mut self) {
1093        self.payload.clear();
1094        self.pending_chunk.clear();
1095        self.writing_to_chunk = false;
1096
1097        self.next_clip_index = FIRST_CLIP_NODE_INDEX;
1098        self.next_spatial_index = FIRST_SPATIAL_NODE_INDEX;
1099        self.next_clip_chain_id = 0;
1100
1101        self.save_state = None;
1102        self.cache_size = 0;
1103        self.serialized_content_buffer = None;
1104
1105        self.rf_mapper = ReferenceFrameMapper::new();
1106    }
1107
1108    /// Saves the current display list state, so it may be `restore()`'d.
1109    ///
1110    /// # Conditions:
1111    ///
1112    /// * Doesn't support popping clips that were pushed before the save.
1113    /// * Doesn't support nested saves.
1114    /// * Must call `clear_save()` if the restore becomes unnecessary.
1115    pub fn save(&mut self) {
1116        assert!(
1117            self.save_state.is_none(),
1118            "DisplayListBuilder doesn't support nested saves"
1119        );
1120
1121        self.save_state = Some(SaveState {
1122            dl_items_len: self.payload.items_data.len(),
1123            dl_cache_len: self.payload.cache_data.len(),
1124            next_clip_index: self.next_clip_index,
1125            next_spatial_index: self.next_spatial_index,
1126            next_clip_chain_id: self.next_clip_chain_id,
1127        });
1128    }
1129
1130    /// Restores the state of the builder to when `save()` was last called.
1131    pub fn restore(&mut self) {
1132        let state = self
1133            .save_state
1134            .take()
1135            .expect("No save to restore DisplayListBuilder from");
1136
1137        self.payload.items_data.truncate(state.dl_items_len);
1138        self.payload.cache_data.truncate(state.dl_cache_len);
1139        self.next_clip_index = state.next_clip_index;
1140        self.next_spatial_index = state.next_spatial_index;
1141        self.next_clip_chain_id = state.next_clip_chain_id;
1142    }
1143
1144    /// Discards the builder's save (indicating the attempted operation was successful).
1145    pub fn clear_save(&mut self) {
1146        self.save_state
1147            .take()
1148            .expect("No save to clear in DisplayListBuilder");
1149    }
1150
1151    /// Emits a debug representation of display items in the list, for debugging
1152    /// purposes. If the range's start parameter is specified, only display
1153    /// items starting at that index (inclusive) will be printed. If the range's
1154    /// end parameter is specified, only display items before that index
1155    /// (exclusive) will be printed. Calling this function with end <= start is
1156    /// allowed but is just a waste of CPU cycles. The function emits the
1157    /// debug representation of the selected display items, one per line, with
1158    /// the given indent, to the provided sink object. The return value is
1159    /// the total number of items in the display list, which allows the
1160    /// caller to subsequently invoke this function to only dump the newly-added
1161    /// items.
1162    pub fn emit_display_list<W>(
1163        &mut self,
1164        indent: usize,
1165        range: Range<Option<usize>>,
1166        mut sink: W,
1167    ) -> usize
1168    where
1169        W: Write,
1170    {
1171        let mut temp = BuiltDisplayList::default();
1172        ensure_red_zone::<di::DisplayItem>(&mut self.payload.items_data);
1173        ensure_red_zone::<di::DisplayItem>(&mut self.payload.cache_data);
1174        mem::swap(&mut temp.payload, &mut self.payload);
1175
1176        let mut index: usize = 0;
1177        {
1178            let mut cache = DisplayItemCache::new();
1179            cache.update(&temp);
1180            let mut iter = temp.iter_with_cache(&cache);
1181            while let Some(item) = iter.next_raw() {
1182                if index >= range.start.unwrap_or(0) && range.end.map_or(true, |e| index < e) {
1183                    writeln!(sink, "{}{:?}", "  ".repeat(indent), item.item()).unwrap();
1184                }
1185                index += 1;
1186            }
1187        }
1188
1189        self.payload = temp.payload;
1190        strip_red_zone::<di::DisplayItem>(&mut self.payload.items_data);
1191        strip_red_zone::<di::DisplayItem>(&mut self.payload.cache_data);
1192        index
1193    }
1194
1195    /// Print the display items in the list to stdout.
1196    pub fn dump_serialized_display_list(&mut self) {
1197        self.serialized_content_buffer = Some(String::new());
1198    }
1199
1200    fn add_to_display_list_dump<T: std::fmt::Debug>(&mut self, item: T) {
1201        if let Some(ref mut content) = self.serialized_content_buffer {
1202            use std::fmt::Write;
1203            write!(content, "{:?}\n", item).expect("DL dump write failed.");
1204        }
1205    }
1206
1207    /// Returns the default section that DisplayListBuilder will write to,
1208    /// if no section is specified explicitly.
1209    fn default_section(&self) -> DisplayListSection {
1210        if self.writing_to_chunk {
1211            DisplayListSection::Chunk
1212        } else {
1213            DisplayListSection::Data
1214        }
1215    }
1216
1217    fn buffer_from_section(&mut self, section: DisplayListSection) -> &mut Vec<u8> {
1218        match section {
1219            DisplayListSection::Data => &mut self.payload.items_data,
1220            DisplayListSection::CacheData => &mut self.payload.cache_data,
1221            DisplayListSection::Chunk => &mut self.pending_chunk,
1222        }
1223    }
1224
1225    #[inline]
1226    pub fn push_item_to_section(&mut self, item: &di::DisplayItem, section: DisplayListSection) {
1227        debug_assert_eq!(self.state, BuildState::Build);
1228        poke_into_vec(item, self.buffer_from_section(section));
1229        self.add_to_display_list_dump(item);
1230    }
1231
1232    /// Add an item to the display list.
1233    ///
1234    /// NOTE: It is usually preferable to use the specialized methods to push
1235    /// display items. Pushing unexpected or invalid items here may
1236    /// result in WebRender panicking or behaving in unexpected ways.
1237    #[inline]
1238    pub fn push_item(&mut self, item: &di::DisplayItem) {
1239        self.push_item_to_section(item, self.default_section());
1240    }
1241
1242    #[inline]
1243    pub fn push_spatial_tree_item(&mut self, item: &di::SpatialTreeItem) {
1244        debug_assert_eq!(self.state, BuildState::Build);
1245        poke_into_vec(item, &mut self.payload.spatial_tree);
1246    }
1247
1248    fn push_iter_impl<I>(data: &mut Vec<u8>, iter_source: I)
1249    where
1250        I: IntoIterator,
1251        I::IntoIter: ExactSizeIterator,
1252        I::Item: Poke,
1253    {
1254        let iter = iter_source.into_iter();
1255        let len = iter.len();
1256        // Format:
1257        // payload_byte_size: usize, item_count: usize, [I; item_count]
1258
1259        // Track the the location of where to write byte size with offsets
1260        // instead of pointers because data may be moved in memory during
1261        // `serialize_iter_fast`.
1262        let byte_size_offset = data.len();
1263
1264        // We write a dummy value so there's room for later
1265        poke_into_vec(&0usize, data);
1266        poke_into_vec(&len, data);
1267        let count = poke_extend_vec(iter, data);
1268        debug_assert_eq!(len, count, "iterator.len() returned two different values");
1269
1270        // Add red zone
1271        ensure_red_zone::<I::Item>(data);
1272
1273        // Now write the actual byte_size
1274        let final_offset = data.len();
1275        debug_assert!(
1276            final_offset >= (byte_size_offset + mem::size_of::<usize>()),
1277            "space was never allocated for this array's byte_size"
1278        );
1279        let byte_size = final_offset - byte_size_offset - mem::size_of::<usize>();
1280        poke_inplace_slice(&byte_size, &mut data[byte_size_offset..]);
1281    }
1282
1283    /// Push items from an iterator to the display list.
1284    ///
1285    /// NOTE: Pushing unexpected or invalid items to the display list
1286    /// may result in panic and confusion.
1287    pub fn push_iter<I>(&mut self, iter: I)
1288    where
1289        I: IntoIterator,
1290        I::IntoIter: ExactSizeIterator,
1291        I::Item: Poke,
1292    {
1293        assert_eq!(self.state, BuildState::Build);
1294
1295        let mut buffer = self.buffer_from_section(self.default_section());
1296        Self::push_iter_impl(&mut buffer, iter);
1297    }
1298
1299    // Remap a clip/bounds from stacking context coords to reference frame relative
1300    fn remap_common_coordinates_and_bounds(
1301        &self,
1302        common: &di::CommonItemProperties,
1303        bounds: LayoutRect,
1304    ) -> (di::CommonItemProperties, LayoutRect) {
1305        let offset = self.rf_mapper.current_offset();
1306
1307        (
1308            di::CommonItemProperties {
1309                clip_rect: common.clip_rect.translate(offset),
1310                ..*common
1311            },
1312            bounds.translate(offset),
1313        )
1314    }
1315
1316    // Remap a bounds from stacking context coords to reference frame relative
1317    fn remap_bounds(
1318        &self,
1319        bounds: LayoutRect,
1320    ) -> LayoutRect {
1321        let offset = self.rf_mapper.current_offset();
1322
1323        bounds.translate(offset)
1324    }
1325
1326    pub fn push_rect(
1327        &mut self,
1328        common: &di::CommonItemProperties,
1329        bounds: LayoutRect,
1330        color: ColorF,
1331    ) {
1332        let (common, bounds) = self.remap_common_coordinates_and_bounds(common, bounds);
1333
1334        let item = di::DisplayItem::Rectangle(di::RectangleDisplayItem {
1335            common,
1336            color: PropertyBinding::Value(color),
1337            bounds,
1338        });
1339        self.push_item(&item);
1340    }
1341
1342    pub fn push_rect_with_animation(
1343        &mut self,
1344        common: &di::CommonItemProperties,
1345        bounds: LayoutRect,
1346        color: PropertyBinding<ColorF>,
1347    ) {
1348        let (common, bounds) = self.remap_common_coordinates_and_bounds(common, bounds);
1349
1350        let item = di::DisplayItem::Rectangle(di::RectangleDisplayItem {
1351            common,
1352            color,
1353            bounds,
1354        });
1355        self.push_item(&item);
1356    }
1357
1358    pub fn push_clear_rect(
1359        &mut self,
1360        common: &di::CommonItemProperties,
1361        bounds: LayoutRect,
1362    ) {
1363        let (common, bounds) = self.remap_common_coordinates_and_bounds(common, bounds);
1364
1365        let item = di::DisplayItem::ClearRectangle(di::ClearRectangleDisplayItem {
1366            common,
1367            bounds,
1368        });
1369        self.push_item(&item);
1370    }
1371
1372    pub fn push_hit_test(
1373        &mut self,
1374        rect: LayoutRect,
1375        clip_chain_id: di::ClipChainId,
1376        spatial_id: di::SpatialId,
1377        flags: di::PrimitiveFlags,
1378        tag: di::ItemTag,
1379    ) {
1380        let rect = self.remap_bounds(rect);
1381
1382        let item = di::DisplayItem::HitTest(di::HitTestDisplayItem {
1383            rect,
1384            clip_chain_id,
1385            spatial_id,
1386            flags,
1387            tag,
1388        });
1389        self.push_item(&item);
1390    }
1391
1392    pub fn push_line(
1393        &mut self,
1394        common: &di::CommonItemProperties,
1395        area: &LayoutRect,
1396        wavy_line_thickness: f32,
1397        orientation: di::LineOrientation,
1398        color: &ColorF,
1399        style: di::LineStyle,
1400    ) {
1401        let (common, area) = self.remap_common_coordinates_and_bounds(common, *area);
1402
1403        let item = di::DisplayItem::Line(di::LineDisplayItem {
1404            common,
1405            area,
1406            wavy_line_thickness,
1407            orientation,
1408            color: *color,
1409            style,
1410        });
1411
1412        self.push_item(&item);
1413    }
1414
1415    pub fn push_image(
1416        &mut self,
1417        common: &di::CommonItemProperties,
1418        bounds: LayoutRect,
1419        image_rendering: di::ImageRendering,
1420        alpha_type: di::AlphaType,
1421        key: ImageKey,
1422        color: ColorF,
1423    ) {
1424        let (common, bounds) = self.remap_common_coordinates_and_bounds(common, bounds);
1425
1426        let item = di::DisplayItem::Image(di::ImageDisplayItem {
1427            common,
1428            bounds,
1429            image_key: key,
1430            image_rendering,
1431            alpha_type,
1432            color,
1433        });
1434
1435        self.push_item(&item);
1436    }
1437
1438    pub fn push_repeating_image(
1439        &mut self,
1440        common: &di::CommonItemProperties,
1441        bounds: LayoutRect,
1442        stretch_size: LayoutSize,
1443        tile_spacing: LayoutSize,
1444        image_rendering: di::ImageRendering,
1445        alpha_type: di::AlphaType,
1446        key: ImageKey,
1447        color: ColorF,
1448    ) {
1449        let (common, bounds) = self.remap_common_coordinates_and_bounds(common, bounds);
1450
1451        let item = di::DisplayItem::RepeatingImage(di::RepeatingImageDisplayItem {
1452            common,
1453            bounds,
1454            image_key: key,
1455            stretch_size,
1456            tile_spacing,
1457            image_rendering,
1458            alpha_type,
1459            color,
1460        });
1461
1462        self.push_item(&item);
1463    }
1464
1465    /// Push a yuv image. All planar data in yuv image should use the same buffer type.
1466    pub fn push_yuv_image(
1467        &mut self,
1468        common: &di::CommonItemProperties,
1469        bounds: LayoutRect,
1470        yuv_data: di::YuvData,
1471        color_depth: ColorDepth,
1472        color_space: di::YuvColorSpace,
1473        color_range: di::ColorRange,
1474        image_rendering: di::ImageRendering,
1475    ) {
1476        let (common, bounds) = self.remap_common_coordinates_and_bounds(common, bounds);
1477
1478        let item = di::DisplayItem::YuvImage(di::YuvImageDisplayItem {
1479            common,
1480            bounds,
1481            yuv_data,
1482            color_depth,
1483            color_space,
1484            color_range,
1485            image_rendering,
1486        });
1487        self.push_item(&item);
1488    }
1489
1490    pub fn push_text(
1491        &mut self,
1492        common: &di::CommonItemProperties,
1493        bounds: LayoutRect,
1494        glyphs: &[GlyphInstance],
1495        font_key: FontInstanceKey,
1496        color: ColorF,
1497        glyph_options: Option<GlyphOptions>,
1498    ) {
1499        let (common, bounds) = self.remap_common_coordinates_and_bounds(common, bounds);
1500        let ref_frame_offset = self.rf_mapper.current_offset();
1501
1502        let item = di::DisplayItem::Text(di::TextDisplayItem {
1503            common,
1504            bounds,
1505            color,
1506            font_key,
1507            glyph_options,
1508            ref_frame_offset,
1509        });
1510
1511        for split_glyphs in glyphs.chunks(MAX_TEXT_RUN_LENGTH) {
1512            self.push_item(&item);
1513            self.push_iter(split_glyphs);
1514        }
1515    }
1516
1517    /// NOTE: gradients must be pushed in the order they're created
1518    /// because create_gradient stores the stops in anticipation.
1519    pub fn create_gradient(
1520        &mut self,
1521        start_point: LayoutPoint,
1522        end_point: LayoutPoint,
1523        stops: Vec<di::GradientStop>,
1524        extend_mode: di::ExtendMode,
1525    ) -> di::Gradient {
1526        let mut builder = GradientBuilder::with_stops(stops);
1527        let gradient = builder.gradient(start_point, end_point, extend_mode);
1528        self.push_stops(builder.stops());
1529        gradient
1530    }
1531
1532    /// NOTE: gradients must be pushed in the order they're created
1533    /// because create_gradient stores the stops in anticipation.
1534    pub fn create_radial_gradient(
1535        &mut self,
1536        center: LayoutPoint,
1537        radius: LayoutSize,
1538        stops: Vec<di::GradientStop>,
1539        extend_mode: di::ExtendMode,
1540    ) -> di::RadialGradient {
1541        let mut builder = GradientBuilder::with_stops(stops);
1542        let gradient = builder.radial_gradient(center, radius, extend_mode);
1543        self.push_stops(builder.stops());
1544        gradient
1545    }
1546
1547    /// NOTE: gradients must be pushed in the order they're created
1548    /// because create_gradient stores the stops in anticipation.
1549    pub fn create_conic_gradient(
1550        &mut self,
1551        center: LayoutPoint,
1552        angle: f32,
1553        stops: Vec<di::GradientStop>,
1554        extend_mode: di::ExtendMode,
1555    ) -> di::ConicGradient {
1556        let mut builder = GradientBuilder::with_stops(stops);
1557        let gradient = builder.conic_gradient(center, angle, extend_mode);
1558        self.push_stops(builder.stops());
1559        gradient
1560    }
1561
1562    pub fn push_border(
1563        &mut self,
1564        common: &di::CommonItemProperties,
1565        bounds: LayoutRect,
1566        widths: LayoutSideOffsets,
1567        details: di::BorderDetails,
1568    ) {
1569        let (common, bounds) = self.remap_common_coordinates_and_bounds(common, bounds);
1570
1571        let item = di::DisplayItem::Border(di::BorderDisplayItem {
1572            common,
1573            bounds,
1574            details,
1575            widths,
1576        });
1577
1578        self.push_item(&item);
1579    }
1580
1581    pub fn push_box_shadow(
1582        &mut self,
1583        common: &di::CommonItemProperties,
1584        box_bounds: LayoutRect,
1585        offset: LayoutVector2D,
1586        color: ColorF,
1587        blur_radius: f32,
1588        spread_radius: f32,
1589        border_radius: di::BorderRadius,
1590        clip_mode: di::BoxShadowClipMode,
1591    ) {
1592        let (common, box_bounds) = self.remap_common_coordinates_and_bounds(common, box_bounds);
1593
1594        let item = di::DisplayItem::BoxShadow(di::BoxShadowDisplayItem {
1595            common,
1596            box_bounds,
1597            offset,
1598            color,
1599            blur_radius,
1600            spread_radius,
1601            border_radius,
1602            clip_mode,
1603        });
1604
1605        self.push_item(&item);
1606    }
1607
1608    /// Pushes a linear gradient to be displayed.
1609    ///
1610    /// The gradient itself is described in the
1611    /// `gradient` parameter. It is drawn on
1612    /// a "tile" with the dimensions from `tile_size`.
1613    /// These tiles are now repeated to the right and
1614    /// to the bottom infinitely. If `tile_spacing`
1615    /// is not zero spacers with the given dimensions
1616    /// are inserted between the tiles as seams.
1617    ///
1618    /// The origin of the tiles is given in `layout.rect.origin`.
1619    /// If the gradient should only be displayed once limit
1620    /// the `layout.rect.size` to a single tile.
1621    /// The gradient is only visible within the local clip.
1622    pub fn push_gradient(
1623        &mut self,
1624        common: &di::CommonItemProperties,
1625        bounds: LayoutRect,
1626        gradient: di::Gradient,
1627        tile_size: LayoutSize,
1628        tile_spacing: LayoutSize,
1629    ) {
1630        let (common, bounds) = self.remap_common_coordinates_and_bounds(common, bounds);
1631
1632        let item = di::DisplayItem::Gradient(di::GradientDisplayItem {
1633            common,
1634            bounds,
1635            gradient,
1636            tile_size,
1637            tile_spacing,
1638        });
1639
1640        self.push_item(&item);
1641    }
1642
1643    /// Pushes a radial gradient to be displayed.
1644    ///
1645    /// See [`push_gradient`](#method.push_gradient) for explanation.
1646    pub fn push_radial_gradient(
1647        &mut self,
1648        common: &di::CommonItemProperties,
1649        bounds: LayoutRect,
1650        gradient: di::RadialGradient,
1651        tile_size: LayoutSize,
1652        tile_spacing: LayoutSize,
1653    ) {
1654        let (common, bounds) = self.remap_common_coordinates_and_bounds(common, bounds);
1655
1656        let item = di::DisplayItem::RadialGradient(di::RadialGradientDisplayItem {
1657            common,
1658            bounds,
1659            gradient,
1660            tile_size,
1661            tile_spacing,
1662        });
1663
1664        self.push_item(&item);
1665    }
1666
1667    /// Pushes a conic gradient to be displayed.
1668    ///
1669    /// See [`push_gradient`](#method.push_gradient) for explanation.
1670    pub fn push_conic_gradient(
1671        &mut self,
1672        common: &di::CommonItemProperties,
1673        bounds: LayoutRect,
1674        gradient: di::ConicGradient,
1675        tile_size: LayoutSize,
1676        tile_spacing: LayoutSize,
1677    ) {
1678        let (common, bounds) = self.remap_common_coordinates_and_bounds(common, bounds);
1679
1680        let item = di::DisplayItem::ConicGradient(di::ConicGradientDisplayItem {
1681            common,
1682            bounds,
1683            gradient,
1684            tile_size,
1685            tile_spacing,
1686        });
1687
1688        self.push_item(&item);
1689    }
1690
1691    pub fn push_reference_frame(
1692        &mut self,
1693        origin: LayoutPoint,
1694        parent_spatial_id: di::SpatialId,
1695        transform_style: di::TransformStyle,
1696        transform: PropertyBinding<LayoutTransform>,
1697        kind: di::ReferenceFrameKind,
1698        key: di::SpatialTreeItemKey,
1699    ) -> di::SpatialId {
1700        let id = self.generate_spatial_index();
1701
1702        let current_offset = self.rf_mapper.current_offset();
1703        let origin = origin + current_offset;
1704
1705        let descriptor = di::SpatialTreeItem::ReferenceFrame(di::ReferenceFrameDescriptor {
1706            parent_spatial_id,
1707            origin,
1708            reference_frame: di::ReferenceFrame {
1709                transform_style,
1710                transform: di::ReferenceTransformBinding::Static { binding: transform },
1711                kind,
1712                id,
1713                key,
1714            },
1715        });
1716        self.push_spatial_tree_item(&descriptor);
1717
1718        self.rf_mapper.push_scope();
1719
1720        let item = di::DisplayItem::PushReferenceFrame(di::ReferenceFrameDisplayListItem {});
1721        self.push_item(&item);
1722
1723        id
1724    }
1725
1726    pub fn push_computed_frame(
1727        &mut self,
1728        origin: LayoutPoint,
1729        parent_spatial_id: di::SpatialId,
1730        scale_from: Option<LayoutSize>,
1731        vertical_flip: bool,
1732        rotation: di::Rotation,
1733        key: di::SpatialTreeItemKey,
1734    ) -> di::SpatialId {
1735        let id = self.generate_spatial_index();
1736
1737        let current_offset = self.rf_mapper.current_offset();
1738        let origin = origin + current_offset;
1739
1740        let descriptor = di::SpatialTreeItem::ReferenceFrame(di::ReferenceFrameDescriptor {
1741            parent_spatial_id,
1742            origin,
1743            reference_frame: di::ReferenceFrame {
1744                transform_style: di::TransformStyle::Flat,
1745                transform: di::ReferenceTransformBinding::Computed {
1746                    scale_from,
1747                    vertical_flip,
1748                    rotation,
1749                },
1750                kind: di::ReferenceFrameKind::Transform {
1751                    is_2d_scale_translation: false,
1752                    should_snap: false,
1753                    paired_with_perspective: false,
1754                },
1755                id,
1756                key,
1757            },
1758        });
1759        self.push_spatial_tree_item(&descriptor);
1760
1761        self.rf_mapper.push_scope();
1762
1763        let item = di::DisplayItem::PushReferenceFrame(di::ReferenceFrameDisplayListItem {});
1764        self.push_item(&item);
1765
1766        id
1767    }
1768
1769    pub fn pop_reference_frame(&mut self) {
1770        self.rf_mapper.pop_scope();
1771        self.push_item(&di::DisplayItem::PopReferenceFrame);
1772    }
1773
1774    pub fn push_stacking_context(
1775        &mut self,
1776        origin: LayoutPoint,
1777        spatial_id: di::SpatialId,
1778        prim_flags: di::PrimitiveFlags,
1779        clip_chain_id: Option<di::ClipChainId>,
1780        transform_style: di::TransformStyle,
1781        mix_blend_mode: di::MixBlendMode,
1782        filters: &[di::FilterOp],
1783        filter_datas: &[di::FilterData],
1784        filter_primitives: &[di::FilterPrimitive],
1785        raster_space: di::RasterSpace,
1786        flags: di::StackingContextFlags,
1787    ) {
1788        let ref_frame_offset = self.rf_mapper.current_offset();
1789        self.push_filters(filters, filter_datas, filter_primitives);
1790
1791        let item = di::DisplayItem::PushStackingContext(di::PushStackingContextDisplayItem {
1792            origin,
1793            spatial_id,
1794            prim_flags,
1795            ref_frame_offset,
1796            stacking_context: di::StackingContext {
1797                transform_style,
1798                mix_blend_mode,
1799                clip_chain_id,
1800                raster_space,
1801                flags,
1802            },
1803        });
1804
1805        self.rf_mapper.push_offset(origin.to_vector());
1806        self.push_item(&item);
1807    }
1808
1809    /// Helper for examples/ code.
1810    pub fn push_simple_stacking_context(
1811        &mut self,
1812        origin: LayoutPoint,
1813        spatial_id: di::SpatialId,
1814        prim_flags: di::PrimitiveFlags,
1815    ) {
1816        self.push_simple_stacking_context_with_filters(
1817            origin,
1818            spatial_id,
1819            prim_flags,
1820            &[],
1821            &[],
1822            &[],
1823        );
1824    }
1825
1826    /// Helper for examples/ code.
1827    pub fn push_simple_stacking_context_with_filters(
1828        &mut self,
1829        origin: LayoutPoint,
1830        spatial_id: di::SpatialId,
1831        prim_flags: di::PrimitiveFlags,
1832        filters: &[di::FilterOp],
1833        filter_datas: &[di::FilterData],
1834        filter_primitives: &[di::FilterPrimitive],
1835    ) {
1836        self.push_stacking_context(
1837            origin,
1838            spatial_id,
1839            prim_flags,
1840            None,
1841            di::TransformStyle::Flat,
1842            di::MixBlendMode::Normal,
1843            filters,
1844            filter_datas,
1845            filter_primitives,
1846            di::RasterSpace::Screen,
1847            di::StackingContextFlags::empty(),
1848        );
1849    }
1850
1851    pub fn pop_stacking_context(&mut self) {
1852        self.rf_mapper.pop_offset();
1853        self.push_item(&di::DisplayItem::PopStackingContext);
1854    }
1855
1856    pub fn push_stops(&mut self, stops: &[di::GradientStop]) {
1857        if stops.is_empty() {
1858            return;
1859        }
1860        self.push_item(&di::DisplayItem::SetGradientStops);
1861        self.push_iter(stops);
1862    }
1863
1864    pub fn push_backdrop_filter(
1865        &mut self,
1866        common: &di::CommonItemProperties,
1867        filters: &[di::FilterOp],
1868        filter_datas: &[di::FilterData],
1869        filter_primitives: &[di::FilterPrimitive],
1870    ) {
1871        let common = di::CommonItemProperties {
1872            clip_rect: self.remap_bounds(common.clip_rect),
1873            ..*common
1874        };
1875
1876        self.push_filters(filters, filter_datas, filter_primitives);
1877
1878        let item = di::DisplayItem::BackdropFilter(di::BackdropFilterDisplayItem {
1879            common,
1880        });
1881        self.push_item(&item);
1882    }
1883
1884    pub fn push_filters(
1885        &mut self,
1886        filters: &[di::FilterOp],
1887        filter_datas: &[di::FilterData],
1888        filter_primitives: &[di::FilterPrimitive],
1889    ) {
1890        if !filters.is_empty() {
1891            self.push_item(&di::DisplayItem::SetFilterOps);
1892            self.push_iter(filters);
1893        }
1894
1895        for filter_data in filter_datas {
1896            let func_types = [
1897                filter_data.func_r_type,
1898                filter_data.func_g_type,
1899                filter_data.func_b_type,
1900                filter_data.func_a_type,
1901            ];
1902            self.push_item(&di::DisplayItem::SetFilterData);
1903            self.push_iter(&func_types);
1904            self.push_iter(&filter_data.r_values);
1905            self.push_iter(&filter_data.g_values);
1906            self.push_iter(&filter_data.b_values);
1907            self.push_iter(&filter_data.a_values);
1908        }
1909
1910        if !filter_primitives.is_empty() {
1911            self.push_item(&di::DisplayItem::SetFilterPrimitives);
1912            self.push_iter(filter_primitives);
1913        }
1914    }
1915
1916    fn generate_clip_index(&mut self) -> di::ClipId {
1917        self.next_clip_index += 1;
1918        di::ClipId(self.next_clip_index - 1, self.pipeline_id)
1919    }
1920
1921    fn generate_spatial_index(&mut self) -> di::SpatialId {
1922        self.next_spatial_index += 1;
1923        di::SpatialId::new(self.next_spatial_index - 1, self.pipeline_id)
1924    }
1925
1926    fn generate_clip_chain_id(&mut self) -> di::ClipChainId {
1927        self.next_clip_chain_id += 1;
1928        di::ClipChainId(self.next_clip_chain_id - 1, self.pipeline_id)
1929    }
1930
1931    pub fn define_scroll_frame(
1932        &mut self,
1933        parent_space: di::SpatialId,
1934        external_id: di::ExternalScrollId,
1935        content_rect: LayoutRect,
1936        frame_rect: LayoutRect,
1937        external_scroll_offset: LayoutVector2D,
1938        scroll_offset_generation: APZScrollGeneration,
1939        has_scroll_linked_effect: HasScrollLinkedEffect,
1940        key: di::SpatialTreeItemKey,
1941    ) -> di::SpatialId {
1942        let scroll_frame_id = self.generate_spatial_index();
1943        let current_offset = self.rf_mapper.current_offset();
1944
1945        let descriptor = di::SpatialTreeItem::ScrollFrame(di::ScrollFrameDescriptor {
1946            content_rect,
1947            frame_rect: frame_rect.translate(current_offset),
1948            parent_space,
1949            scroll_frame_id,
1950            external_id,
1951            external_scroll_offset,
1952            scroll_offset_generation,
1953            has_scroll_linked_effect,
1954            key,
1955        });
1956
1957        self.push_spatial_tree_item(&descriptor);
1958
1959        scroll_frame_id
1960    }
1961
1962    pub fn define_clip_chain<I>(
1963        &mut self,
1964        parent: Option<di::ClipChainId>,
1965        clips: I,
1966    ) -> di::ClipChainId
1967    where
1968        I: IntoIterator<Item = di::ClipId>,
1969        I::IntoIter: ExactSizeIterator + Clone,
1970    {
1971        let id = self.generate_clip_chain_id();
1972        self.push_item(&di::DisplayItem::ClipChain(di::ClipChainItem {
1973            id,
1974            parent,
1975        }));
1976        self.push_iter(clips);
1977        id
1978    }
1979
1980    pub fn define_clip_image_mask(
1981        &mut self,
1982        spatial_id: di::SpatialId,
1983        image_mask: di::ImageMask,
1984        points: &[LayoutPoint],
1985        fill_rule: di::FillRule,
1986    ) -> di::ClipId {
1987        let id = self.generate_clip_index();
1988
1989        let current_offset = self.rf_mapper.current_offset();
1990
1991        let image_mask = di::ImageMask {
1992            rect: image_mask.rect.translate(current_offset),
1993            ..image_mask
1994        };
1995
1996        let item = di::DisplayItem::ImageMaskClip(di::ImageMaskClipDisplayItem {
1997            id,
1998            spatial_id,
1999            image_mask,
2000            fill_rule,
2001        });
2002
2003        // We only need to supply points if there are at least 3, which is the
2004        // minimum to specify a polygon. BuiltDisplayListIter.next ensures that points
2005        // are cleared between processing other display items, so we'll correctly get
2006        // zero points when no SetPoints item has been pushed.
2007        if points.len() >= 3 {
2008            self.push_item(&di::DisplayItem::SetPoints);
2009            self.push_iter(points);
2010        }
2011        self.push_item(&item);
2012        id
2013    }
2014
2015    pub fn define_clip_rect(
2016        &mut self,
2017        spatial_id: di::SpatialId,
2018        clip_rect: LayoutRect,
2019    ) -> di::ClipId {
2020        let id = self.generate_clip_index();
2021
2022        let current_offset = self.rf_mapper.current_offset();
2023        let clip_rect = clip_rect.translate(current_offset);
2024
2025        let item = di::DisplayItem::RectClip(di::RectClipDisplayItem {
2026            id,
2027            spatial_id,
2028            clip_rect,
2029        });
2030
2031        self.push_item(&item);
2032        id
2033    }
2034
2035    pub fn define_clip_rounded_rect(
2036        &mut self,
2037        spatial_id: di::SpatialId,
2038        clip: di::ComplexClipRegion,
2039    ) -> di::ClipId {
2040        let id = self.generate_clip_index();
2041
2042        let current_offset = self.rf_mapper.current_offset();
2043
2044        let clip = di::ComplexClipRegion {
2045            rect: clip.rect.translate(current_offset),
2046            ..clip
2047        };
2048
2049        let item = di::DisplayItem::RoundedRectClip(di::RoundedRectClipDisplayItem {
2050            id,
2051            spatial_id,
2052            clip,
2053        });
2054
2055        self.push_item(&item);
2056        id
2057    }
2058
2059    pub fn define_sticky_frame(
2060        &mut self,
2061        parent_spatial_id: di::SpatialId,
2062        frame_rect: LayoutRect,
2063        margins: SideOffsets2D<Option<f32>, LayoutPixel>,
2064        vertical_offset_bounds: di::StickyOffsetBounds,
2065        horizontal_offset_bounds: di::StickyOffsetBounds,
2066        previously_applied_offset: LayoutVector2D,
2067        key: di::SpatialTreeItemKey,
2068        // TODO: The caller only ever passes an identity transform.
2069        // Could we pass just an (optional) animation id instead?
2070        transform: Option<PropertyBinding<LayoutTransform>>
2071    ) -> di::SpatialId {
2072        let id = self.generate_spatial_index();
2073        let current_offset = self.rf_mapper.current_offset();
2074
2075        let descriptor = di::SpatialTreeItem::StickyFrame(di::StickyFrameDescriptor {
2076            parent_spatial_id,
2077            id,
2078            bounds: frame_rect.translate(current_offset),
2079            margins,
2080            vertical_offset_bounds,
2081            horizontal_offset_bounds,
2082            previously_applied_offset,
2083            key,
2084            transform,
2085        });
2086
2087        self.push_spatial_tree_item(&descriptor);
2088        id
2089    }
2090
2091    pub fn push_iframe(
2092        &mut self,
2093        bounds: LayoutRect,
2094        clip_rect: LayoutRect,
2095        space_and_clip: &di::SpaceAndClipInfo,
2096        pipeline_id: PipelineId,
2097        ignore_missing_pipeline: bool,
2098    ) {
2099        let current_offset = self.rf_mapper.current_offset();
2100        let bounds = bounds.translate(current_offset);
2101        let clip_rect = clip_rect.translate(current_offset);
2102
2103        let item = di::DisplayItem::Iframe(di::IframeDisplayItem {
2104            bounds,
2105            clip_rect,
2106            space_and_clip: *space_and_clip,
2107            pipeline_id,
2108            ignore_missing_pipeline,
2109        });
2110        self.push_item(&item);
2111    }
2112
2113    pub fn push_shadow(
2114        &mut self,
2115        space_and_clip: &di::SpaceAndClipInfo,
2116        shadow: di::Shadow,
2117        should_inflate: bool,
2118    ) {
2119        let item = di::DisplayItem::PushShadow(di::PushShadowDisplayItem {
2120            space_and_clip: *space_and_clip,
2121            shadow,
2122            should_inflate,
2123        });
2124        self.push_item(&item);
2125    }
2126
2127    pub fn pop_all_shadows(&mut self) {
2128        self.push_item(&di::DisplayItem::PopAllShadows);
2129    }
2130
2131    pub fn start_item_group(&mut self) {
2132        debug_assert!(!self.writing_to_chunk);
2133        debug_assert!(self.pending_chunk.is_empty());
2134
2135        self.writing_to_chunk = true;
2136    }
2137
2138    fn flush_pending_item_group(&mut self, key: di::ItemKey) {
2139        // Push RetainedItems-marker to cache_data section.
2140        self.push_retained_items(key);
2141
2142        // Push pending chunk to cache_data section.
2143        self.payload.cache_data.append(&mut self.pending_chunk);
2144
2145        // Push ReuseItems-marker to data section.
2146        self.push_reuse_items(key);
2147    }
2148
2149    pub fn finish_item_group(&mut self, key: di::ItemKey) -> bool {
2150        debug_assert!(self.writing_to_chunk);
2151        self.writing_to_chunk = false;
2152
2153        if self.pending_chunk.is_empty() {
2154            return false;
2155        }
2156
2157        self.flush_pending_item_group(key);
2158        true
2159    }
2160
2161    pub fn cancel_item_group(&mut self, discard: bool) {
2162        debug_assert!(self.writing_to_chunk);
2163        self.writing_to_chunk = false;
2164
2165        if discard {
2166            self.pending_chunk.clear();
2167        } else {
2168            // Push pending chunk to data section.
2169            self.payload.items_data.append(&mut self.pending_chunk);
2170        }
2171    }
2172
2173    pub fn push_reuse_items(&mut self, key: di::ItemKey) {
2174        self.push_item_to_section(&di::DisplayItem::ReuseItems(key), DisplayListSection::Data);
2175    }
2176
2177    fn push_retained_items(&mut self, key: di::ItemKey) {
2178        self.push_item_to_section(
2179            &di::DisplayItem::RetainedItems(key),
2180            DisplayListSection::CacheData,
2181        );
2182    }
2183
2184    pub fn set_cache_size(&mut self, cache_size: usize) {
2185        self.cache_size = cache_size;
2186    }
2187
2188    pub fn begin(&mut self) {
2189        assert_eq!(self.state, BuildState::Idle);
2190        self.state = BuildState::Build;
2191        self.builder_start_time = precise_time_ns();
2192        self.reset();
2193    }
2194
2195    pub fn end(&mut self) -> (PipelineId, BuiltDisplayList) {
2196        assert_eq!(self.state, BuildState::Build);
2197        assert!(
2198            self.save_state.is_none(),
2199            "Finalized DisplayListBuilder with a pending save"
2200        );
2201
2202        if let Some(content) = self.serialized_content_buffer.take() {
2203            println!(
2204                "-- WebRender display list for {:?} --\n{}",
2205                self.pipeline_id, content
2206            );
2207        }
2208
2209        // Add `DisplayItem::max_size` zone of zeroes to the end of display list
2210        // so there is at least this amount available in the display list during
2211        // serialization.
2212        ensure_red_zone::<di::DisplayItem>(&mut self.payload.items_data);
2213        ensure_red_zone::<di::DisplayItem>(&mut self.payload.cache_data);
2214        ensure_red_zone::<di::SpatialTreeItem>(&mut self.payload.spatial_tree);
2215
2216        // While the first display list after tab-switch can be large, the
2217        // following ones are always smaller thanks to interning. We attempt
2218        // to reserve the same capacity again, although it may fail. Memory
2219        // pressure events will cause us to release our buffers if we ask for
2220        // too much. See bug 1531819 for related OOM issues.
2221        let next_capacity = DisplayListCapacity {
2222            cache_size: self.payload.cache_data.len(),
2223            items_size: self.payload.items_data.len(),
2224            spatial_tree_size: self.payload.spatial_tree.len(),
2225        };
2226        let payload = mem::replace(&mut self.payload, DisplayListPayload::new(next_capacity));
2227        let end_time = precise_time_ns();
2228
2229        self.state = BuildState::Idle;
2230
2231        (
2232            self.pipeline_id,
2233            BuiltDisplayList {
2234                descriptor: BuiltDisplayListDescriptor {
2235                    gecko_display_list_type: GeckoDisplayListType::None,
2236                    builder_start_time: self.builder_start_time,
2237                    builder_finish_time: end_time,
2238                    send_start_time: end_time,
2239                    total_clip_nodes: self.next_clip_index,
2240                    total_spatial_nodes: self.next_spatial_index,
2241                    cache_size: self.cache_size,
2242                },
2243                payload,
2244            },
2245        )
2246    }
2247}
2248
2249fn iter_spatial_tree<F>(spatial_tree: &[u8], mut f: F)
2250where
2251    F: FnMut(&di::SpatialTreeItem),
2252{
2253    let mut src = spatial_tree;
2254    let mut item = di::SpatialTreeItem::Invalid;
2255
2256    while src.len() > di::SpatialTreeItem::max_size() {
2257        src = peek_from_slice(src, &mut item);
2258        f(&item);
2259    }
2260}
2261
2262/// The offset stack for a given reference frame.
2263#[derive(Clone)]
2264struct ReferenceFrameState {
2265    /// A stack of current offsets from the current reference frame scope.
2266    offsets: Vec<LayoutVector2D>,
2267}
2268
2269/// Maps from stacking context layout coordinates into reference frame
2270/// relative coordinates.
2271#[derive(Clone)]
2272pub struct ReferenceFrameMapper {
2273    /// A stack of reference frame scopes.
2274    frames: Vec<ReferenceFrameState>,
2275}
2276
2277impl ReferenceFrameMapper {
2278    pub fn new() -> Self {
2279        ReferenceFrameMapper {
2280            frames: vec![ReferenceFrameState {
2281                offsets: vec![LayoutVector2D::zero()],
2282            }],
2283        }
2284    }
2285
2286    /// Push a new scope. This resets the current offset to zero, and is
2287    /// used when a new reference frame or iframe is pushed.
2288    pub fn push_scope(&mut self) {
2289        self.frames.push(ReferenceFrameState {
2290            offsets: vec![LayoutVector2D::zero()],
2291        });
2292    }
2293
2294    /// Pop a reference frame scope off the stack.
2295    pub fn pop_scope(&mut self) {
2296        self.frames.pop().unwrap();
2297    }
2298
2299    /// Push a new offset for the current scope. This is used when
2300    /// a new stacking context is pushed.
2301    pub fn push_offset(&mut self, offset: LayoutVector2D) {
2302        let frame = self.frames.last_mut().unwrap();
2303        let current_offset = *frame.offsets.last().unwrap();
2304        frame.offsets.push(current_offset + offset);
2305    }
2306
2307    /// Pop a local stacking context offset from the current scope.
2308    pub fn pop_offset(&mut self) {
2309        let frame = self.frames.last_mut().unwrap();
2310        frame.offsets.pop().unwrap();
2311    }
2312
2313    /// Retrieve the current offset to allow converting a stacking context
2314    /// relative coordinate to be relative to the owing reference frame.
2315    /// TODO(gw): We could perhaps have separate coordinate spaces for this,
2316    ///           however that's going to either mean a lot of changes to
2317    ///           public API code, or a lot of changes to internal code.
2318    ///           Before doing that, we should revisit how Gecko would
2319    ///           prefer to provide coordinates.
2320    /// TODO(gw): For now, this includes only the reference frame relative
2321    ///           offset. Soon, we will expand this to include the initial
2322    ///           scroll offsets that are now available on scroll nodes. This
2323    ///           will allow normalizing the coordinates even between display
2324    ///           lists where APZ has scrolled the content.
2325    pub fn current_offset(&self) -> LayoutVector2D {
2326        *self.frames.last().unwrap().offsets.last().unwrap()
2327    }
2328}