Skip to main content

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