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