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