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 bincode;
6 use euclid::SideOffsets2D;
7 #[cfg(feature = "deserialize")]
8 use serde::de::Deserializer;
9 #[cfg(feature = "serialize")]
10 use serde::ser::{Serializer, SerializeSeq};
11 use serde::{Deserialize, Serialize};
12 use std::io::{Read, Write};
13 use std::marker::PhantomData;
14 use std::{io, mem, ptr, slice};
15 use time::precise_time_ns;
16 use {AlphaType, BorderDetails, BorderDisplayItem, BorderRadius, BorderWidths, BoxShadowClipMode};
17 use {BoxShadowDisplayItem, ClipAndScrollInfo, ClipChainId, ClipChainItem, ClipDisplayItem, ClipId};
18 use {ColorF, ComplexClipRegion, DisplayItem, ExtendMode, ExternalScrollId, FilterOp};
19 use {FontInstanceKey, GlyphInstance, GlyphOptions, Gradient, GradientDisplayItem, GradientStop};
20 use {IframeDisplayItem, ImageDisplayItem, ImageKey, ImageMask, ImageRendering, LayerPrimitiveInfo};
21 use {LayoutPoint, LayoutPrimitiveInfo, LayoutRect, LayoutSize, LayoutTransform, LayoutVector2D};
22 use {LineDisplayItem, LineOrientation, LineStyle, LocalClip, MixBlendMode, PipelineId};
23 use {PropertyBinding, PushStackingContextDisplayItem, RadialGradient, RadialGradientDisplayItem};
24 use {RectangleDisplayItem, ScrollFrameDisplayItem, ScrollPolicy, ScrollSensitivity, Shadow};
25 use {SpecificDisplayItem, StackingContext, StickyFrameDisplayItem, StickyOffsetBounds};
26 use {TextDisplayItem, TransformStyle, YuvColorSpace, YuvData, YuvImageDisplayItem};
27 
28 // We don't want to push a long text-run. If a text-run is too long, split it into several parts.
29 // This needs to be set to (renderer::MAX_VERTEX_TEXTURE_WIDTH - VECS_PER_PRIM_HEADER - VECS_PER_TEXT_RUN) * 2
30 pub const MAX_TEXT_RUN_LENGTH: usize = 2038;
31 
32 // We start at 2, because the root reference is always 0 and the root scroll node is always 1.
33 const FIRST_CLIP_ID: usize = 2;
34 
35 #[repr(C)]
36 #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
37 pub struct ItemRange<T> {
38     start: usize,
39     length: usize,
40     _boo: PhantomData<T>,
41 }
42 
43 impl<T> Default for ItemRange<T> {
default() -> Self44     fn default() -> Self {
45         ItemRange {
46             start: 0,
47             length: 0,
48             _boo: PhantomData,
49         }
50     }
51 }
52 
53 impl<T> ItemRange<T> {
is_empty(&self) -> bool54     pub fn is_empty(&self) -> bool {
55         // Nothing more than space for a length (0).
56         self.length <= mem::size_of::<u64>()
57     }
58 }
59 
60 /// A display list.
61 #[derive(Clone, Default)]
62 pub struct BuiltDisplayList {
63     /// Serde encoded bytes. Mostly DisplayItems, but some mixed in slices.
64     data: Vec<u8>,
65     descriptor: BuiltDisplayListDescriptor,
66 }
67 
68 /// Describes the memory layout of a display list.
69 ///
70 /// A display list consists of some number of display list items, followed by a number of display
71 /// items.
72 #[repr(C)]
73 #[derive(Copy, Clone, Default, Deserialize, Serialize)]
74 pub struct BuiltDisplayListDescriptor {
75     /// The first IPC time stamp: before any work has been done
76     builder_start_time: u64,
77     /// The second IPC time stamp: after serialization
78     builder_finish_time: u64,
79     /// The third IPC time stamp: just before sending
80     send_start_time: u64,
81     /// The amount of clips ids assigned while building this display list.
82     total_clip_ids: usize,
83 }
84 
85 pub struct BuiltDisplayListIter<'a> {
86     list: &'a BuiltDisplayList,
87     data: &'a [u8],
88     cur_item: DisplayItem,
89     cur_stops: ItemRange<GradientStop>,
90     cur_glyphs: ItemRange<GlyphInstance>,
91     cur_filters: ItemRange<FilterOp>,
92     cur_clip_chain_items: ItemRange<ClipId>,
93     cur_complex_clip: (ItemRange<ComplexClipRegion>, usize),
94     peeking: Peek,
95 }
96 
97 pub struct DisplayItemRef<'a: 'b, 'b> {
98     iter: &'b BuiltDisplayListIter<'a>,
99 }
100 
101 #[derive(PartialEq)]
102 enum Peek {
103     StartPeeking,
104     IsPeeking,
105     NotPeeking,
106 }
107 
108 #[derive(Clone)]
109 pub struct AuxIter<'a, T> {
110     data: &'a [u8],
111     size: usize,
112     _boo: PhantomData<T>,
113 }
114 
115 impl BuiltDisplayListDescriptor {}
116 
117 impl BuiltDisplayList {
from_data(data: Vec<u8>, descriptor: BuiltDisplayListDescriptor) -> BuiltDisplayList118     pub fn from_data(data: Vec<u8>, descriptor: BuiltDisplayListDescriptor) -> BuiltDisplayList {
119         BuiltDisplayList { data, descriptor }
120     }
121 
into_data(mut self) -> (Vec<u8>, BuiltDisplayListDescriptor)122     pub fn into_data(mut self) -> (Vec<u8>, BuiltDisplayListDescriptor) {
123         self.descriptor.send_start_time = precise_time_ns();
124         (self.data, self.descriptor)
125     }
126 
data(&self) -> &[u8]127     pub fn data(&self) -> &[u8] {
128         &self.data[..]
129     }
130 
131     // Currently redundant with data, but may be useful if we add extra data to dl
item_slice(&self) -> &[u8]132     pub fn item_slice(&self) -> &[u8] {
133         &self.data[..]
134     }
135 
descriptor(&self) -> &BuiltDisplayListDescriptor136     pub fn descriptor(&self) -> &BuiltDisplayListDescriptor {
137         &self.descriptor
138     }
139 
times(&self) -> (u64, u64, u64)140     pub fn times(&self) -> (u64, u64, u64) {
141         (
142             self.descriptor.builder_start_time,
143             self.descriptor.builder_finish_time,
144             self.descriptor.send_start_time,
145         )
146     }
147 
total_clip_ids(&self) -> usize148     pub fn total_clip_ids(&self) -> usize {
149         self.descriptor.total_clip_ids
150     }
151 
iter(&self) -> BuiltDisplayListIter152     pub fn iter(&self) -> BuiltDisplayListIter {
153         BuiltDisplayListIter::new(self)
154     }
155 
get<'de, T: Deserialize<'de>>(&self, range: ItemRange<T>) -> AuxIter<T>156     pub fn get<'de, T: Deserialize<'de>>(&self, range: ItemRange<T>) -> AuxIter<T> {
157         AuxIter::new(&self.data[range.start .. range.start + range.length])
158     }
159 }
160 
161 /// Returns the byte-range the slice occupied, and the number of elements
162 /// in the slice.
skip_slice<T: for<'de> Deserialize<'de>>( list: &BuiltDisplayList, data: &mut &[u8], ) -> (ItemRange<T>, usize)163 fn skip_slice<T: for<'de> Deserialize<'de>>(
164     list: &BuiltDisplayList,
165     data: &mut &[u8],
166 ) -> (ItemRange<T>, usize) {
167     let base = list.data.as_ptr() as usize;
168 
169     let byte_size: usize = bincode::deserialize_from(data, bincode::Infinite)
170                                     .expect("MEH: malicious input?");
171     let start = data.as_ptr() as usize;
172     let item_count: usize = bincode::deserialize_from(data, bincode::Infinite)
173                                     .expect("MEH: malicious input?");
174 
175     // Remember how many bytes item_count occupied
176     let item_count_size = data.as_ptr() as usize - start;
177 
178     let range = ItemRange {
179         start: start - base,                      // byte offset to item_count
180         length: byte_size + item_count_size,      // number of bytes for item_count + payload
181         _boo: PhantomData,
182     };
183 
184     // Adjust data pointer to skip read values
185     *data = &data[byte_size ..];
186     (range, item_count)
187 }
188 
189 
190 impl<'a> BuiltDisplayListIter<'a> {
new(list: &'a BuiltDisplayList) -> Self191     pub fn new(list: &'a BuiltDisplayList) -> Self {
192         Self::new_with_list_and_data(list, list.item_slice())
193     }
194 
new_with_list_and_data(list: &'a BuiltDisplayList, data: &'a [u8]) -> Self195     pub fn new_with_list_and_data(list: &'a BuiltDisplayList, data: &'a [u8]) -> Self {
196         BuiltDisplayListIter {
197             list,
198             data: &data,
199             cur_item: DisplayItem {
200                 // Dummy data, will be overwritten by `next`
201                 item: SpecificDisplayItem::PopStackingContext,
202                 clip_and_scroll:
203                     ClipAndScrollInfo::simple(ClipId::root_scroll_node(PipelineId::dummy())),
204                 info: LayoutPrimitiveInfo::new(LayoutRect::zero()),
205             },
206             cur_stops: ItemRange::default(),
207             cur_glyphs: ItemRange::default(),
208             cur_filters: ItemRange::default(),
209             cur_clip_chain_items: ItemRange::default(),
210             cur_complex_clip: (ItemRange::default(), 0),
211             peeking: Peek::NotPeeking,
212         }
213     }
214 
display_list(&self) -> &'a BuiltDisplayList215     pub fn display_list(&self) -> &'a BuiltDisplayList {
216         self.list
217     }
218 
next<'b>(&'b mut self) -> Option<DisplayItemRef<'a, 'b>>219     pub fn next<'b>(&'b mut self) -> Option<DisplayItemRef<'a, 'b>> {
220         use SpecificDisplayItem::*;
221 
222         match self.peeking {
223             Peek::IsPeeking => {
224                 self.peeking = Peek::NotPeeking;
225                 return Some(self.as_ref());
226             }
227             Peek::StartPeeking => {
228                 self.peeking = Peek::IsPeeking;
229             }
230             Peek::NotPeeking => { /* do nothing */ }
231         }
232 
233         // Don't let these bleed into another item
234         self.cur_stops = ItemRange::default();
235         self.cur_complex_clip = (ItemRange::default(), 0);
236         self.cur_clip_chain_items = ItemRange::default();
237 
238         loop {
239             if self.data.len() == 0 {
240                 return None;
241             }
242 
243             {
244                 let reader = bincode::read_types::IoReader::new(UnsafeReader::new(&mut self.data));
245                 let mut deserializer = bincode::Deserializer::new(reader, bincode::Infinite);
246                 Deserialize::deserialize_in_place(&mut deserializer, &mut self.cur_item)
247                     .expect("MEH: malicious process?");
248             }
249 
250             match self.cur_item.item {
251                 SetGradientStops => {
252                     self.cur_stops = skip_slice::<GradientStop>(self.list, &mut self.data).0;
253 
254                     // This is a dummy item, skip over it
255                     continue;
256                 }
257                 ClipChain(_) => {
258                     self.cur_clip_chain_items = skip_slice::<ClipId>(self.list, &mut self.data).0;
259                 }
260                 Clip(_) | ScrollFrame(_) => {
261                     self.cur_complex_clip = self.skip_slice::<ComplexClipRegion>()
262                 }
263                 Text(_) => self.cur_glyphs = self.skip_slice::<GlyphInstance>().0,
264                 PushStackingContext(_) => self.cur_filters = self.skip_slice::<FilterOp>().0,
265                 _ => { /* do nothing */ }
266             }
267 
268             break;
269         }
270 
271         Some(self.as_ref())
272     }
273 
skip_slice<T: for<'de> Deserialize<'de>>(&mut self) -> (ItemRange<T>, usize)274     fn skip_slice<T: for<'de> Deserialize<'de>>(&mut self) -> (ItemRange<T>, usize) {
275         skip_slice::<T>(self.list, &mut self.data)
276     }
277 
as_ref<'b>(&'b self) -> DisplayItemRef<'a, 'b>278     pub fn as_ref<'b>(&'b self) -> DisplayItemRef<'a, 'b> {
279         DisplayItemRef { iter: self }
280     }
281 
starting_stacking_context( &mut self, ) -> Option<(StackingContext, LayoutRect, ItemRange<FilterOp>)>282     pub fn starting_stacking_context(
283         &mut self,
284     ) -> Option<(StackingContext, LayoutRect, ItemRange<FilterOp>)> {
285         self.next().and_then(|item| match *item.item() {
286             SpecificDisplayItem::PushStackingContext(ref specific_item) => Some((
287                 specific_item.stacking_context,
288                 item.rect(),
289                 item.filters(),
290             )),
291             _ => None,
292         })
293     }
294 
skip_current_stacking_context(&mut self)295     pub fn skip_current_stacking_context(&mut self) {
296         let mut depth = 0;
297         while let Some(item) = self.next() {
298             match *item.item() {
299                 SpecificDisplayItem::PushStackingContext(..) => depth += 1,
300                 SpecificDisplayItem::PopStackingContext if depth == 0 => return,
301                 SpecificDisplayItem::PopStackingContext => depth -= 1,
302                 _ => {}
303             }
304             debug_assert!(depth >= 0);
305         }
306     }
307 
current_stacking_context_empty(&mut self) -> bool308     pub fn current_stacking_context_empty(&mut self) -> bool {
309         match self.peek() {
310             Some(item) => *item.item() == SpecificDisplayItem::PopStackingContext,
311             None => true,
312         }
313     }
314 
peek<'b>(&'b mut self) -> Option<DisplayItemRef<'a, 'b>>315     pub fn peek<'b>(&'b mut self) -> Option<DisplayItemRef<'a, 'b>> {
316         if self.peeking == Peek::NotPeeking {
317             self.peeking = Peek::StartPeeking;
318             self.next()
319         } else {
320             Some(self.as_ref())
321         }
322     }
323 }
324 
325 // Some of these might just become ItemRanges
326 impl<'a, 'b> DisplayItemRef<'a, 'b> {
display_item(&self) -> &DisplayItem327     pub fn display_item(&self) -> &DisplayItem {
328         &self.iter.cur_item
329     }
330 
rect(&self) -> LayoutRect331     pub fn rect(&self) -> LayoutRect {
332         self.iter.cur_item.info.rect
333     }
334 
get_layer_primitive_info(&self, offset: &LayoutVector2D) -> LayerPrimitiveInfo335     pub fn get_layer_primitive_info(&self, offset: &LayoutVector2D) -> LayerPrimitiveInfo {
336         let info = self.iter.cur_item.info;
337         LayerPrimitiveInfo {
338             rect: info.rect.translate(&offset),
339             local_clip: info.local_clip.create_with_offset(offset),
340             is_backface_visible: info.is_backface_visible,
341             tag: info.tag,
342         }
343     }
344 
local_clip(&self) -> &LocalClip345     pub fn local_clip(&self) -> &LocalClip {
346         &self.iter.cur_item.info.local_clip
347     }
348 
clip_and_scroll(&self) -> ClipAndScrollInfo349     pub fn clip_and_scroll(&self) -> ClipAndScrollInfo {
350         self.iter.cur_item.clip_and_scroll
351     }
352 
item(&self) -> &SpecificDisplayItem353     pub fn item(&self) -> &SpecificDisplayItem {
354         &self.iter.cur_item.item
355     }
356 
complex_clip(&self) -> (ItemRange<ComplexClipRegion>, usize)357     pub fn complex_clip(&self) -> (ItemRange<ComplexClipRegion>, usize) {
358         self.iter.cur_complex_clip
359     }
360 
gradient_stops(&self) -> ItemRange<GradientStop>361     pub fn gradient_stops(&self) -> ItemRange<GradientStop> {
362         self.iter.cur_stops
363     }
364 
glyphs(&self) -> ItemRange<GlyphInstance>365     pub fn glyphs(&self) -> ItemRange<GlyphInstance> {
366         self.iter.cur_glyphs
367     }
368 
filters(&self) -> ItemRange<FilterOp>369     pub fn filters(&self) -> ItemRange<FilterOp> {
370         self.iter.cur_filters
371     }
372 
clip_chain_items(&self) -> ItemRange<ClipId>373     pub fn clip_chain_items(&self) -> ItemRange<ClipId> {
374         self.iter.cur_clip_chain_items
375     }
376 
display_list(&self) -> &BuiltDisplayList377     pub fn display_list(&self) -> &BuiltDisplayList {
378         self.iter.display_list()
379     }
380 
is_backface_visible(&self) -> bool381     pub fn is_backface_visible(&self) -> bool {
382         self.iter.cur_item.info.is_backface_visible
383     }
384 
385     // Creates a new iterator where this element's iterator is, to hack around borrowck.
sub_iter(&self) -> BuiltDisplayListIter<'a>386     pub fn sub_iter(&self) -> BuiltDisplayListIter<'a> {
387         BuiltDisplayListIter::new_with_list_and_data(self.iter.list, self.iter.data)
388     }
389 }
390 
391 impl<'de, 'a, T: Deserialize<'de>> AuxIter<'a, T> {
new(mut data: &'a [u8]) -> Self392     pub fn new(mut data: &'a [u8]) -> Self {
393         let size: usize = if data.len() == 0 {
394             0 // Accept empty ItemRanges pointing anywhere
395         } else {
396             bincode::deserialize_from(&mut UnsafeReader::new(&mut data), bincode::Infinite)
397                 .expect("MEH: malicious input?")
398         };
399 
400         AuxIter {
401             data,
402             size,
403             _boo: PhantomData,
404         }
405     }
406 }
407 
408 impl<'a, T: for<'de> Deserialize<'de>> Iterator for AuxIter<'a, T> {
409     type Item = T;
410 
next(&mut self) -> Option<T>411     fn next(&mut self) -> Option<T> {
412         if self.size == 0 {
413             None
414         } else {
415             self.size -= 1;
416             Some(
417                 bincode::deserialize_from(&mut UnsafeReader::new(&mut self.data), bincode::Infinite)
418                     .expect("MEH: malicious input?"),
419             )
420         }
421     }
422 
size_hint(&self) -> (usize, Option<usize>)423     fn size_hint(&self) -> (usize, Option<usize>) {
424         (self.size, Some(self.size))
425     }
426 }
427 
428 impl<'a, T: for<'de> Deserialize<'de>> ::std::iter::ExactSizeIterator for AuxIter<'a, T> {}
429 
430 
431 #[cfg(feature = "serialize")]
432 impl Serialize for BuiltDisplayList {
serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error>433     fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
434         use display_item::CompletelySpecificDisplayItem::*;
435         use display_item::GenericDisplayItem;
436 
437         let mut seq = serializer.serialize_seq(None)?;
438         let mut traversal = self.iter();
439         while let Some(item) = traversal.next() {
440             let display_item = item.display_item();
441             let serial_di = GenericDisplayItem {
442                 item: match display_item.item {
443                     SpecificDisplayItem::Clip(v) => Clip(
444                         v,
445                         item.iter.list.get(item.iter.cur_complex_clip.0).collect()
446                     ),
447                     SpecificDisplayItem::ClipChain(v) => ClipChain(
448                         v,
449                         item.iter.list.get(item.iter.cur_clip_chain_items).collect(),
450                     ),
451                     SpecificDisplayItem::ScrollFrame(v) => ScrollFrame(
452                         v,
453                         item.iter.list.get(item.iter.cur_complex_clip.0).collect()
454                     ),
455                     SpecificDisplayItem::StickyFrame(v) => StickyFrame(v),
456                     SpecificDisplayItem::Rectangle(v) => Rectangle(v),
457                     SpecificDisplayItem::ClearRectangle => ClearRectangle,
458                     SpecificDisplayItem::Line(v) => Line(v),
459                     SpecificDisplayItem::Text(v) => Text(
460                         v,
461                         item.iter.list.get(item.iter.cur_glyphs).collect()
462                     ),
463                     SpecificDisplayItem::Image(v) => Image(v),
464                     SpecificDisplayItem::YuvImage(v) => YuvImage(v),
465                     SpecificDisplayItem::Border(v) => Border(v),
466                     SpecificDisplayItem::BoxShadow(v) => BoxShadow(v),
467                     SpecificDisplayItem::Gradient(v) => Gradient(v),
468                     SpecificDisplayItem::RadialGradient(v) => RadialGradient(v),
469                     SpecificDisplayItem::Iframe(v) => Iframe(v),
470                     SpecificDisplayItem::PushStackingContext(v) => PushStackingContext(
471                         v,
472                         item.iter.list.get(item.iter.cur_filters).collect()
473                     ),
474                     SpecificDisplayItem::PopStackingContext => PopStackingContext,
475                     SpecificDisplayItem::SetGradientStops => SetGradientStops(
476                         item.iter.list.get(item.iter.cur_stops).collect()
477                     ),
478                     SpecificDisplayItem::PushShadow(v) => PushShadow(v),
479                     SpecificDisplayItem::PopAllShadows => PopAllShadows,
480                 },
481                 clip_and_scroll: display_item.clip_and_scroll,
482                 info: display_item.info,
483             };
484             seq.serialize_element(&serial_di)?
485         }
486         seq.end()
487     }
488 }
489 
490 // The purpose of this implementation is to deserialize
491 // a display list from one format just to immediately
492 // serialize then into a "built" `Vec<u8>`.
493 
494 #[cfg(feature = "deserialize")]
495 impl<'de> Deserialize<'de> for BuiltDisplayList {
deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de>,496     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
497     where
498         D: Deserializer<'de>,
499     {
500         use display_item::CompletelySpecificDisplayItem::*;
501         use display_item::{CompletelySpecificDisplayItem, GenericDisplayItem};
502 
503         let list = Vec::<GenericDisplayItem<CompletelySpecificDisplayItem>>
504             ::deserialize(deserializer)?;
505 
506         let mut data = Vec::new();
507         let mut temp = Vec::new();
508         let mut total_clip_ids = FIRST_CLIP_ID;
509         for complete in list {
510             let item = DisplayItem {
511                 item: match complete.item {
512                     Clip(specific_item, complex_clips) => {
513                         total_clip_ids += 1;
514                         DisplayListBuilder::push_iter_impl(&mut temp, complex_clips);
515                         SpecificDisplayItem::Clip(specific_item)
516                     },
517                     ClipChain(specific_item, clip_chain_ids) => {
518                         DisplayListBuilder::push_iter_impl(&mut temp, clip_chain_ids);
519                         SpecificDisplayItem::ClipChain(specific_item)
520                     }
521                     ScrollFrame(specific_item, complex_clips) => {
522                         total_clip_ids += 2;
523                         DisplayListBuilder::push_iter_impl(&mut temp, complex_clips);
524                         SpecificDisplayItem::ScrollFrame(specific_item)
525                     },
526                     StickyFrame(specific_item) => {
527                         total_clip_ids += 1;
528                         SpecificDisplayItem::StickyFrame(specific_item)
529                     }
530                     Rectangle(specific_item) => SpecificDisplayItem::Rectangle(specific_item),
531                     ClearRectangle => SpecificDisplayItem::ClearRectangle,
532                     Line(specific_item) => SpecificDisplayItem::Line(specific_item),
533                     Text(specific_item, glyphs) => {
534                         DisplayListBuilder::push_iter_impl(&mut temp, glyphs);
535                         SpecificDisplayItem::Text(specific_item)
536                     },
537                     Image(specific_item) => SpecificDisplayItem::Image(specific_item),
538                     YuvImage(specific_item) => SpecificDisplayItem::YuvImage(specific_item),
539                     Border(specific_item) => SpecificDisplayItem::Border(specific_item),
540                     BoxShadow(specific_item) => SpecificDisplayItem::BoxShadow(specific_item),
541                     Gradient(specific_item) => SpecificDisplayItem::Gradient(specific_item),
542                     RadialGradient(specific_item) =>
543                         SpecificDisplayItem::RadialGradient(specific_item),
544                     Iframe(specific_item) => {
545                         total_clip_ids += 1;
546                         SpecificDisplayItem::Iframe(specific_item)
547                     }
548                     PushStackingContext(specific_item, filters) => {
549                         if specific_item.stacking_context.reference_frame_id.is_some() {
550                             total_clip_ids += 1;
551                         }
552                         DisplayListBuilder::push_iter_impl(&mut temp, filters);
553                         SpecificDisplayItem::PushStackingContext(specific_item)
554                     },
555                     PopStackingContext => SpecificDisplayItem::PopStackingContext,
556                     SetGradientStops(stops) => {
557                         DisplayListBuilder::push_iter_impl(&mut temp, stops);
558                         SpecificDisplayItem::SetGradientStops
559                     },
560                     PushShadow(specific_item) => SpecificDisplayItem::PushShadow(specific_item),
561                     PopAllShadows => SpecificDisplayItem::PopAllShadows,
562                 },
563                 clip_and_scroll: complete.clip_and_scroll,
564                 info: complete.info,
565             };
566             serialize_fast(&mut data, &item);
567             // the aux data is serialized after the item, hence the temporary
568             data.extend(temp.drain(..));
569         }
570 
571         Ok(BuiltDisplayList {
572             data,
573             descriptor: BuiltDisplayListDescriptor {
574                 builder_start_time: 0,
575                 builder_finish_time: 1,
576                 send_start_time: 0,
577                 total_clip_ids,
578             },
579         })
580     }
581 }
582 
583 // This is a replacement for bincode::serialize_into(&vec)
584 // The default implementation Write for Vec will basically
585 // call extend_from_slice(). Serde ends up calling that for every
586 // field of a struct that we're serializing. extend_from_slice()
587 // does not get inlined and thus we end up calling a generic memcpy()
588 // implementation. If we instead reserve enough room for the serialized
589 // struct in the Vec ahead of time we can rely on that and use
590 // the following UnsafeVecWriter to write into the vec without
591 // any checks. This writer assumes that size returned by the
592 // serialize function will not change between calls to serialize_into:
593 //
594 // For example, the following struct will cause memory unsafety when
595 // used with UnsafeVecWriter.
596 //
597 // struct S {
598 //    first: Cell<bool>,
599 // }
600 //
601 // impl Serialize for S {
602 //    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
603 //        where S: Serializer
604 //    {
605 //        if self.first.get() {
606 //            self.first.set(false);
607 //            ().serialize(serializer)
608 //        } else {
609 //            0.serialize(serializer)
610 //        }
611 //    }
612 // }
613 //
614 
615 struct UnsafeVecWriter(*mut u8);
616 
617 impl Write for UnsafeVecWriter {
618     #[inline(always)]
write(&mut self, buf: &[u8]) -> io::Result<usize>619     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
620         unsafe {
621             ptr::copy_nonoverlapping(buf.as_ptr(), self.0, buf.len());
622             self.0 = self.0.offset(buf.len() as isize);
623         }
624         Ok(buf.len())
625     }
626 
627     #[inline(always)]
write_all(&mut self, buf: &[u8]) -> io::Result<()>628     fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
629         unsafe {
630             ptr::copy_nonoverlapping(buf.as_ptr(), self.0, buf.len());
631             self.0 = self.0.offset(buf.len() as isize);
632         }
633         Ok(())
634     }
635 
636     #[inline(always)]
flush(&mut self) -> io::Result<()>637     fn flush(&mut self) -> io::Result<()> { Ok(()) }
638 }
639 
640 struct SizeCounter(usize);
641 
642 impl<'a> Write for SizeCounter {
643     #[inline(always)]
write(&mut self, buf: &[u8]) -> io::Result<usize>644     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
645         self.0 += buf.len();
646         Ok(buf.len())
647     }
648 
649     #[inline(always)]
write_all(&mut self, buf: &[u8]) -> io::Result<()>650     fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
651         self.0 += buf.len();
652         Ok(())
653     }
654 
655     #[inline(always)]
flush(&mut self) -> io::Result<()>656     fn flush(&mut self) -> io::Result<()> { Ok(()) }
657 }
658 
659 /// Serializes a value assuming the Serialize impl has a stable size across two
660 /// invocations.
661 ///
662 /// If this assumption is incorrect, the result will be Undefined Behaviour. This
663 /// assumption should hold for all derived Serialize impls, which is all we currently
664 /// use.
serialize_fast<T: Serialize>(vec: &mut Vec<u8>, e: &T)665 fn serialize_fast<T: Serialize>(vec: &mut Vec<u8>, e: &T) {
666     // manually counting the size is faster than vec.reserve(bincode::serialized_size(&e) as usize) for some reason
667     let mut size = SizeCounter(0);
668     bincode::serialize_into(&mut size, e, bincode::Infinite).unwrap();
669     vec.reserve(size.0);
670 
671     let old_len = vec.len();
672     let ptr = unsafe { vec.as_mut_ptr().offset(old_len as isize) };
673     let mut w = UnsafeVecWriter(ptr);
674     bincode::serialize_into(&mut w, e, bincode::Infinite).unwrap();
675 
676     // fix up the length
677     unsafe { vec.set_len(old_len + size.0); }
678 
679     // make sure we wrote the right amount
680     debug_assert_eq!(((w.0 as usize) - (vec.as_ptr() as usize)), vec.len());
681 }
682 
683 /// Serializes an iterator, assuming:
684 ///
685 /// * The Clone impl is trivial (e.g. we're just memcopying a slice iterator)
686 /// * The ExactSizeIterator impl is stable and correct across a Clone
687 /// * The Serialize impl has a stable size across two invocations
688 ///
689 /// If the first is incorrect, webrender will be very slow. If the other two are
690 /// incorrect, the result will be Undefined Behaviour! The ExactSizeIterator
691 /// bound would ideally be replaced with a TrustedLen bound to protect us a bit
692 /// better, but that trait isn't stable (and won't be for a good while, if ever).
693 ///
694 /// Debug asserts are included that should catch all Undefined Behaviour, but
695 /// we can't afford to include these in release builds.
serialize_iter_fast<I>(vec: &mut Vec<u8>, iter: I) -> usize where I: ExactSizeIterator + Clone, I::Item: Serialize,696 fn serialize_iter_fast<I>(vec: &mut Vec<u8>, iter: I) -> usize
697 where I: ExactSizeIterator + Clone,
698       I::Item: Serialize,
699 {
700     // manually counting the size is faster than vec.reserve(bincode::serialized_size(&e) as usize) for some reason
701     let mut size = SizeCounter(0);
702     let mut count1 = 0;
703 
704     for e in iter.clone() {
705         bincode::serialize_into(&mut size, &e, bincode::Infinite).unwrap();
706         count1 += 1;
707     }
708 
709     vec.reserve(size.0);
710 
711     let old_len = vec.len();
712     let ptr = unsafe { vec.as_mut_ptr().offset(old_len as isize) };
713     let mut w = UnsafeVecWriter(ptr);
714     let mut count2 = 0;
715 
716     for e in iter {
717         bincode::serialize_into(&mut w, &e, bincode::Infinite).unwrap();
718         count2 += 1;
719     }
720 
721     // fix up the length
722     unsafe { vec.set_len(old_len + size.0); }
723 
724     // make sure we wrote the right amount
725     debug_assert_eq!(((w.0 as usize) - (vec.as_ptr() as usize)), vec.len());
726     debug_assert_eq!(count1, count2);
727 
728     count1
729 }
730 
731 // This uses a (start, end) representation instead of (start, len) so that
732 // only need to update a single field as we read through it. This
733 // makes it easier for llvm to understand what's going on. (https://github.com/rust-lang/rust/issues/45068)
734 // We update the slice only once we're done reading
735 struct UnsafeReader<'a: 'b, 'b> {
736     start: *const u8,
737     end: *const u8,
738     slice: &'b mut &'a [u8],
739 }
740 
741 impl<'a, 'b> UnsafeReader<'a, 'b> {
742     #[inline(always)]
new(buf: &'b mut &'a [u8]) -> UnsafeReader<'a, 'b>743     fn new(buf: &'b mut &'a [u8]) -> UnsafeReader<'a, 'b> {
744         unsafe {
745             let end = buf.as_ptr().offset(buf.len() as isize);
746             let start = buf.as_ptr();
747             UnsafeReader { start: start, end, slice: buf }
748         }
749     }
750 
751     // This read implementation is significantly faster than the standard &[u8] one.
752     //
753     // First, it only supports reading exactly buf.len() bytes. This ensures that
754     // the argument to memcpy is always buf.len() and will allow a constant buf.len()
755     // to be propagated through to memcpy which LLVM will turn into explicit loads and
756     // stores. The standard implementation does a len = min(slice.len(), buf.len())
757     //
758     // Second, we only need to adjust 'start' after reading and it's only adjusted by a
759     // constant. This allows LLVM to avoid adjusting the length field after ever read
760     // and lets it be aggregated into a single adjustment.
761     #[inline(always)]
read_internal(&mut self, buf: &mut [u8])762     fn read_internal(&mut self, buf: &mut [u8]) {
763         // this is safe because we panic if start + buf.len() > end
764         unsafe {
765             assert!(self.start.offset(buf.len() as isize) <= self.end, "UnsafeReader: read past end of target");
766             ptr::copy_nonoverlapping(self.start, buf.as_mut_ptr(), buf.len());
767             self.start = self.start.offset(buf.len() as isize);
768         }
769     }
770 }
771 
772 impl<'a, 'b> Drop for UnsafeReader<'a, 'b> {
773     // this adjusts input slice so that it properly represents the amount that's left.
774     #[inline(always)]
drop(&mut self)775     fn drop(&mut self) {
776         // this is safe because we know that start and end are contained inside the original slice
777         unsafe {
778             *self.slice = slice::from_raw_parts(self.start, (self.end as usize) - (self.start as usize));
779         }
780     }
781 }
782 
783 impl<'a, 'b> Read for UnsafeReader<'a, 'b> {
784     // These methods were not being inlined and we need them to be so that the memcpy
785     // is for a constant size
786     #[inline(always)]
read(&mut self, buf: &mut [u8]) -> io::Result<usize>787     fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
788         self.read_internal(buf);
789         Ok(buf.len())
790     }
791     #[inline(always)]
read_exact(&mut self, buf: &mut [u8]) -> io::Result<()>792     fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
793         self.read_internal(buf);
794         Ok(())
795     }
796 }
797 
798 #[derive(Clone, Debug)]
799 pub struct SaveState {
800     dl_len: usize,
801     clip_stack_len: usize,
802     next_clip_id: usize,
803     next_clip_chain_id: u64,
804 }
805 
806 #[derive(Clone)]
807 pub struct DisplayListBuilder {
808     pub data: Vec<u8>,
809     pub pipeline_id: PipelineId,
810     clip_stack: Vec<ClipAndScrollInfo>,
811     next_clip_id: usize,
812     next_clip_chain_id: u64,
813     builder_start_time: u64,
814 
815     /// The size of the content of this display list. This is used to allow scrolling
816     /// outside the bounds of the display list items themselves.
817     content_size: LayoutSize,
818     save_state: Option<SaveState>,
819 }
820 
821 impl DisplayListBuilder {
new(pipeline_id: PipelineId, content_size: LayoutSize) -> Self822     pub fn new(pipeline_id: PipelineId, content_size: LayoutSize) -> Self {
823         Self::with_capacity(pipeline_id, content_size, 0)
824     }
825 
with_capacity( pipeline_id: PipelineId, content_size: LayoutSize, capacity: usize, ) -> Self826     pub fn with_capacity(
827         pipeline_id: PipelineId,
828         content_size: LayoutSize,
829         capacity: usize,
830     ) -> Self {
831         let start_time = precise_time_ns();
832 
833         DisplayListBuilder {
834             data: Vec::with_capacity(capacity),
835             pipeline_id,
836             clip_stack: vec![
837                 ClipAndScrollInfo::simple(ClipId::root_scroll_node(pipeline_id)),
838             ],
839             next_clip_id: FIRST_CLIP_ID,
840             next_clip_chain_id: 0,
841             builder_start_time: start_time,
842             content_size,
843             save_state: None,
844         }
845     }
846 
847     /// Return the content size for this display list
content_size(&self) -> LayoutSize848     pub fn content_size(&self) -> LayoutSize {
849         self.content_size
850     }
851 
852     /// Saves the current display list state, so it may be `restore()`'d.
853     ///
854     /// # Conditions:
855     ///
856     /// * Doesn't support popping clips that were pushed before the save.
857     /// * Doesn't support nested saves.
858     /// * Must call `clear_save()` if the restore becomes unnecessary.
save(&mut self)859     pub fn save(&mut self) {
860         assert!(self.save_state.is_none(), "DisplayListBuilder doesn't support nested saves");
861 
862         self.save_state = Some(SaveState {
863             clip_stack_len: self.clip_stack.len(),
864             dl_len: self.data.len(),
865             next_clip_id: self.next_clip_id,
866             next_clip_chain_id: self.next_clip_chain_id,
867         });
868     }
869 
870     /// Restores the state of the builder to when `save()` was last called.
restore(&mut self)871     pub fn restore(&mut self) {
872         let state = self.save_state.take().expect("No save to restore DisplayListBuilder from");
873 
874         self.clip_stack.truncate(state.clip_stack_len);
875         self.data.truncate(state.dl_len);
876         self.next_clip_id = state.next_clip_id;
877         self.next_clip_chain_id = state.next_clip_chain_id;
878     }
879 
880     /// Discards the builder's save (indicating the attempted operation was sucessful).
clear_save(&mut self)881     pub fn clear_save(&mut self) {
882         self.save_state.take().expect("No save to clear in DisplayListBuilder");
883     }
884 
print_display_list(&mut self)885     pub fn print_display_list(&mut self) {
886         let mut temp = BuiltDisplayList::default();
887         mem::swap(&mut temp.data, &mut self.data);
888 
889         {
890             let mut iter = BuiltDisplayListIter::new(&temp);
891             while let Some(item) = iter.next() {
892                 println!("{:?}", item.display_item());
893             }
894         }
895 
896         self.data = temp.data;
897     }
898 
push_item(&mut self, item: SpecificDisplayItem, info: &LayoutPrimitiveInfo)899     fn push_item(&mut self, item: SpecificDisplayItem, info: &LayoutPrimitiveInfo) {
900         serialize_fast(
901             &mut self.data,
902             &DisplayItem {
903                 item,
904                 clip_and_scroll: *self.clip_stack.last().unwrap(),
905                 info: *info,
906             },
907         )
908     }
909 
push_item_with_clip_scroll_info( &mut self, item: SpecificDisplayItem, info: &LayoutPrimitiveInfo, scrollinfo: ClipAndScrollInfo )910     fn push_item_with_clip_scroll_info(
911         &mut self,
912         item: SpecificDisplayItem,
913         info: &LayoutPrimitiveInfo,
914         scrollinfo: ClipAndScrollInfo
915     ) {
916         serialize_fast(
917             &mut self.data,
918             &DisplayItem {
919                 item,
920                 clip_and_scroll: scrollinfo,
921                 info: *info,
922             },
923         )
924     }
925 
push_new_empty_item(&mut self, item: SpecificDisplayItem)926     fn push_new_empty_item(&mut self, item: SpecificDisplayItem) {
927         let info = LayoutPrimitiveInfo::new(LayoutRect::zero());
928         serialize_fast(
929             &mut self.data,
930             &DisplayItem {
931                 item,
932                 clip_and_scroll: *self.clip_stack.last().unwrap(),
933                 info,
934             }
935         )
936     }
937 
push_iter_impl<I>(data: &mut Vec<u8>, iter_source: I) where I: IntoIterator, I::IntoIter: ExactSizeIterator + Clone, I::Item: Serialize,938     fn push_iter_impl<I>(data: &mut Vec<u8>, iter_source: I)
939     where
940         I: IntoIterator,
941         I::IntoIter: ExactSizeIterator + Clone,
942         I::Item: Serialize,
943     {
944         let iter = iter_source.into_iter();
945         let len = iter.len();
946         // Format:
947         // payload_byte_size: usize, item_count: usize, [I; item_count]
948 
949         // We write a dummy value so there's room for later
950         let byte_size_offset = data.len();
951         serialize_fast(data, &0usize);
952         serialize_fast(data, &len);
953         let payload_offset = data.len();
954 
955         let count = serialize_iter_fast(data, iter);
956 
957         // Now write the actual byte_size
958         let final_offset = data.len();
959         let byte_size = final_offset - payload_offset;
960 
961         // Note we don't use serialize_fast because we don't want to change the Vec's len
962         bincode::serialize_into(
963             &mut &mut data[byte_size_offset..],
964             &byte_size,
965             bincode::Infinite,
966         ).unwrap();
967 
968         debug_assert_eq!(len, count);
969     }
970 
push_iter<I>(&mut self, iter: I) where I: IntoIterator, I::IntoIter: ExactSizeIterator + Clone, I::Item: Serialize,971     fn push_iter<I>(&mut self, iter: I)
972     where
973         I: IntoIterator,
974         I::IntoIter: ExactSizeIterator + Clone,
975         I::Item: Serialize,
976     {
977         Self::push_iter_impl(&mut self.data, iter);
978     }
979 
push_rect(&mut self, info: &LayoutPrimitiveInfo, color: ColorF)980     pub fn push_rect(&mut self, info: &LayoutPrimitiveInfo, color: ColorF) {
981         let item = SpecificDisplayItem::Rectangle(RectangleDisplayItem { color });
982         self.push_item(item, info);
983     }
984 
push_clear_rect(&mut self, info: &LayoutPrimitiveInfo)985     pub fn push_clear_rect(&mut self, info: &LayoutPrimitiveInfo) {
986         self.push_item(SpecificDisplayItem::ClearRectangle, info);
987     }
988 
push_line( &mut self, info: &LayoutPrimitiveInfo, wavy_line_thickness: f32, orientation: LineOrientation, color: &ColorF, style: LineStyle, )989     pub fn push_line(
990         &mut self,
991         info: &LayoutPrimitiveInfo,
992         wavy_line_thickness: f32,
993         orientation: LineOrientation,
994         color: &ColorF,
995         style: LineStyle,
996     ) {
997         let item = SpecificDisplayItem::Line(LineDisplayItem {
998             wavy_line_thickness,
999             orientation,
1000             color: *color,
1001             style,
1002         });
1003 
1004         self.push_item(item, info);
1005     }
1006 
push_image( &mut self, info: &LayoutPrimitiveInfo, stretch_size: LayoutSize, tile_spacing: LayoutSize, image_rendering: ImageRendering, alpha_type: AlphaType, key: ImageKey, )1007     pub fn push_image(
1008         &mut self,
1009         info: &LayoutPrimitiveInfo,
1010         stretch_size: LayoutSize,
1011         tile_spacing: LayoutSize,
1012         image_rendering: ImageRendering,
1013         alpha_type: AlphaType,
1014         key: ImageKey,
1015     ) {
1016         let item = SpecificDisplayItem::Image(ImageDisplayItem {
1017             image_key: key,
1018             stretch_size,
1019             tile_spacing,
1020             image_rendering,
1021             alpha_type,
1022         });
1023 
1024         self.push_item(item, info);
1025     }
1026 
1027     /// Push a yuv image. All planar data in yuv image should use the same buffer type.
push_yuv_image( &mut self, info: &LayoutPrimitiveInfo, yuv_data: YuvData, color_space: YuvColorSpace, image_rendering: ImageRendering, )1028     pub fn push_yuv_image(
1029         &mut self,
1030         info: &LayoutPrimitiveInfo,
1031         yuv_data: YuvData,
1032         color_space: YuvColorSpace,
1033         image_rendering: ImageRendering,
1034     ) {
1035         let item = SpecificDisplayItem::YuvImage(YuvImageDisplayItem {
1036             yuv_data,
1037             color_space,
1038             image_rendering,
1039         });
1040         self.push_item(item, info);
1041     }
1042 
push_text( &mut self, info: &LayoutPrimitiveInfo, glyphs: &[GlyphInstance], font_key: FontInstanceKey, color: ColorF, glyph_options: Option<GlyphOptions>, )1043     pub fn push_text(
1044         &mut self,
1045         info: &LayoutPrimitiveInfo,
1046         glyphs: &[GlyphInstance],
1047         font_key: FontInstanceKey,
1048         color: ColorF,
1049         glyph_options: Option<GlyphOptions>,
1050     ) {
1051         let item = SpecificDisplayItem::Text(TextDisplayItem {
1052             color,
1053             font_key,
1054             glyph_options,
1055         });
1056 
1057         for split_glyphs in glyphs.chunks(MAX_TEXT_RUN_LENGTH) {
1058             self.push_item(item, info);
1059             self.push_iter(split_glyphs);
1060         }
1061     }
1062 
1063     // Gradients can be defined with stops outside the range of [0, 1]
1064     // when this happens the gradient needs to be normalized by adjusting
1065     // the gradient stops and gradient line into an equivalent gradient
1066     // with stops in the range [0, 1]. this is done by moving the beginning
1067     // of the gradient line to where stop[0] and the end of the gradient line
1068     // to stop[n-1]. this function adjusts the stops in place, and returns
1069     // the amount to adjust the gradient line start and stop
normalize_stops(stops: &mut Vec<GradientStop>, extend_mode: ExtendMode) -> (f32, f32)1070     fn normalize_stops(stops: &mut Vec<GradientStop>, extend_mode: ExtendMode) -> (f32, f32) {
1071         assert!(stops.len() >= 2);
1072 
1073         let first = *stops.first().unwrap();
1074         let last = *stops.last().unwrap();
1075 
1076         assert!(first.offset <= last.offset);
1077 
1078         let stops_origin = first.offset;
1079         let stops_delta = last.offset - first.offset;
1080 
1081         if stops_delta > 0.000001 {
1082             for stop in stops {
1083                 stop.offset = (stop.offset - stops_origin) / stops_delta;
1084             }
1085 
1086             (first.offset, last.offset)
1087         } else {
1088             // We have a degenerate gradient and can't accurately transform the stops
1089             // what happens here depends on the repeat behavior, but in any case
1090             // we reconstruct the gradient stops to something simpler and equivalent
1091             stops.clear();
1092 
1093             match extend_mode {
1094                 ExtendMode::Clamp => {
1095                     // This gradient is two colors split at the offset of the stops,
1096                     // so create a gradient with two colors split at 0.5 and adjust
1097                     // the gradient line so 0.5 is at the offset of the stops
1098                     stops.push(GradientStop {
1099                         color: first.color,
1100                         offset: 0.0,
1101                     });
1102                     stops.push(GradientStop {
1103                         color: first.color,
1104                         offset: 0.5,
1105                     });
1106                     stops.push(GradientStop {
1107                         color: last.color,
1108                         offset: 0.5,
1109                     });
1110                     stops.push(GradientStop {
1111                         color: last.color,
1112                         offset: 1.0,
1113                     });
1114 
1115                     let offset = last.offset;
1116 
1117                     (offset - 0.5, offset + 0.5)
1118                 }
1119                 ExtendMode::Repeat => {
1120                     // A repeating gradient with stops that are all in the same
1121                     // position should just display the last color. I believe the
1122                     // spec says that it should be the average color of the gradient,
1123                     // but this matches what Gecko and Blink does
1124                     stops.push(GradientStop {
1125                         color: last.color,
1126                         offset: 0.0,
1127                     });
1128                     stops.push(GradientStop {
1129                         color: last.color,
1130                         offset: 1.0,
1131                     });
1132 
1133                     (0.0, 1.0)
1134                 }
1135             }
1136         }
1137     }
1138 
1139     // NOTE: gradients must be pushed in the order they're created
1140     // because create_gradient stores the stops in anticipation
create_gradient( &mut self, start_point: LayoutPoint, end_point: LayoutPoint, mut stops: Vec<GradientStop>, extend_mode: ExtendMode, ) -> Gradient1141     pub fn create_gradient(
1142         &mut self,
1143         start_point: LayoutPoint,
1144         end_point: LayoutPoint,
1145         mut stops: Vec<GradientStop>,
1146         extend_mode: ExtendMode,
1147     ) -> Gradient {
1148         let (start_offset, end_offset) =
1149             DisplayListBuilder::normalize_stops(&mut stops, extend_mode);
1150 
1151         let start_to_end = end_point - start_point;
1152 
1153         self.push_stops(&stops);
1154 
1155         Gradient {
1156             start_point: start_point + start_to_end * start_offset,
1157             end_point: start_point + start_to_end * end_offset,
1158             extend_mode,
1159         }
1160     }
1161 
1162     // NOTE: gradients must be pushed in the order they're created
1163     // because create_gradient stores the stops in anticipation
create_radial_gradient( &mut self, center: LayoutPoint, radius: LayoutSize, mut stops: Vec<GradientStop>, extend_mode: ExtendMode, ) -> RadialGradient1164     pub fn create_radial_gradient(
1165         &mut self,
1166         center: LayoutPoint,
1167         radius: LayoutSize,
1168         mut stops: Vec<GradientStop>,
1169         extend_mode: ExtendMode,
1170     ) -> RadialGradient {
1171         if radius.width <= 0.0 || radius.height <= 0.0 {
1172             // The shader cannot handle a non positive radius. So
1173             // reuse the stops vector and construct an equivalent
1174             // gradient.
1175             let last_color = stops.last().unwrap().color;
1176 
1177             let stops = [
1178                 GradientStop {
1179                     offset: 0.0,
1180                     color: last_color,
1181                 },
1182                 GradientStop {
1183                     offset: 1.0,
1184                     color: last_color,
1185                 },
1186             ];
1187 
1188             self.push_stops(&stops);
1189 
1190             return RadialGradient {
1191                 start_center: center,
1192                 start_radius: 0.0,
1193                 end_center: center,
1194                 end_radius: 1.0,
1195                 ratio_xy: 1.0,
1196                 extend_mode,
1197             };
1198         }
1199 
1200         let (start_offset, end_offset) =
1201             DisplayListBuilder::normalize_stops(&mut stops, extend_mode);
1202 
1203         self.push_stops(&stops);
1204 
1205         RadialGradient {
1206             start_center: center,
1207             start_radius: radius.width * start_offset,
1208             end_center: center,
1209             end_radius: radius.width * end_offset,
1210             ratio_xy: radius.width / radius.height,
1211             extend_mode,
1212         }
1213     }
1214 
1215     // NOTE: gradients must be pushed in the order they're created
1216     // because create_gradient stores the stops in anticipation
create_complex_radial_gradient( &mut self, start_center: LayoutPoint, start_radius: f32, end_center: LayoutPoint, end_radius: f32, ratio_xy: f32, stops: Vec<GradientStop>, extend_mode: ExtendMode, ) -> RadialGradient1217     pub fn create_complex_radial_gradient(
1218         &mut self,
1219         start_center: LayoutPoint,
1220         start_radius: f32,
1221         end_center: LayoutPoint,
1222         end_radius: f32,
1223         ratio_xy: f32,
1224         stops: Vec<GradientStop>,
1225         extend_mode: ExtendMode,
1226     ) -> RadialGradient {
1227         self.push_stops(&stops);
1228 
1229         RadialGradient {
1230             start_center,
1231             start_radius,
1232             end_center,
1233             end_radius,
1234             ratio_xy,
1235             extend_mode,
1236         }
1237     }
1238 
push_border( &mut self, info: &LayoutPrimitiveInfo, widths: BorderWidths, details: BorderDetails, )1239     pub fn push_border(
1240         &mut self,
1241         info: &LayoutPrimitiveInfo,
1242         widths: BorderWidths,
1243         details: BorderDetails,
1244     ) {
1245         let item = SpecificDisplayItem::Border(BorderDisplayItem { details, widths });
1246 
1247         self.push_item(item, info);
1248     }
1249 
push_box_shadow( &mut self, info: &LayoutPrimitiveInfo, box_bounds: LayoutRect, offset: LayoutVector2D, color: ColorF, blur_radius: f32, spread_radius: f32, border_radius: BorderRadius, clip_mode: BoxShadowClipMode, )1250     pub fn push_box_shadow(
1251         &mut self,
1252         info: &LayoutPrimitiveInfo,
1253         box_bounds: LayoutRect,
1254         offset: LayoutVector2D,
1255         color: ColorF,
1256         blur_radius: f32,
1257         spread_radius: f32,
1258         border_radius: BorderRadius,
1259         clip_mode: BoxShadowClipMode,
1260     ) {
1261         let item = SpecificDisplayItem::BoxShadow(BoxShadowDisplayItem {
1262             box_bounds,
1263             offset,
1264             color,
1265             blur_radius,
1266             spread_radius,
1267             border_radius,
1268             clip_mode,
1269         });
1270 
1271         self.push_item(item, info);
1272     }
1273 
1274     /// Pushes a linear gradient to be displayed.
1275     ///
1276     /// The gradient itself is described in the
1277     /// `gradient` parameter. It is drawn on
1278     /// a "tile" with the dimensions from `tile_size`.
1279     /// These tiles are now repeated to the right and
1280     /// to the bottom infinitly. If `tile_spacing`
1281     /// is not zero spacers with the given dimensions
1282     /// are inserted between the tiles as seams.
1283     ///
1284     /// The origin of the tiles is given in `info.rect.origin`.
1285     /// If the gradient should only be displayed once limit
1286     /// the `info.rect.size` to a single tile.
1287     /// The gradient is only visible within the local clip.
push_gradient( &mut self, info: &LayoutPrimitiveInfo, gradient: Gradient, tile_size: LayoutSize, tile_spacing: LayoutSize, )1288     pub fn push_gradient(
1289         &mut self,
1290         info: &LayoutPrimitiveInfo,
1291         gradient: Gradient,
1292         tile_size: LayoutSize,
1293         tile_spacing: LayoutSize,
1294     ) {
1295         let item = SpecificDisplayItem::Gradient(GradientDisplayItem {
1296             gradient,
1297             tile_size,
1298             tile_spacing,
1299         });
1300 
1301         self.push_item(item, info);
1302     }
1303 
1304     /// Pushes a radial gradient to be displayed.
1305     ///
1306     /// See [`push_gradient`](#method.push_gradient) for explanation.
push_radial_gradient( &mut self, info: &LayoutPrimitiveInfo, gradient: RadialGradient, tile_size: LayoutSize, tile_spacing: LayoutSize, )1307     pub fn push_radial_gradient(
1308         &mut self,
1309         info: &LayoutPrimitiveInfo,
1310         gradient: RadialGradient,
1311         tile_size: LayoutSize,
1312         tile_spacing: LayoutSize,
1313     ) {
1314         let item = SpecificDisplayItem::RadialGradient(RadialGradientDisplayItem {
1315             gradient,
1316             tile_size,
1317             tile_spacing,
1318         });
1319 
1320         self.push_item(item, info);
1321     }
1322 
push_stacking_context( &mut self, info: &LayoutPrimitiveInfo, scroll_policy: ScrollPolicy, transform: Option<PropertyBinding<LayoutTransform>>, transform_style: TransformStyle, perspective: Option<LayoutTransform>, mix_blend_mode: MixBlendMode, filters: Vec<FilterOp>, )1323     pub fn push_stacking_context(
1324         &mut self,
1325         info: &LayoutPrimitiveInfo,
1326         scroll_policy: ScrollPolicy,
1327         transform: Option<PropertyBinding<LayoutTransform>>,
1328         transform_style: TransformStyle,
1329         perspective: Option<LayoutTransform>,
1330         mix_blend_mode: MixBlendMode,
1331         filters: Vec<FilterOp>,
1332     ) {
1333         let reference_frame_id = if transform.is_some() || perspective.is_some() {
1334             Some(self.generate_clip_id())
1335         } else {
1336             None
1337         };
1338 
1339         let item = SpecificDisplayItem::PushStackingContext(PushStackingContextDisplayItem {
1340             stacking_context: StackingContext {
1341                 scroll_policy,
1342                 transform,
1343                 transform_style,
1344                 perspective,
1345                 mix_blend_mode,
1346                 reference_frame_id,
1347             },
1348         });
1349 
1350         self.push_item(item, info);
1351         self.push_iter(&filters);
1352     }
1353 
pop_stacking_context(&mut self)1354     pub fn pop_stacking_context(&mut self) {
1355         self.push_new_empty_item(SpecificDisplayItem::PopStackingContext);
1356     }
1357 
push_stops(&mut self, stops: &[GradientStop])1358     pub fn push_stops(&mut self, stops: &[GradientStop]) {
1359         if stops.is_empty() {
1360             return;
1361         }
1362         self.push_new_empty_item(SpecificDisplayItem::SetGradientStops);
1363         self.push_iter(stops);
1364     }
1365 
generate_clip_id(&mut self) -> ClipId1366     fn generate_clip_id(&mut self) -> ClipId {
1367         self.next_clip_id += 1;
1368         ClipId::Clip(self.next_clip_id - 1, self.pipeline_id)
1369     }
1370 
generate_clip_chain_id(&mut self) -> ClipChainId1371     fn generate_clip_chain_id(&mut self) -> ClipChainId {
1372         self.next_clip_chain_id += 1;
1373         ClipChainId(self.next_clip_chain_id - 1, self.pipeline_id)
1374     }
1375 
define_scroll_frame<I>( &mut self, external_id: Option<ExternalScrollId>, content_rect: LayoutRect, clip_rect: LayoutRect, complex_clips: I, image_mask: Option<ImageMask>, scroll_sensitivity: ScrollSensitivity, ) -> ClipId where I: IntoIterator<Item = ComplexClipRegion>, I::IntoIter: ExactSizeIterator + Clone,1376     pub fn define_scroll_frame<I>(
1377         &mut self,
1378         external_id: Option<ExternalScrollId>,
1379         content_rect: LayoutRect,
1380         clip_rect: LayoutRect,
1381         complex_clips: I,
1382         image_mask: Option<ImageMask>,
1383         scroll_sensitivity: ScrollSensitivity,
1384     ) -> ClipId
1385     where
1386         I: IntoIterator<Item = ComplexClipRegion>,
1387         I::IntoIter: ExactSizeIterator + Clone,
1388     {
1389         let parent = self.clip_stack.last().unwrap().scroll_node_id;
1390         self.define_scroll_frame_with_parent(
1391             parent,
1392             external_id,
1393             content_rect,
1394             clip_rect,
1395             complex_clips,
1396             image_mask,
1397             scroll_sensitivity)
1398     }
1399 
define_scroll_frame_with_parent<I>( &mut self, parent: ClipId, external_id: Option<ExternalScrollId>, content_rect: LayoutRect, clip_rect: LayoutRect, complex_clips: I, image_mask: Option<ImageMask>, scroll_sensitivity: ScrollSensitivity, ) -> ClipId where I: IntoIterator<Item = ComplexClipRegion>, I::IntoIter: ExactSizeIterator + Clone,1400     pub fn define_scroll_frame_with_parent<I>(
1401         &mut self,
1402         parent: ClipId,
1403         external_id: Option<ExternalScrollId>,
1404         content_rect: LayoutRect,
1405         clip_rect: LayoutRect,
1406         complex_clips: I,
1407         image_mask: Option<ImageMask>,
1408         scroll_sensitivity: ScrollSensitivity,
1409     ) -> ClipId
1410     where
1411         I: IntoIterator<Item = ComplexClipRegion>,
1412         I::IntoIter: ExactSizeIterator + Clone,
1413     {
1414         let clip_id = self.generate_clip_id();
1415         let scroll_frame_id = self.generate_clip_id();
1416         let item = SpecificDisplayItem::ScrollFrame(ScrollFrameDisplayItem {
1417             clip_id,
1418             scroll_frame_id,
1419             external_id,
1420             image_mask,
1421             scroll_sensitivity,
1422         });
1423 
1424         self.push_item_with_clip_scroll_info(
1425             item,
1426             &LayoutPrimitiveInfo::with_clip_rect(content_rect, clip_rect),
1427             ClipAndScrollInfo::simple(parent),
1428         );
1429         self.push_iter(complex_clips);
1430 
1431         scroll_frame_id
1432     }
1433 
define_clip_chain<I>( &mut self, parent: Option<ClipChainId>, clips: I, ) -> ClipChainId where I: IntoIterator<Item = ClipId>, I::IntoIter: ExactSizeIterator + Clone,1434     pub fn define_clip_chain<I>(
1435         &mut self,
1436         parent: Option<ClipChainId>,
1437         clips: I,
1438     ) -> ClipChainId
1439     where
1440         I: IntoIterator<Item = ClipId>,
1441         I::IntoIter: ExactSizeIterator + Clone,
1442     {
1443         let id = self.generate_clip_chain_id();
1444         self.push_new_empty_item(SpecificDisplayItem::ClipChain(ClipChainItem { id, parent }));
1445         self.push_iter(clips);
1446         id
1447     }
1448 
define_clip<I>( &mut self, clip_rect: LayoutRect, complex_clips: I, image_mask: Option<ImageMask>, ) -> ClipId where I: IntoIterator<Item = ComplexClipRegion>, I::IntoIter: ExactSizeIterator + Clone,1449     pub fn define_clip<I>(
1450         &mut self,
1451         clip_rect: LayoutRect,
1452         complex_clips: I,
1453         image_mask: Option<ImageMask>,
1454     ) -> ClipId
1455     where
1456         I: IntoIterator<Item = ComplexClipRegion>,
1457         I::IntoIter: ExactSizeIterator + Clone,
1458     {
1459         let parent = self.clip_stack.last().unwrap().scroll_node_id;
1460         self.define_clip_with_parent(
1461             parent,
1462             clip_rect,
1463             complex_clips,
1464             image_mask
1465         )
1466     }
1467 
define_clip_with_parent<I>( &mut self, parent: ClipId, clip_rect: LayoutRect, complex_clips: I, image_mask: Option<ImageMask>, ) -> ClipId where I: IntoIterator<Item = ComplexClipRegion>, I::IntoIter: ExactSizeIterator + Clone,1468     pub fn define_clip_with_parent<I>(
1469         &mut self,
1470         parent: ClipId,
1471         clip_rect: LayoutRect,
1472         complex_clips: I,
1473         image_mask: Option<ImageMask>,
1474     ) -> ClipId
1475     where
1476         I: IntoIterator<Item = ComplexClipRegion>,
1477         I::IntoIter: ExactSizeIterator + Clone,
1478     {
1479         let id = self.generate_clip_id();
1480         let item = SpecificDisplayItem::Clip(ClipDisplayItem {
1481             id,
1482             image_mask: image_mask,
1483         });
1484 
1485         let info = LayoutPrimitiveInfo::new(clip_rect);
1486 
1487         let scrollinfo = ClipAndScrollInfo::simple(parent);
1488         self.push_item_with_clip_scroll_info(item, &info, scrollinfo);
1489         self.push_iter(complex_clips);
1490         id
1491     }
1492 
define_sticky_frame( &mut self, frame_rect: LayoutRect, margins: SideOffsets2D<Option<f32>>, vertical_offset_bounds: StickyOffsetBounds, horizontal_offset_bounds: StickyOffsetBounds, previously_applied_offset: LayoutVector2D, ) -> ClipId1493     pub fn define_sticky_frame(
1494         &mut self,
1495         frame_rect: LayoutRect,
1496         margins: SideOffsets2D<Option<f32>>,
1497         vertical_offset_bounds: StickyOffsetBounds,
1498         horizontal_offset_bounds: StickyOffsetBounds,
1499         previously_applied_offset: LayoutVector2D,
1500 
1501     ) -> ClipId {
1502         let id = self.generate_clip_id();
1503         let item = SpecificDisplayItem::StickyFrame(StickyFrameDisplayItem {
1504             id,
1505             margins,
1506             vertical_offset_bounds,
1507             horizontal_offset_bounds,
1508             previously_applied_offset,
1509         });
1510 
1511         let info = LayoutPrimitiveInfo::new(frame_rect);
1512         self.push_item(item, &info);
1513         id
1514     }
1515 
push_clip_id(&mut self, id: ClipId)1516     pub fn push_clip_id(&mut self, id: ClipId) {
1517         self.clip_stack.push(ClipAndScrollInfo::simple(id));
1518     }
1519 
push_clip_and_scroll_info(&mut self, info: ClipAndScrollInfo)1520     pub fn push_clip_and_scroll_info(&mut self, info: ClipAndScrollInfo) {
1521         self.clip_stack.push(info);
1522     }
1523 
pop_clip_id(&mut self)1524     pub fn pop_clip_id(&mut self) {
1525         self.clip_stack.pop();
1526         if let Some(save_state) = self.save_state.as_ref() {
1527             assert!(self.clip_stack.len() >= save_state.clip_stack_len,
1528                     "Cannot pop clips that were pushed before the DisplayListBuilder save.");
1529         }
1530         assert!(self.clip_stack.len() > 0);
1531     }
1532 
push_iframe(&mut self, info: &LayoutPrimitiveInfo, pipeline_id: PipelineId)1533     pub fn push_iframe(&mut self, info: &LayoutPrimitiveInfo, pipeline_id: PipelineId) {
1534         let item = SpecificDisplayItem::Iframe(IframeDisplayItem {
1535             clip_id: self.generate_clip_id(),
1536             pipeline_id,
1537         });
1538         self.push_item(item, info);
1539     }
1540 
push_shadow(&mut self, info: &LayoutPrimitiveInfo, shadow: Shadow)1541     pub fn push_shadow(&mut self, info: &LayoutPrimitiveInfo, shadow: Shadow) {
1542         self.push_item(SpecificDisplayItem::PushShadow(shadow), info);
1543     }
1544 
pop_all_shadows(&mut self)1545     pub fn pop_all_shadows(&mut self) {
1546         self.push_new_empty_item(SpecificDisplayItem::PopAllShadows);
1547     }
1548 
finalize(self) -> (PipelineId, LayoutSize, BuiltDisplayList)1549     pub fn finalize(self) -> (PipelineId, LayoutSize, BuiltDisplayList) {
1550         assert!(self.save_state.is_none(), "Finalized DisplayListBuilder with a pending save");
1551 
1552         let end_time = precise_time_ns();
1553 
1554 
1555         (
1556             self.pipeline_id,
1557             self.content_size,
1558             BuiltDisplayList {
1559                 descriptor: BuiltDisplayListDescriptor {
1560                     builder_start_time: self.builder_start_time,
1561                     builder_finish_time: end_time,
1562                     send_start_time: 0,
1563                     total_clip_ids: self.next_clip_id,
1564                 },
1565                 data: self.data,
1566             },
1567         )
1568     }
1569 }
1570