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