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