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