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