tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

display_list.rs (75054B)


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