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