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