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