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/. */
5 use euclid::SideOffsets2D;
6 use peek_poke::{ensure_red_zone, peek_from_slice, poke_extend_vec, strip_red_zone};
7 use peek_poke::{poke_inplace_slice, poke_into_vec, Poke};
8 #[cfg(feature = "deserialize")]
9 use serde::de::Deserializer;
10 #[cfg(feature = "serialize")]
11 use serde::ser::{Serializer, SerializeSeq};
12 use serde::{Deserialize, Serialize};
14 use std::marker::PhantomData;
17 use std::collections::HashMap;
18 use time::precise_time_ns;
19 use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
21 use crate::display_item as di;
22 use crate::display_item_cache::*;
23 use crate::{PipelineId, PropertyBinding};
24 use crate::gradient_builder::GradientBuilder;
25 use crate::color::ColorF;
26 use crate::font::{FontInstanceKey, GlyphInstance, GlyphOptions};
27 use crate::image::{ColorDepth, ImageKey};
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
33 pub const MAX_TEXT_RUN_LENGTH: usize = 2040;
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
38 const FIRST_SPATIAL_NODE_INDEX: usize = 2;
40 // See ROOT_SCROLL_NODE_SPATIAL_ID
41 const FIRST_CLIP_NODE_INDEX: usize = 1;
44 #[derive(Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
45 pub struct ItemRange<'a, T> {
50 impl<'a, T> Copy for ItemRange<'a, T> {}
51 impl<'a, T> Clone for ItemRange<'a, T> {
52 fn clone(&self) -> Self {
57 impl<'a, T> Default for ItemRange<'a, T> {
58 fn default() -> Self {
60 bytes: Default::default(),
66 impl<'a, T> ItemRange<'a, T> {
67 pub fn new(bytes: &'a [u8]) -> Self {
74 pub fn is_empty(&self) -> bool {
75 // Nothing more than space for a length (0).
76 self.bytes.len() <= mem::size_of::<usize>()
79 pub fn bytes(&self) -> &[u8] {
84 impl<'a, T: Default> ItemRange<'a, T> {
85 pub fn iter(&self) -> AuxIter<'a, T> {
86 AuxIter::new(T::default(), self.bytes)
90 impl<'a, T> IntoIterator for ItemRange<'a, T>
92 T: Copy + Default + peek_poke::Peek,
95 type IntoIter = AuxIter<'a, T>;
96 fn into_iter(self) -> Self::IntoIter {
101 #[derive(Copy, Clone)]
102 pub 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>,
111 #[derive(Clone, Default)]
112 pub struct BuiltDisplayList {
113 /// Serde encoded bytes. Mostly DisplayItems, but some mixed in slices.
115 descriptor: BuiltDisplayListDescriptor,
118 /// Describes the memory layout of a display list.
120 /// A display list consists of some number of display list items, followed by a number of display
123 #[derive(Copy, Clone, Default, Deserialize, Serialize)]
124 pub struct BuiltDisplayListDescriptor {
125 /// The time spent in painting before creating WR DL.
126 gecko_display_list_time: f64,
127 /// The first IPC time stamp: before any work has been done
128 builder_start_time: u64,
129 /// The second IPC time stamp: after serialization
130 builder_finish_time: u64,
131 /// The third IPC time stamp: just before sending
132 send_start_time: u64,
133 /// The amount of clipping nodes created while building this display list.
134 total_clip_nodes: usize,
135 /// The amount of spatial nodes created while building this display list.
136 total_spatial_nodes: usize,
137 /// The size of the cache for this display list.
139 /// The offset for additional display list data.
140 extra_data_offset: usize,
144 pub struct DisplayListWithCache {
145 display_list: BuiltDisplayList,
146 cache: DisplayItemCache,
149 impl DisplayListWithCache {
150 pub fn iter(&self) -> BuiltDisplayListIter {
151 self.display_list.iter_with_cache(&self.cache)
154 pub fn new_from_list(display_list: BuiltDisplayList) -> Self {
155 let mut cache = DisplayItemCache::new();
156 cache.update(&display_list);
158 DisplayListWithCache {
164 pub fn update(&mut self, display_list: BuiltDisplayList) {
165 self.cache.update(&display_list);
166 self.display_list = display_list;
169 pub fn descriptor(&self) -> &BuiltDisplayListDescriptor {
170 self.display_list.descriptor()
173 pub fn times(&self) -> (f64, u64, u64, u64) {
174 self.display_list.times()
177 pub fn data(&self) -> &[u8] {
178 self.display_list.data()
182 impl MallocSizeOf for DisplayListWithCache {
183 fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
184 self.display_list.data.size_of(ops) + self.cache.size_of(ops)
188 #[cfg(feature = "serialize")]
189 impl Serialize for DisplayListWithCache {
190 fn serialize<S: Serializer>(
193 ) -> Result<S::Ok, S::Error> {
194 BuiltDisplayList::serialize_with_iterator(serializer, self.iter())
198 #[cfg(feature = "deserialize")]
199 impl<'de> Deserialize<'de> for DisplayListWithCache {
200 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
202 D: Deserializer<'de>,
204 let display_list = BuiltDisplayList::deserialize(deserializer)?;
205 let cache = DisplayItemCache::new();
207 Ok(DisplayListWithCache {
214 impl BuiltDisplayListDescriptor {}
216 pub struct BuiltDisplayListIter<'a> {
217 list: &'a BuiltDisplayList,
219 cache: Option<&'a DisplayItemCache>,
220 pending_items: std::slice::Iter<'a, CachedDisplayItem>,
221 cur_cached_item: Option<&'a CachedDisplayItem>,
222 cur_item: di::DisplayItem,
223 cur_stops: ItemRange<'a, di::GradientStop>,
224 cur_glyphs: ItemRange<'a, GlyphInstance>,
225 cur_filters: ItemRange<'a, di::FilterOp>,
226 cur_filter_data: Vec<TempFilterData<'a>>,
227 cur_filter_primitives: ItemRange<'a, di::FilterPrimitive>,
228 cur_clip_chain_items: ItemRange<'a, di::ClipId>,
229 cur_complex_clip: ItemRange<'a, di::ComplexClipRegion>,
230 cur_points: ItemRange<'a, LayoutPoint>,
232 /// Should just be initialized but never populated in release builds
233 debug_stats: DebugStats,
236 /// Internal info used for more detailed analysis of serialized display lists
239 /// Last address in the buffer we pointed to, for computing serialized sizes
241 stats: HashMap<&'static str, ItemStats>,
245 #[cfg(feature = "display_list_stats")]
246 fn _update_entry(&mut self, name: &'static str, item_count: usize, byte_count: usize) {
247 let entry = self.stats.entry(name).or_default();
248 entry.total_count += item_count;
249 entry.num_bytes += byte_count;
252 /// Computes the number of bytes we've processed since we last called
253 /// this method, so we can compute the serialized size of a display item.
254 #[cfg(feature = "display_list_stats")]
255 fn debug_num_bytes(&mut self, data: &[u8]) -> usize {
256 let old_addr = self.last_addr;
257 let new_addr = data.as_ptr() as usize;
258 let delta = new_addr - old_addr;
259 self.last_addr = new_addr;
264 /// Logs stats for the last deserialized display item
265 #[cfg(feature = "display_list_stats")]
266 fn log_item(&mut self, data: &[u8], item: &di::DisplayItem) {
267 let num_bytes = self.debug_num_bytes(data);
268 self._update_entry(item.debug_name(), 1, num_bytes);
271 /// Logs the stats for the given serialized slice
272 #[cfg(feature = "display_list_stats")]
273 fn log_slice<T: Copy + Default + peek_poke::Peek>(
275 slice_name: &'static str,
276 range: &ItemRange<T>,
278 // Run this so log_item_stats is accurate, but ignore its result
279 // because log_slice_stats may be called after multiple slices have been
280 // processed, and the `range` has everything we need.
281 self.last_addr = range.bytes.as_ptr() as usize + range.bytes.len();
283 self._update_entry(slice_name, range.iter().len(), range.bytes.len());
286 #[cfg(not(feature = "display_list_stats"))]
287 fn log_slice<T>(&mut self, _slice_name: &str, _range: &ItemRange<T>) {
292 /// Stats for an individual item
293 #[derive(Copy, Clone, Debug, Default)]
294 pub struct ItemStats {
295 /// How many instances of this kind of item we deserialized
296 pub total_count: usize,
297 /// How many bytes we processed for this kind of item
298 pub num_bytes: usize,
301 pub struct DisplayItemRef<'a: 'b, 'b> {
302 iter: &'b BuiltDisplayListIter<'a>,
305 // Some of these might just become ItemRanges
306 impl<'a, 'b> DisplayItemRef<'a, 'b> {
307 pub fn display_list(&self) -> &BuiltDisplayList {
308 self.iter.display_list()
311 // Creates a new iterator where this element's iterator is, to hack around borrowck.
312 pub fn sub_iter(&self) -> BuiltDisplayListIter<'a> {
316 pub fn item(&self) -> &di::DisplayItem {
317 self.iter.current_item()
320 pub fn clip_chain_items(&self) -> ItemRange<di::ClipId> {
321 self.iter.cur_clip_chain_items
324 pub fn complex_clip(&self) -> ItemRange<di::ComplexClipRegion> {
325 self.iter.cur_complex_clip
328 pub fn points(&self) -> ItemRange<LayoutPoint> {
332 pub fn glyphs(&self) -> ItemRange<GlyphInstance> {
336 pub fn gradient_stops(&self) -> ItemRange<di::GradientStop> {
337 self.iter.gradient_stops()
340 pub fn filters(&self) -> ItemRange<di::FilterOp> {
341 self.iter.cur_filters
344 pub fn filter_datas(&self) -> &Vec<TempFilterData> {
345 &self.iter.cur_filter_data
348 pub fn filter_primitives(&self) -> ItemRange<di::FilterPrimitive> {
349 self.iter.cur_filter_primitives
361 pub struct AuxIter<'a, T> {
365 // _boo: PhantomData<T>,
368 impl BuiltDisplayList {
369 pub fn from_data(data: Vec<u8>, descriptor: BuiltDisplayListDescriptor) -> Self {
370 BuiltDisplayList { data, descriptor }
373 pub fn into_data(self) -> (Vec<u8>, BuiltDisplayListDescriptor) {
374 (self.data, self.descriptor)
377 pub fn data(&self) -> &[u8] {
381 pub fn item_slice(&self) -> &[u8] {
382 &self.data[..self.descriptor.extra_data_offset]
385 pub fn extra_slice(&self) -> &[u8] {
386 &self.data[self.descriptor.extra_data_offset..]
389 pub fn descriptor(&self) -> &BuiltDisplayListDescriptor {
393 pub fn set_send_time_ns(&mut self, time: u64) {
394 self.descriptor.send_start_time = time;
397 pub fn times(&self) -> (f64, u64, u64, u64) {
399 self.descriptor.gecko_display_list_time,
400 self.descriptor.builder_start_time,
401 self.descriptor.builder_finish_time,
402 self.descriptor.send_start_time,
406 pub fn total_clip_nodes(&self) -> usize {
407 self.descriptor.total_clip_nodes
410 pub fn total_spatial_nodes(&self) -> usize {
411 self.descriptor.total_spatial_nodes
414 pub fn iter(&self) -> BuiltDisplayListIter {
415 BuiltDisplayListIter::new(self, self.item_slice(), None)
418 pub fn extra_data_iter(&self) -> BuiltDisplayListIter {
419 BuiltDisplayListIter::new(self, self.extra_slice(), None)
422 pub fn iter_with_cache<'a>(
424 cache: &'a DisplayItemCache
425 ) -> BuiltDisplayListIter<'a> {
426 BuiltDisplayListIter::new(self, self.item_slice(), Some(cache))
429 pub fn cache_size(&self) -> usize {
430 self.descriptor.cache_size
433 #[cfg(feature = "serialize")]
434 pub fn serialize_with_iterator<S: Serializer>(
436 mut iterator: BuiltDisplayListIter,
437 ) -> Result<S::Ok, S::Error> {
438 use crate::display_item::DisplayItem as Real;
439 use crate::display_item::DebugDisplayItem as Debug;
441 let mut seq = serializer.serialize_seq(None)?;
443 while let Some(item) = iterator.next_raw() {
444 let serial_di = match *item.item() {
445 Real::Clip(v) => Debug::Clip(
447 item.iter.cur_complex_clip.iter().collect()
449 Real::ClipChain(v) => Debug::ClipChain(
451 item.iter.cur_clip_chain_items.iter().collect()
453 Real::ScrollFrame(v) => Debug::ScrollFrame(v),
454 Real::Text(v) => Debug::Text(
456 item.iter.cur_glyphs.iter().collect()
458 Real::SetFilterOps => Debug::SetFilterOps(
459 item.iter.cur_filters.iter().collect()
461 Real::SetFilterData => {
462 debug_assert!(!item.iter.cur_filter_data.is_empty(),
463 "next_raw should have populated cur_filter_data");
464 let temp_filter_data = &item.iter.cur_filter_data[item.iter.cur_filter_data.len()-1];
466 let func_types: Vec<di::ComponentTransferFuncType> =
467 temp_filter_data.func_types.iter().collect();
468 debug_assert!(func_types.len() == 4,
469 "someone changed the number of filter funcs without updating this code");
470 Debug::SetFilterData(di::FilterData {
471 func_r_type: func_types[0],
472 r_values: temp_filter_data.r_values.iter().collect(),
473 func_g_type: func_types[1],
474 g_values: temp_filter_data.g_values.iter().collect(),
475 func_b_type: func_types[2],
476 b_values: temp_filter_data.b_values.iter().collect(),
477 func_a_type: func_types[3],
478 a_values: temp_filter_data.a_values.iter().collect(),
481 Real::SetFilterPrimitives => Debug::SetFilterPrimitives(
482 item.iter.cur_filter_primitives.iter().collect()
484 Real::SetGradientStops => Debug::SetGradientStops(
485 item.iter.cur_stops.iter().collect()
487 Real::SetPoints => Debug::SetPoints(
488 item.iter.cur_points.iter().collect()
490 Real::RectClip(v) => Debug::RectClip(v),
491 Real::RoundedRectClip(v) => Debug::RoundedRectClip(v),
492 Real::ImageMaskClip(v) => Debug::ImageMaskClip(v),
493 Real::StickyFrame(v) => Debug::StickyFrame(v),
494 Real::Rectangle(v) => Debug::Rectangle(v),
495 Real::ClearRectangle(v) => Debug::ClearRectangle(v),
496 Real::HitTest(v) => Debug::HitTest(v),
497 Real::Line(v) => Debug::Line(v),
498 Real::Image(v) => Debug::Image(v),
499 Real::RepeatingImage(v) => Debug::RepeatingImage(v),
500 Real::YuvImage(v) => Debug::YuvImage(v),
501 Real::Border(v) => Debug::Border(v),
502 Real::BoxShadow(v) => Debug::BoxShadow(v),
503 Real::Gradient(v) => Debug::Gradient(v),
504 Real::RadialGradient(v) => Debug::RadialGradient(v),
505 Real::ConicGradient(v) => Debug::ConicGradient(v),
506 Real::Iframe(v) => Debug::Iframe(v),
507 Real::PushReferenceFrame(v) => Debug::PushReferenceFrame(v),
508 Real::PushStackingContext(v) => Debug::PushStackingContext(v),
509 Real::PushShadow(v) => Debug::PushShadow(v),
510 Real::BackdropFilter(v) => Debug::BackdropFilter(v),
512 Real::PopReferenceFrame => Debug::PopReferenceFrame,
513 Real::PopStackingContext => Debug::PopStackingContext,
514 Real::PopAllShadows => Debug::PopAllShadows,
515 Real::ReuseItems(_) |
516 Real::RetainedItems(_) => unreachable!("Unexpected item"),
518 seq.serialize_element(&serial_di)?
524 /// Returns the byte-range the slice occupied.
525 fn skip_slice<'a, T: peek_poke::Peek>(data: &mut &'a [u8]) -> ItemRange<'a, T> {
526 let mut skip_offset = 0usize;
527 *data = peek_from_slice(data, &mut skip_offset);
528 let (skip, rest) = data.split_at(skip_offset);
530 // Adjust data pointer to skip read values
539 impl<'a> BuiltDisplayListIter<'a> {
541 list: &'a BuiltDisplayList,
543 cache: Option<&'a DisplayItemCache>,
549 pending_items: [].iter(),
550 cur_cached_item: None,
551 cur_item: di::DisplayItem::PopStackingContext,
552 cur_stops: ItemRange::default(),
553 cur_glyphs: ItemRange::default(),
554 cur_filters: ItemRange::default(),
555 cur_filter_data: Vec::new(),
556 cur_filter_primitives: ItemRange::default(),
557 cur_clip_chain_items: ItemRange::default(),
558 cur_complex_clip: ItemRange::default(),
559 cur_points: ItemRange::default(),
560 peeking: Peek::NotPeeking,
561 debug_stats: DebugStats {
562 last_addr: data.as_ptr() as usize,
563 stats: HashMap::default(),
568 pub fn sub_iter(&self) -> Self {
569 let mut iter = BuiltDisplayListIter::new(
570 self.list, self.data, self.cache
572 iter.pending_items = self.pending_items.clone();
576 pub fn display_list(&self) -> &'a BuiltDisplayList {
580 pub fn current_item(&self) -> &di::DisplayItem {
581 match self.cur_cached_item {
582 Some(cached_item) => cached_item.display_item(),
583 None => &self.cur_item
587 fn cached_item_range_or<T>(
589 data: ItemRange<'a, T>
590 ) -> ItemRange<'a, T> {
591 match self.cur_cached_item {
592 Some(cached_item) => cached_item.data_as_item_range(),
597 pub fn glyphs(&self) -> ItemRange<GlyphInstance> {
598 self.cached_item_range_or(self.cur_glyphs)
601 pub fn gradient_stops(&self) -> ItemRange<di::GradientStop> {
602 self.cached_item_range_or(self.cur_stops)
605 fn advance_pending_items(&mut self) -> bool {
606 self.cur_cached_item = self.pending_items.next();
607 self.cur_cached_item.is_some()
610 pub fn next<'b>(&'b mut self) -> Option<DisplayItemRef<'a, 'b>> {
611 use crate::DisplayItem::*;
615 self.peeking = Peek::NotPeeking;
616 return Some(self.as_ref());
618 Peek::StartPeeking => {
619 self.peeking = Peek::IsPeeking;
621 Peek::NotPeeking => { /* do nothing */ }
624 // Don't let these bleed into another item
625 self.cur_stops = ItemRange::default();
626 self.cur_complex_clip = ItemRange::default();
627 self.cur_clip_chain_items = ItemRange::default();
628 self.cur_points = ItemRange::default();
629 self.cur_filters = ItemRange::default();
630 self.cur_filter_primitives = ItemRange::default();
631 self.cur_filter_data.clear();
635 match self.cur_item {
639 SetFilterPrimitives |
641 // These are marker items for populating other display items, don't yield them.
653 /// Gets the next display item, even if it's a dummy. Also doesn't handle peeking
654 /// and may leave irrelevant ranges live (so a Clip may have GradientStops if
655 /// for some reason you ask).
656 pub fn next_raw<'b>(&'b mut self) -> Option<DisplayItemRef<'a, 'b>> {
657 use crate::DisplayItem::*;
659 if self.advance_pending_items() {
660 return Some(self.as_ref());
663 // A "red zone" of DisplayItem::max_size() bytes has been added to the
664 // end of the serialized display list. If this amount, or less, is
665 // remaining then we've reached the end of the display list.
666 if self.data.len() <= di::DisplayItem::max_size() {
670 self.data = peek_from_slice(self.data, &mut self.cur_item);
671 self.log_item_stats();
673 match self.cur_item {
674 SetGradientStops => {
675 self.cur_stops = skip_slice::<di::GradientStop>(&mut self.data);
676 self.debug_stats.log_slice("set_gradient_stops.stops", &self.cur_stops);
679 self.cur_filters = skip_slice::<di::FilterOp>(&mut self.data);
680 self.debug_stats.log_slice("set_filter_ops.ops", &self.cur_filters);
683 self.cur_filter_data.push(TempFilterData {
684 func_types: skip_slice::<di::ComponentTransferFuncType>(&mut self.data),
685 r_values: skip_slice::<f32>(&mut self.data),
686 g_values: skip_slice::<f32>(&mut self.data),
687 b_values: skip_slice::<f32>(&mut self.data),
688 a_values: skip_slice::<f32>(&mut self.data),
691 let data = *self.cur_filter_data.last().unwrap();
692 self.debug_stats.log_slice("set_filter_data.func_types", &data.func_types);
693 self.debug_stats.log_slice("set_filter_data.r_values", &data.r_values);
694 self.debug_stats.log_slice("set_filter_data.g_values", &data.g_values);
695 self.debug_stats.log_slice("set_filter_data.b_values", &data.b_values);
696 self.debug_stats.log_slice("set_filter_data.a_values", &data.a_values);
698 SetFilterPrimitives => {
699 self.cur_filter_primitives = skip_slice::<di::FilterPrimitive>(&mut self.data);
700 self.debug_stats.log_slice("set_filter_primitives.primitives", &self.cur_filter_primitives);
703 self.cur_points = skip_slice::<LayoutPoint>(&mut self.data);
704 self.debug_stats.log_slice("set_points.points", &self.cur_points);
707 self.cur_clip_chain_items = skip_slice::<di::ClipId>(&mut self.data);
708 self.debug_stats.log_slice("clip_chain.clip_ids", &self.cur_clip_chain_items);
711 self.cur_complex_clip = skip_slice::<di::ComplexClipRegion>(&mut self.data);
712 self.debug_stats.log_slice("clip.complex_clips", &self.cur_complex_clip);
715 self.cur_glyphs = skip_slice::<GlyphInstance>(&mut self.data);
716 self.debug_stats.log_slice("text.glyphs", &self.cur_glyphs);
721 self.pending_items = cache.get_items(key).iter();
722 self.advance_pending_items();
725 unreachable!("Cache marker without cache!");
729 _ => { /* do nothing */ }
735 pub fn as_ref<'b>(&'b self) -> DisplayItemRef<'a, 'b> {
741 pub fn skip_current_stacking_context(&mut self) {
743 while let Some(item) = self.next() {
745 di::DisplayItem::PushStackingContext(..) => depth += 1,
746 di::DisplayItem::PopStackingContext if depth == 0 => return,
747 di::DisplayItem::PopStackingContext => depth -= 1,
753 pub fn current_stacking_context_empty(&mut self) -> bool {
755 Some(item) => *item.item() == di::DisplayItem::PopStackingContext,
760 pub fn peek<'b>(&'b mut self) -> Option<DisplayItemRef<'a, 'b>> {
761 if self.peeking == Peek::NotPeeking {
762 self.peeking = Peek::StartPeeking;
769 /// Get the debug stats for what this iterator has deserialized.
770 /// Should always be empty in release builds.
771 pub fn debug_stats(&mut self) -> Vec<(&'static str, ItemStats)> {
772 let mut result = self.debug_stats.stats.drain().collect::<Vec<_>>();
773 result.sort_by_key(|stats| stats.0);
777 /// Adds the debug stats from another to our own, assuming we are a sub-iter of the other
778 /// (so we can ignore where they were in the traversal).
779 pub fn merge_debug_stats_from(&mut self, other: &mut Self) {
780 for (key, other_entry) in other.debug_stats.stats.iter() {
781 let entry = self.debug_stats.stats.entry(key).or_default();
783 entry.total_count += other_entry.total_count;
784 entry.num_bytes += other_entry.num_bytes;
788 /// Logs stats for the last deserialized display item
789 #[cfg(feature = "display_list_stats")]
790 fn log_item_stats(&mut self) {
791 self.debug_stats.log_item(self.data, &self.cur_item);
794 #[cfg(not(feature = "display_list_stats"))]
795 fn log_item_stats(&mut self) { /* no-op */ }
798 impl<'a, T> AuxIter<'a, T> {
799 pub fn new(item: T, mut data: &'a [u8]) -> Self {
800 let mut size = 0usize;
801 if !data.is_empty() {
802 data = peek_from_slice(data, &mut size);
809 // _boo: PhantomData,
814 impl<'a, T: Copy + peek_poke::Peek> Iterator for AuxIter<'a, T> {
817 fn next(&mut self) -> Option<Self::Item> {
822 self.data = peek_from_slice(self.data, &mut self.item);
827 fn size_hint(&self) -> (usize, Option<usize>) {
828 (self.size, Some(self.size))
832 impl<'a, T: Copy + peek_poke::Peek> ::std::iter::ExactSizeIterator for AuxIter<'a, T> {}
834 #[cfg(feature = "serialize")]
835 impl Serialize for BuiltDisplayList {
836 fn serialize<S: Serializer>(
839 ) -> Result<S::Ok, S::Error> {
840 Self::serialize_with_iterator(serializer, self.iter())
844 // The purpose of this implementation is to deserialize
845 // a display list from one format just to immediately
846 // serialize then into a "built" `Vec<u8>`.
848 #[cfg(feature = "deserialize")]
849 impl<'de> Deserialize<'de> for BuiltDisplayList {
850 fn deserialize<D: Deserializer<'de>>(
852 ) -> Result<Self, D::Error> {
853 use crate::display_item::DisplayItem as Real;
854 use crate::display_item::DebugDisplayItem as Debug;
856 let list = Vec::<Debug>::deserialize(deserializer)?;
858 let mut data = Vec::new();
859 let mut temp = Vec::new();
860 let mut total_clip_nodes = FIRST_CLIP_NODE_INDEX;
861 let mut total_spatial_nodes = FIRST_SPATIAL_NODE_INDEX;
862 for complete in list {
863 let item = match complete {
864 Debug::Clip(v, complex_clips) => {
865 total_clip_nodes += 1;
866 DisplayListBuilder::push_iter_impl(&mut temp, complex_clips);
869 Debug::ClipChain(v, clip_chain_ids) => {
870 DisplayListBuilder::push_iter_impl(&mut temp, clip_chain_ids);
873 Debug::ScrollFrame(v) => {
874 total_spatial_nodes += 1;
875 total_clip_nodes += 1;
878 Debug::StickyFrame(v) => {
879 total_spatial_nodes += 1;
882 Debug::Text(v, glyphs) => {
883 DisplayListBuilder::push_iter_impl(&mut temp, glyphs);
886 Debug::Iframe(v) => {
887 total_clip_nodes += 1;
890 Debug::PushReferenceFrame(v) => {
891 total_spatial_nodes += 1;
892 Real::PushReferenceFrame(v)
894 Debug::SetFilterOps(filters) => {
895 DisplayListBuilder::push_iter_impl(&mut temp, filters);
898 Debug::SetFilterData(filter_data) => {
899 let func_types: Vec<di::ComponentTransferFuncType> =
900 [filter_data.func_r_type,
901 filter_data.func_g_type,
902 filter_data.func_b_type,
903 filter_data.func_a_type].to_vec();
904 DisplayListBuilder::push_iter_impl(&mut temp, func_types);
905 DisplayListBuilder::push_iter_impl(&mut temp, filter_data.r_values);
906 DisplayListBuilder::push_iter_impl(&mut temp, filter_data.g_values);
907 DisplayListBuilder::push_iter_impl(&mut temp, filter_data.b_values);
908 DisplayListBuilder::push_iter_impl(&mut temp, filter_data.a_values);
911 Debug::SetFilterPrimitives(filter_primitives) => {
912 DisplayListBuilder::push_iter_impl(&mut temp, filter_primitives);
913 Real::SetFilterPrimitives
915 Debug::SetGradientStops(stops) => {
916 DisplayListBuilder::push_iter_impl(&mut temp, stops);
917 Real::SetGradientStops
919 Debug::SetPoints(points) => {
920 DisplayListBuilder::push_iter_impl(&mut temp, points);
923 Debug::RectClip(v) => Real::RectClip(v),
924 Debug::RoundedRectClip(v) => Real::RoundedRectClip(v),
925 Debug::ImageMaskClip(v) => Real::ImageMaskClip(v),
926 Debug::Rectangle(v) => Real::Rectangle(v),
927 Debug::ClearRectangle(v) => Real::ClearRectangle(v),
928 Debug::HitTest(v) => Real::HitTest(v),
929 Debug::Line(v) => Real::Line(v),
930 Debug::Image(v) => Real::Image(v),
931 Debug::RepeatingImage(v) => Real::RepeatingImage(v),
932 Debug::YuvImage(v) => Real::YuvImage(v),
933 Debug::Border(v) => Real::Border(v),
934 Debug::BoxShadow(v) => Real::BoxShadow(v),
935 Debug::Gradient(v) => Real::Gradient(v),
936 Debug::RadialGradient(v) => Real::RadialGradient(v),
937 Debug::ConicGradient(v) => Real::ConicGradient(v),
938 Debug::PushStackingContext(v) => Real::PushStackingContext(v),
939 Debug::PushShadow(v) => Real::PushShadow(v),
940 Debug::BackdropFilter(v) => Real::BackdropFilter(v),
942 Debug::PopStackingContext => Real::PopStackingContext,
943 Debug::PopReferenceFrame => Real::PopReferenceFrame,
944 Debug::PopAllShadows => Real::PopAllShadows,
946 poke_into_vec(&item, &mut data);
947 // the aux data is serialized after the item, hence the temporary
948 data.extend(temp.drain(..));
951 // Add `DisplayItem::max_size` zone of zeroes to the end of display list
952 // so there is at least this amount available in the display list during
954 ensure_red_zone::<di::DisplayItem>(&mut data);
955 let extra_data_offset = data.len();
957 Ok(BuiltDisplayList {
959 descriptor: BuiltDisplayListDescriptor {
960 gecko_display_list_time: 0.0,
961 builder_start_time: 0,
962 builder_finish_time: 1,
973 #[derive(Clone, Debug)]
974 pub struct SaveState {
976 next_clip_index: usize,
977 next_spatial_index: usize,
978 next_clip_chain_id: u64,
981 /// DisplayListSection determines the target buffer for the display items.
982 pub enum DisplayListSection {
983 /// The main/default buffer: contains item data and item group markers.
985 /// Auxiliary buffer: contains the item data for item groups.
987 /// Temporary buffer: contains the data for pending item group. Flushed to
988 /// one of the buffers above, after item grouping finishes.
993 pub struct DisplayListBuilder {
995 pub pipeline_id: PipelineId,
998 pending_chunk: Vec<u8>,
999 writing_to_chunk: bool,
1001 next_clip_index: usize,
1002 next_spatial_index: usize,
1003 next_clip_chain_id: u64,
1004 builder_start_time: u64,
1006 save_state: Option<SaveState>,
1009 serialized_content_buffer: Option<String>,
1012 impl DisplayListBuilder {
1013 pub fn new(pipeline_id: PipelineId) -> Self {
1014 Self::with_capacity(pipeline_id, 0)
1017 pub fn with_capacity(
1018 pipeline_id: PipelineId,
1021 let start_time = precise_time_ns();
1023 DisplayListBuilder {
1024 data: Vec::with_capacity(capacity),
1027 extra_data: Vec::new(),
1028 pending_chunk: Vec::new(),
1029 writing_to_chunk: false,
1031 next_clip_index: FIRST_CLIP_NODE_INDEX,
1032 next_spatial_index: FIRST_SPATIAL_NODE_INDEX,
1033 next_clip_chain_id: 0,
1034 builder_start_time: start_time,
1037 serialized_content_buffer: None,
1041 /// Saves the current display list state, so it may be `restore()`'d.
1045 /// * Doesn't support popping clips that were pushed before the save.
1046 /// * Doesn't support nested saves.
1047 /// * Must call `clear_save()` if the restore becomes unnecessary.
1048 pub fn save(&mut self) {
1049 assert!(self.save_state.is_none(), "DisplayListBuilder doesn't support nested saves");
1051 self.save_state = Some(SaveState {
1052 dl_len: self.data.len(),
1053 next_clip_index: self.next_clip_index,
1054 next_spatial_index: self.next_spatial_index,
1055 next_clip_chain_id: self.next_clip_chain_id,
1059 /// Restores the state of the builder to when `save()` was last called.
1060 pub fn restore(&mut self) {
1061 let state = self.save_state.take().expect("No save to restore DisplayListBuilder from");
1063 self.data.truncate(state.dl_len);
1064 self.next_clip_index = state.next_clip_index;
1065 self.next_spatial_index = state.next_spatial_index;
1066 self.next_clip_chain_id = state.next_clip_chain_id;
1069 /// Discards the builder's save (indicating the attempted operation was successful).
1070 pub fn clear_save(&mut self) {
1071 self.save_state.take().expect("No save to clear in DisplayListBuilder");
1074 /// Emits a debug representation of display items in the list, for debugging
1075 /// purposes. If the range's start parameter is specified, only display
1076 /// items starting at that index (inclusive) will be printed. If the range's
1077 /// end parameter is specified, only display items before that index
1078 /// (exclusive) will be printed. Calling this function with end <= start is
1079 /// allowed but is just a waste of CPU cycles. The function emits the
1080 /// debug representation of the selected display items, one per line, with
1081 /// the given indent, to the provided sink object. The return value is
1082 /// the total number of items in the display list, which allows the
1083 /// caller to subsequently invoke this function to only dump the newly-added
1085 pub fn emit_display_list<W>(
1088 range: Range<Option<usize>>,
1094 let mut temp = BuiltDisplayList::default();
1095 ensure_red_zone::<di::DisplayItem>(&mut self.data);
1096 temp.descriptor.extra_data_offset = self.data.len();
1097 mem::swap(&mut temp.data, &mut self.data);
1099 let mut index: usize = 0;
1101 let mut cache = DisplayItemCache::new();
1102 cache.update(&temp);
1103 let mut iter = temp.iter_with_cache(&cache);
1104 while let Some(item) = iter.next_raw() {
1105 if index >= range.start.unwrap_or(0) && range.end.map_or(true, |e| index < e) {
1106 writeln!(sink, "{}{:?}", " ".repeat(indent), item.item()).unwrap();
1112 self.data = temp.data;
1113 strip_red_zone::<di::DisplayItem>(&mut self.data);
1117 /// Print the display items in the list to stdout.
1118 pub fn dump_serialized_display_list(&mut self) {
1119 self.serialized_content_buffer = Some(String::new());
1122 fn add_to_display_list_dump<T: std::fmt::Debug>(&mut self, item: T) {
1123 if let Some(ref mut content) = self.serialized_content_buffer {
1124 use std::fmt::Write;
1125 write!(content, "{:?}\n", item).expect("DL dump write failed.");
1129 /// Returns the default section that DisplayListBuilder will write to,
1130 /// if no section is specified explicitly.
1131 fn default_section(&self) -> DisplayListSection {
1132 if self.writing_to_chunk {
1133 DisplayListSection::Chunk
1135 DisplayListSection::Data
1139 fn buffer_from_section(
1141 section: DisplayListSection
1144 DisplayListSection::Data => &mut self.data,
1145 DisplayListSection::ExtraData => &mut self.extra_data,
1146 DisplayListSection::Chunk => &mut self.pending_chunk,
1151 pub fn push_item_to_section(
1153 item: &di::DisplayItem,
1154 section: DisplayListSection,
1156 poke_into_vec(item, self.buffer_from_section(section));
1157 self.add_to_display_list_dump(item);
1160 /// Add an item to the display list.
1162 /// NOTE: It is usually preferable to use the specialized methods to push
1163 /// display items. Pushing unexpected or invalid items here may
1164 /// result in WebRender panicking or behaving in unexpected ways.
1166 pub fn push_item(&mut self, item: &di::DisplayItem) {
1167 self.push_item_to_section(item, self.default_section());
1170 fn push_iter_impl<I>(data: &mut Vec<u8>, iter_source: I)
1173 I::IntoIter: ExactSizeIterator,
1176 let iter = iter_source.into_iter();
1177 let len = iter.len();
1179 // payload_byte_size: usize, item_count: usize, [I; item_count]
1181 // Track the the location of where to write byte size with offsets
1182 // instead of pointers because data may be moved in memory during
1183 // `serialize_iter_fast`.
1184 let byte_size_offset = data.len();
1186 // We write a dummy value so there's room for later
1187 poke_into_vec(&0usize, data);
1188 poke_into_vec(&len, data);
1189 let count = poke_extend_vec(iter, data);
1190 debug_assert_eq!(len, count, "iterator.len() returned two different values");
1193 ensure_red_zone::<I::Item>(data);
1195 // Now write the actual byte_size
1196 let final_offset = data.len();
1197 debug_assert!(final_offset >= (byte_size_offset + mem::size_of::<usize>()),
1198 "space was never allocated for this array's byte_size");
1199 let byte_size = final_offset - byte_size_offset - mem::size_of::<usize>();
1200 poke_inplace_slice(&byte_size, &mut data[byte_size_offset..]);
1203 /// Push items from an iterator to the display list.
1205 /// NOTE: Pushing unexpected or invalid items to the display list
1206 /// may result in panic and confusion.
1207 pub fn push_iter<I>(&mut self, iter: I)
1210 I::IntoIter: ExactSizeIterator,
1213 let mut buffer = self.buffer_from_section(self.default_section());
1214 Self::push_iter_impl(&mut buffer, iter);
1219 common: &di::CommonItemProperties,
1223 let item = di::DisplayItem::Rectangle(di::RectangleDisplayItem {
1225 color: PropertyBinding::Value(color),
1228 self.push_item(&item);
1231 pub fn push_rect_with_animation(
1233 common: &di::CommonItemProperties,
1235 color: PropertyBinding<ColorF>,
1237 let item = di::DisplayItem::Rectangle(di::RectangleDisplayItem {
1242 self.push_item(&item);
1245 pub fn push_clear_rect(
1247 common: &di::CommonItemProperties,
1250 let item = di::DisplayItem::ClearRectangle(di::ClearRectangleDisplayItem {
1254 self.push_item(&item);
1257 pub fn push_hit_test(
1259 common: &di::CommonItemProperties,
1262 let item = di::DisplayItem::HitTest(di::HitTestDisplayItem {
1266 self.push_item(&item);
1271 common: &di::CommonItemProperties,
1273 wavy_line_thickness: f32,
1274 orientation: di::LineOrientation,
1276 style: di::LineStyle,
1278 let item = di::DisplayItem::Line(di::LineDisplayItem {
1281 wavy_line_thickness,
1287 self.push_item(&item);
1292 common: &di::CommonItemProperties,
1294 image_rendering: di::ImageRendering,
1295 alpha_type: di::AlphaType,
1299 let item = di::DisplayItem::Image(di::ImageDisplayItem {
1308 self.push_item(&item);
1311 pub fn push_repeating_image(
1313 common: &di::CommonItemProperties,
1315 stretch_size: LayoutSize,
1316 tile_spacing: LayoutSize,
1317 image_rendering: di::ImageRendering,
1318 alpha_type: di::AlphaType,
1322 let item = di::DisplayItem::RepeatingImage(di::RepeatingImageDisplayItem {
1333 self.push_item(&item);
1336 /// Push a yuv image. All planar data in yuv image should use the same buffer type.
1337 pub fn push_yuv_image(
1339 common: &di::CommonItemProperties,
1341 yuv_data: di::YuvData,
1342 color_depth: ColorDepth,
1343 color_space: di::YuvColorSpace,
1344 color_range: di::ColorRange,
1345 image_rendering: di::ImageRendering,
1347 let item = di::DisplayItem::YuvImage(di::YuvImageDisplayItem {
1356 self.push_item(&item);
1361 common: &di::CommonItemProperties,
1363 glyphs: &[GlyphInstance],
1364 font_key: FontInstanceKey,
1366 glyph_options: Option<GlyphOptions>,
1368 let item = di::DisplayItem::Text(di::TextDisplayItem {
1376 for split_glyphs in glyphs.chunks(MAX_TEXT_RUN_LENGTH) {
1377 self.push_item(&item);
1378 self.push_iter(split_glyphs);
1382 /// NOTE: gradients must be pushed in the order they're created
1383 /// because create_gradient stores the stops in anticipation.
1384 pub fn create_gradient(
1386 start_point: LayoutPoint,
1387 end_point: LayoutPoint,
1388 stops: Vec<di::GradientStop>,
1389 extend_mode: di::ExtendMode,
1391 let mut builder = GradientBuilder::with_stops(stops);
1392 let gradient = builder.gradient(start_point, end_point, extend_mode);
1393 self.push_stops(builder.stops());
1397 /// NOTE: gradients must be pushed in the order they're created
1398 /// because create_gradient stores the stops in anticipation.
1399 pub fn create_radial_gradient(
1401 center: LayoutPoint,
1403 stops: Vec<di::GradientStop>,
1404 extend_mode: di::ExtendMode,
1405 ) -> di::RadialGradient {
1406 let mut builder = GradientBuilder::with_stops(stops);
1407 let gradient = builder.radial_gradient(center, radius, extend_mode);
1408 self.push_stops(builder.stops());
1412 /// NOTE: gradients must be pushed in the order they're created
1413 /// because create_gradient stores the stops in anticipation.
1414 pub fn create_conic_gradient(
1416 center: LayoutPoint,
1418 stops: Vec<di::GradientStop>,
1419 extend_mode: di::ExtendMode,
1420 ) -> di::ConicGradient {
1421 let mut builder = GradientBuilder::with_stops(stops);
1422 let gradient = builder.conic_gradient(center, angle, extend_mode);
1423 self.push_stops(builder.stops());
1429 common: &di::CommonItemProperties,
1431 widths: LayoutSideOffsets,
1432 details: di::BorderDetails,
1434 let item = di::DisplayItem::Border(di::BorderDisplayItem {
1441 self.push_item(&item);
1444 pub fn push_box_shadow(
1446 common: &di::CommonItemProperties,
1447 box_bounds: LayoutRect,
1448 offset: LayoutVector2D,
1452 border_radius: di::BorderRadius,
1453 clip_mode: di::BoxShadowClipMode,
1455 let item = di::DisplayItem::BoxShadow(di::BoxShadowDisplayItem {
1466 self.push_item(&item);
1469 /// Pushes a linear gradient to be displayed.
1471 /// The gradient itself is described in the
1472 /// `gradient` parameter. It is drawn on
1473 /// a "tile" with the dimensions from `tile_size`.
1474 /// These tiles are now repeated to the right and
1475 /// to the bottom infinitely. If `tile_spacing`
1476 /// is not zero spacers with the given dimensions
1477 /// are inserted between the tiles as seams.
1479 /// The origin of the tiles is given in `layout.rect.origin`.
1480 /// If the gradient should only be displayed once limit
1481 /// the `layout.rect.size` to a single tile.
1482 /// The gradient is only visible within the local clip.
1483 pub fn push_gradient(
1485 common: &di::CommonItemProperties,
1487 gradient: di::Gradient,
1488 tile_size: LayoutSize,
1489 tile_spacing: LayoutSize,
1491 let item = di::DisplayItem::Gradient(di::GradientDisplayItem {
1499 self.push_item(&item);
1502 /// Pushes a radial gradient to be displayed.
1504 /// See [`push_gradient`](#method.push_gradient) for explanation.
1505 pub fn push_radial_gradient(
1507 common: &di::CommonItemProperties,
1509 gradient: di::RadialGradient,
1510 tile_size: LayoutSize,
1511 tile_spacing: LayoutSize,
1513 let item = di::DisplayItem::RadialGradient(di::RadialGradientDisplayItem {
1521 self.push_item(&item);
1524 /// Pushes a conic gradient to be displayed.
1526 /// See [`push_gradient`](#method.push_gradient) for explanation.
1527 pub fn push_conic_gradient(
1529 common: &di::CommonItemProperties,
1531 gradient: di::ConicGradient,
1532 tile_size: LayoutSize,
1533 tile_spacing: LayoutSize,
1535 let item = di::DisplayItem::ConicGradient(di::ConicGradientDisplayItem {
1543 self.push_item(&item);
1546 pub fn push_reference_frame(
1548 origin: LayoutPoint,
1549 parent_spatial_id: di::SpatialId,
1550 transform_style: di::TransformStyle,
1551 transform: PropertyBinding<LayoutTransform>,
1552 kind: di::ReferenceFrameKind,
1553 ) -> di::SpatialId {
1554 let id = self.generate_spatial_index();
1556 let item = di::DisplayItem::PushReferenceFrame(di::ReferenceFrameDisplayListItem {
1559 reference_frame: di::ReferenceFrame {
1561 transform: di::ReferenceTransformBinding::Static {
1569 self.push_item(&item);
1573 pub fn push_computed_frame(
1575 origin: LayoutPoint,
1576 parent_spatial_id: di::SpatialId,
1577 scale_from: Option<LayoutSize>,
1578 vertical_flip: bool,
1579 rotation: di::Rotation,
1580 ) -> di::SpatialId {
1581 let id = self.generate_spatial_index();
1583 let item = di::DisplayItem::PushReferenceFrame(di::ReferenceFrameDisplayListItem {
1586 reference_frame: di::ReferenceFrame {
1587 transform_style: di::TransformStyle::Flat,
1588 transform: di::ReferenceTransformBinding::Computed {
1593 kind: di::ReferenceFrameKind::Transform {
1594 is_2d_scale_translation: false,
1601 self.push_item(&item);
1605 pub fn pop_reference_frame(&mut self) {
1606 self.push_item(&di::DisplayItem::PopReferenceFrame);
1609 pub fn push_stacking_context(
1611 origin: LayoutPoint,
1612 spatial_id: di::SpatialId,
1613 prim_flags: di::PrimitiveFlags,
1614 clip_id: Option<di::ClipId>,
1615 transform_style: di::TransformStyle,
1616 mix_blend_mode: di::MixBlendMode,
1617 filters: &[di::FilterOp],
1618 filter_datas: &[di::FilterData],
1619 filter_primitives: &[di::FilterPrimitive],
1620 raster_space: di::RasterSpace,
1621 flags: di::StackingContextFlags,
1623 self.push_filters(filters, filter_datas, filter_primitives);
1625 let item = di::DisplayItem::PushStackingContext(di::PushStackingContextDisplayItem {
1629 stacking_context: di::StackingContext {
1638 self.push_item(&item);
1641 /// Helper for examples/ code.
1642 pub fn push_simple_stacking_context(
1644 origin: LayoutPoint,
1645 spatial_id: di::SpatialId,
1646 prim_flags: di::PrimitiveFlags,
1648 self.push_simple_stacking_context_with_filters(
1658 /// Helper for examples/ code.
1659 pub fn push_simple_stacking_context_with_filters(
1661 origin: LayoutPoint,
1662 spatial_id: di::SpatialId,
1663 prim_flags: di::PrimitiveFlags,
1664 filters: &[di::FilterOp],
1665 filter_datas: &[di::FilterData],
1666 filter_primitives: &[di::FilterPrimitive],
1668 self.push_stacking_context(
1673 di::TransformStyle::Flat,
1674 di::MixBlendMode::Normal,
1678 di::RasterSpace::Screen,
1679 di::StackingContextFlags::empty(),
1683 pub fn pop_stacking_context(&mut self) {
1684 self.push_item(&di::DisplayItem::PopStackingContext);
1687 pub fn push_stops(&mut self, stops: &[di::GradientStop]) {
1688 if stops.is_empty() {
1691 self.push_item(&di::DisplayItem::SetGradientStops);
1692 self.push_iter(stops);
1695 pub fn push_backdrop_filter(
1697 common: &di::CommonItemProperties,
1698 filters: &[di::FilterOp],
1699 filter_datas: &[di::FilterData],
1700 filter_primitives: &[di::FilterPrimitive],
1702 self.push_filters(filters, filter_datas, filter_primitives);
1704 let item = di::DisplayItem::BackdropFilter(di::BackdropFilterDisplayItem {
1707 self.push_item(&item);
1710 pub fn push_filters(
1712 filters: &[di::FilterOp],
1713 filter_datas: &[di::FilterData],
1714 filter_primitives: &[di::FilterPrimitive],
1716 if !filters.is_empty() {
1717 self.push_item(&di::DisplayItem::SetFilterOps);
1718 self.push_iter(filters);
1721 for filter_data in filter_datas {
1723 filter_data.func_r_type, filter_data.func_g_type,
1724 filter_data.func_b_type, filter_data.func_a_type];
1725 self.push_item(&di::DisplayItem::SetFilterData);
1726 self.push_iter(&func_types);
1727 self.push_iter(&filter_data.r_values);
1728 self.push_iter(&filter_data.g_values);
1729 self.push_iter(&filter_data.b_values);
1730 self.push_iter(&filter_data.a_values);
1733 if !filter_primitives.is_empty() {
1734 self.push_item(&di::DisplayItem::SetFilterPrimitives);
1735 self.push_iter(filter_primitives);
1739 fn generate_clip_index(&mut self) -> di::ClipId {
1740 self.next_clip_index += 1;
1741 di::ClipId::Clip(self.next_clip_index - 1, self.pipeline_id)
1744 fn generate_spatial_index(&mut self) -> di::SpatialId {
1745 self.next_spatial_index += 1;
1746 di::SpatialId::new(self.next_spatial_index - 1, self.pipeline_id)
1749 fn generate_clip_chain_id(&mut self) -> di::ClipChainId {
1750 self.next_clip_chain_id += 1;
1751 di::ClipChainId(self.next_clip_chain_id - 1, self.pipeline_id)
1754 pub fn define_scroll_frame(
1756 parent_space_and_clip: &di::SpaceAndClipInfo,
1757 external_id: di::ExternalScrollId,
1758 content_rect: LayoutRect,
1759 clip_rect: LayoutRect,
1760 scroll_sensitivity: di::ScrollSensitivity,
1761 external_scroll_offset: LayoutVector2D,
1762 ) -> di::SpaceAndClipInfo {
1763 let clip_id = self.generate_clip_index();
1764 let scroll_frame_id = self.generate_spatial_index();
1765 let item = di::DisplayItem::ScrollFrame(di::ScrollFrameDisplayItem {
1768 parent_space_and_clip: *parent_space_and_clip,
1773 external_scroll_offset,
1776 self.push_item(&item);
1778 di::SpaceAndClipInfo {
1779 spatial_id: scroll_frame_id,
1784 pub fn define_clip_chain<I>(
1786 parent: Option<di::ClipChainId>,
1788 ) -> di::ClipChainId
1790 I: IntoIterator<Item = di::ClipId>,
1791 I::IntoIter: ExactSizeIterator + Clone,
1793 let id = self.generate_clip_chain_id();
1794 self.push_item(&di::DisplayItem::ClipChain(di::ClipChainItem { id, parent }));
1795 self.push_iter(clips);
1799 pub fn define_clip_image_mask(
1801 parent_space_and_clip: &di::SpaceAndClipInfo,
1802 image_mask: di::ImageMask,
1804 // TODO(bradwerth): get points and fill_rule as parameters.
1805 let points = Vec::<LayoutPoint>::new();
1806 let fill_rule = di::FillRule::Nonzero;
1808 let id = self.generate_clip_index();
1809 let item = di::DisplayItem::ImageMaskClip(di::ImageMaskClipDisplayItem {
1811 parent_space_and_clip: *parent_space_and_clip,
1816 self.push_item(&di::DisplayItem::SetPoints);
1817 self.push_iter(points);
1818 self.push_item(&item);
1822 pub fn define_clip_rect(
1824 parent_space_and_clip: &di::SpaceAndClipInfo,
1825 clip_rect: LayoutRect,
1827 let id = self.generate_clip_index();
1828 let item = di::DisplayItem::RectClip(di::RectClipDisplayItem {
1830 parent_space_and_clip: *parent_space_and_clip,
1834 self.push_item(&item);
1838 pub fn define_clip_rounded_rect(
1840 parent_space_and_clip: &di::SpaceAndClipInfo,
1841 clip: di::ComplexClipRegion,
1843 let id = self.generate_clip_index();
1844 let item = di::DisplayItem::RoundedRectClip(di::RoundedRectClipDisplayItem {
1846 parent_space_and_clip: *parent_space_and_clip,
1850 self.push_item(&item);
1854 pub fn define_clip<I>(
1856 parent_space_and_clip: &di::SpaceAndClipInfo,
1857 clip_rect: LayoutRect,
1861 I: IntoIterator<Item = di::ComplexClipRegion>,
1862 I::IntoIter: ExactSizeIterator + Clone,
1864 let id = self.generate_clip_index();
1865 let item = di::DisplayItem::Clip(di::ClipDisplayItem {
1867 parent_space_and_clip: *parent_space_and_clip,
1871 self.push_item(&item);
1872 self.push_iter(complex_clips);
1876 pub fn define_sticky_frame(
1878 parent_spatial_id: di::SpatialId,
1879 frame_rect: LayoutRect,
1880 margins: SideOffsets2D<Option<f32>, LayoutPixel>,
1881 vertical_offset_bounds: di::StickyOffsetBounds,
1882 horizontal_offset_bounds: di::StickyOffsetBounds,
1883 previously_applied_offset: LayoutVector2D,
1884 ) -> di::SpatialId {
1885 let id = self.generate_spatial_index();
1886 let item = di::DisplayItem::StickyFrame(di::StickyFrameDisplayItem {
1891 vertical_offset_bounds,
1892 horizontal_offset_bounds,
1893 previously_applied_offset,
1896 self.push_item(&item);
1903 clip_rect: LayoutRect,
1904 space_and_clip: &di::SpaceAndClipInfo,
1905 pipeline_id: PipelineId,
1906 ignore_missing_pipeline: bool
1908 let item = di::DisplayItem::Iframe(di::IframeDisplayItem {
1911 space_and_clip: *space_and_clip,
1913 ignore_missing_pipeline,
1915 self.push_item(&item);
1920 space_and_clip: &di::SpaceAndClipInfo,
1922 should_inflate: bool,
1924 let item = di::DisplayItem::PushShadow(di::PushShadowDisplayItem {
1925 space_and_clip: *space_and_clip,
1929 self.push_item(&item);
1932 pub fn pop_all_shadows(&mut self) {
1933 self.push_item(&di::DisplayItem::PopAllShadows);
1936 pub fn start_item_group(&mut self) {
1937 debug_assert!(!self.writing_to_chunk);
1938 debug_assert!(self.pending_chunk.is_empty());
1940 self.writing_to_chunk = true;
1943 fn flush_pending_item_group(&mut self, key: di::ItemKey) {
1944 // Push RetainedItems-marker to extra_data section.
1945 self.push_retained_items(key);
1947 // Push pending chunk to extra_data section.
1948 self.extra_data.append(&mut self.pending_chunk);
1950 // Push ReuseItems-marker to data section.
1951 self.push_reuse_items(key);
1954 pub fn finish_item_group(&mut self, key: di::ItemKey) -> bool {
1955 debug_assert!(self.writing_to_chunk);
1956 self.writing_to_chunk = false;
1958 if self.pending_chunk.is_empty() {
1962 self.flush_pending_item_group(key);
1966 pub fn cancel_item_group(&mut self, discard: bool) {
1967 debug_assert!(self.writing_to_chunk);
1968 self.writing_to_chunk = false;
1971 self.pending_chunk.clear();
1973 // Push pending chunk to data section.
1974 self.data.append(&mut self.pending_chunk);
1978 pub fn push_reuse_items(&mut self, key: di::ItemKey) {
1979 self.push_item_to_section(
1980 &di::DisplayItem::ReuseItems(key),
1981 DisplayListSection::Data
1985 fn push_retained_items(&mut self, key: di::ItemKey) {
1986 self.push_item_to_section(
1987 &di::DisplayItem::RetainedItems(key),
1988 DisplayListSection::ExtraData
1992 pub fn set_cache_size(&mut self, cache_size: usize) {
1993 self.cache_size = cache_size;
1996 pub fn finalize(mut self) -> (PipelineId, BuiltDisplayList) {
1997 assert!(self.save_state.is_none(), "Finalized DisplayListBuilder with a pending save");
1999 if let Some(content) = self.serialized_content_buffer.take() {
2000 println!("-- WebRender display list for {:?} --\n{}",
2001 self.pipeline_id, content);
2004 // Add `DisplayItem::max_size` zone of zeroes to the end of display list
2005 // so there is at least this amount available in the display list during
2007 ensure_red_zone::<di::DisplayItem>(&mut self.data);
2009 let extra_data_offset = self.data.len();
2011 if self.extra_data.len() > 0 {
2012 ensure_red_zone::<di::DisplayItem>(&mut self.extra_data);
2013 self.data.extend(self.extra_data);
2016 let end_time = precise_time_ns();
2020 descriptor: BuiltDisplayListDescriptor {
2021 gecko_display_list_time: 0.0,
2022 builder_start_time: self.builder_start_time,
2023 builder_finish_time: end_time,
2024 send_start_time: end_time,
2025 total_clip_nodes: self.next_clip_index,
2026 total_spatial_nodes: self.next_spatial_index,
2027 cache_size: self.cache_size,