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