1use api::{BorderRadius, ClipMode, ImageMask, ClipId, ClipChainId};
96use api::{BoxShadowClipMode, FillRule, ImageKey, ImageRendering};
97use api::units::*;
98use crate::image_tiling::{self, Repetition};
99use crate::border::{ensure_no_corner_overlap, BorderRadiusAu};
100use crate::box_shadow::{BLUR_SAMPLE_SCALE, BoxShadowClipSource, BoxShadowCacheKey};
101use crate::spatial_tree::{SpatialTree, SpatialNodeIndex};
102use crate::ellipse::Ellipse;
103use crate::gpu_cache::GpuCache;
104use crate::gpu_types::{BoxShadowStretchMode};
105use crate::intern;
106use crate::internal_types::{FastHashMap, FastHashSet, LayoutPrimitiveInfo};
107use crate::prim_store::{VisibleMaskImageTile};
108use crate::prim_store::{PointKey, SizeKey, RectangleKey, PolygonKey};
109use crate::render_task_cache::to_cache_size;
110use crate::render_task::RenderTask;
111use crate::render_task_graph::RenderTaskGraphBuilder;
112use crate::resource_cache::{ImageRequest, ResourceCache};
113use crate::scene_builder_thread::Interners;
114use crate::space::SpaceMapper;
115use crate::util::{clamp_to_scale_factor, extract_inner_rect_safe, project_rect, MatrixHelpers, MaxRect, ScaleOffset};
116use euclid::approxeq::ApproxEq;
117use std::{iter, ops, u32, mem};
118
119#[cfg_attr(feature = "capture", derive(Serialize))]
121#[cfg_attr(feature = "replay", derive(Deserialize))]
122#[derive(MallocSizeOf)]
123pub struct ClipTreeNode {
124 pub handle: ClipDataHandle,
125 pub parent: ClipNodeId,
126
127 children: Vec<ClipNodeId>,
128
129 }
132
133#[cfg_attr(feature = "capture", derive(Serialize))]
136#[cfg_attr(feature = "replay", derive(Deserialize))]
137#[derive(MallocSizeOf)]
138pub struct ClipTreeLeaf {
139 pub node_id: ClipNodeId,
140
141 pub local_clip_rect: LayoutRect,
146}
147
148#[derive(Debug, Copy, Clone, PartialEq, MallocSizeOf, Eq, Hash)]
150#[cfg_attr(feature = "capture", derive(Serialize))]
151#[cfg_attr(feature = "replay", derive(Deserialize))]
152pub struct ClipNodeId(u32);
153
154impl ClipNodeId {
155 pub const NONE: ClipNodeId = ClipNodeId(0);
156}
157
158#[derive(Debug, Copy, Clone, PartialEq, MallocSizeOf, Eq, Hash)]
160#[cfg_attr(feature = "capture", derive(Serialize))]
161#[cfg_attr(feature = "replay", derive(Deserialize))]
162pub struct ClipLeafId(u32);
163
164#[cfg_attr(feature = "capture", derive(Serialize))]
166#[cfg_attr(feature = "replay", derive(Deserialize))]
167pub struct ClipTree {
168 nodes: Vec<ClipTreeNode>,
169 leaves: Vec<ClipTreeLeaf>,
170 clip_root_stack: Vec<ClipNodeId>,
171}
172
173impl ClipTree {
174 pub fn new() -> Self {
175 ClipTree {
176 nodes: vec![
177 ClipTreeNode {
178 handle: ClipDataHandle::INVALID,
179 children: Vec::new(),
180 parent: ClipNodeId::NONE,
181 }
182 ],
183 leaves: Vec::new(),
184 clip_root_stack: vec![
185 ClipNodeId::NONE,
186 ],
187 }
188 }
189
190 pub fn reset(&mut self) {
191 self.nodes.clear();
192 self.nodes.push(ClipTreeNode {
193 handle: ClipDataHandle::INVALID,
194 children: Vec::new(),
195 parent: ClipNodeId::NONE,
196 });
197
198 self.leaves.clear();
199
200 self.clip_root_stack.clear();
201 self.clip_root_stack.push(ClipNodeId::NONE);
202 }
203
204 fn add_impl(
207 id: ClipNodeId,
208 clips: &[ClipDataHandle],
209 nodes: &mut Vec<ClipTreeNode>,
210 ) -> ClipNodeId {
211 if clips.is_empty() {
212 return id;
213 }
214
215 let handle = clips[0];
216 let next_clips = &clips[1..];
217
218 let node_index = nodes[id.0 as usize]
219 .children
220 .iter()
221 .find(|n| nodes[n.0 as usize].handle == handle)
222 .cloned();
223
224 let node_index = match node_index {
225 Some(node_index) => node_index,
226 None => {
227 let node_index = ClipNodeId(nodes.len() as u32);
228 nodes[id.0 as usize].children.push(node_index);
229 let node = ClipTreeNode {
230 handle,
231 children: Vec::new(),
232 parent: id,
233 };
234 nodes.push(node);
235 node_index
236 }
237 };
238
239 ClipTree::add_impl(
240 node_index,
241 next_clips,
242 nodes,
243 )
244 }
245
246 pub fn add(
249 &mut self,
250 root: ClipNodeId,
251 clips: &[ClipDataHandle],
252 ) -> ClipNodeId {
253 ClipTree::add_impl(
254 root,
255 clips,
256 &mut self.nodes,
257 )
258 }
259
260 pub fn current_clip_root(&self) -> ClipNodeId {
263 self.clip_root_stack.last().cloned().unwrap()
264 }
265
266 pub fn push_clip_root_leaf(&mut self, clip_leaf_id: ClipLeafId) {
269 let leaf = &self.leaves[clip_leaf_id.0 as usize];
270 self.clip_root_stack.push(leaf.node_id);
271 }
272
273 pub fn push_clip_root_node(&mut self, clip_node_id: ClipNodeId) {
276 self.clip_root_stack.push(clip_node_id);
277 }
278
279 pub fn pop_clip_root(&mut self) {
281 self.clip_root_stack.pop().unwrap();
282 }
283
284 pub fn get_node(&self, id: ClipNodeId) -> &ClipTreeNode {
286 assert!(id != ClipNodeId::NONE);
287
288 &self.nodes[id.0 as usize]
289 }
290
291 pub fn get_parent(&self, id: ClipNodeId) -> Option<ClipNodeId> {
292 let parent = self.nodes[id.0 as usize].parent;
296 if parent == ClipNodeId::NONE {
297 return None;
298 }
299
300 return Some(parent)
301 }
302
303 pub fn get_leaf(&self, id: ClipLeafId) -> &ClipTreeLeaf {
305 &self.leaves[id.0 as usize]
306 }
307
308 #[allow(unused)]
310 pub fn print(&self) {
311 use crate::print_tree::PrintTree;
312
313 fn print_node<T: crate::print_tree::PrintTreePrinter>(
314 id: ClipNodeId,
315 nodes: &[ClipTreeNode],
316 pt: &mut T,
317 ) {
318 let node = &nodes[id.0 as usize];
319
320 pt.new_level(format!("{:?}", id));
321 pt.add_item(format!("{:?}", node.handle));
322
323 for child_id in &node.children {
324 print_node(*child_id, nodes, pt);
325 }
326
327 pt.end_level();
328 }
329
330 fn print_leaf<T: crate::print_tree::PrintTreePrinter>(
331 id: ClipLeafId,
332 leaves: &[ClipTreeLeaf],
333 pt: &mut T,
334 ) {
335 let leaf = &leaves[id.0 as usize];
336
337 pt.new_level(format!("{:?}", id));
338 pt.add_item(format!("node_id: {:?}", leaf.node_id));
339 pt.add_item(format!("local_clip_rect: {:?}", leaf.local_clip_rect));
340 pt.end_level();
341 }
342
343 let mut pt = PrintTree::new("clip tree");
344 print_node(ClipNodeId::NONE, &self.nodes, &mut pt);
345
346 for i in 0 .. self.leaves.len() {
347 print_leaf(ClipLeafId(i as u32), &self.leaves, &mut pt);
348 }
349 }
350
351 pub fn find_lowest_common_ancestor(
354 &self,
355 mut node1: ClipNodeId,
356 mut node2: ClipNodeId,
357 ) -> ClipNodeId {
358 fn get_node_depth(
360 id: ClipNodeId,
361 nodes: &[ClipTreeNode],
362 ) -> usize {
363 let mut depth = 0;
364 let mut current = id;
365
366 while current != ClipNodeId::NONE {
367 let node = &nodes[current.0 as usize];
368 depth += 1;
369 current = node.parent;
370 }
371
372 depth
373 }
374
375 let mut depth1 = get_node_depth(node1, &self.nodes);
376 let mut depth2 = get_node_depth(node2, &self.nodes);
377
378 while depth1 > depth2 {
379 node1 = self.nodes[node1.0 as usize].parent;
380 depth1 -= 1;
381 }
382
383 while depth2 > depth1 {
384 node2 = self.nodes[node2.0 as usize].parent;
385 depth2 -= 1;
386 }
387
388 while node1 != node2 {
389 node1 = self.nodes[node1.0 as usize].parent;
390 node2 = self.nodes[node2.0 as usize].parent;
391 }
392
393 node1
394 }
395}
396
397#[cfg_attr(feature = "capture", derive(Serialize))]
401#[cfg_attr(feature = "replay", derive(Deserialize))]
402pub struct ClipChain {
403 parent: Option<usize>,
404 clips: Vec<ClipDataHandle>,
405}
406
407#[cfg_attr(feature = "capture", derive(Serialize))]
408#[cfg_attr(feature = "replay", derive(Deserialize))]
409pub struct ClipStackEntry {
410 last_clip_chain_cache: Option<(ClipChainId, ClipNodeId)>,
412
413 seen_clips: FastHashSet<ClipDataHandle>,
415
416 clip_node_id: ClipNodeId,
418}
419
420#[cfg_attr(feature = "capture", derive(Serialize))]
422#[cfg_attr(feature = "replay", derive(Deserialize))]
423pub struct ClipTreeBuilder {
424 clip_map: FastHashMap<ClipId, ClipDataHandle>,
426
427 clip_chains: Vec<ClipChain>,
429 clip_chain_map: FastHashMap<ClipChainId, usize>,
430
431 clip_stack: Vec<ClipStackEntry>,
433
434 tree: ClipTree,
436
437 clip_handles_buffer: Vec<ClipDataHandle>,
439}
440
441impl ClipTreeBuilder {
442 pub fn new() -> Self {
443 ClipTreeBuilder {
444 clip_map: FastHashMap::default(),
445 clip_chain_map: FastHashMap::default(),
446 clip_chains: Vec::new(),
447 clip_stack: vec![
448 ClipStackEntry {
449 clip_node_id: ClipNodeId::NONE,
450 last_clip_chain_cache: None,
451 seen_clips: FastHashSet::default(),
452 },
453 ],
454 tree: ClipTree::new(),
455 clip_handles_buffer: Vec::new(),
456 }
457 }
458
459 pub fn begin(&mut self) {
460 self.clip_map.clear();
461 self.clip_chain_map.clear();
462 self.clip_chains.clear();
463 self.clip_stack.clear();
464 self.clip_stack.push(ClipStackEntry {
465 clip_node_id: ClipNodeId::NONE,
466 last_clip_chain_cache: None,
467 seen_clips: FastHashSet::default(),
468 });
469 self.tree.reset();
470 self.clip_handles_buffer.clear();
471 }
472
473 pub fn recycle_tree(&mut self, tree: ClipTree) {
474 self.tree = tree;
475 }
476
477 pub fn define_rect_clip(
479 &mut self,
480 id: ClipId,
481 handle: ClipDataHandle,
482 ) {
483 self.clip_map.insert(id, handle);
484 }
485
486 pub fn define_rounded_rect_clip(
488 &mut self,
489 id: ClipId,
490 handle: ClipDataHandle,
491 ) {
492 self.clip_map.insert(id, handle);
493 }
494
495 pub fn define_image_mask_clip(
497 &mut self,
498 id: ClipId,
499 handle: ClipDataHandle,
500 ) {
501 self.clip_map.insert(id, handle);
502 }
503
504 pub fn define_clip_chain<I: Iterator<Item = ClipId>>(
506 &mut self,
507 id: ClipChainId,
508 parent: Option<ClipChainId>,
509 clips: I,
510 ) {
511 let parent = parent.map(|ref id| self.clip_chain_map[id]);
512 let index = self.clip_chains.len();
513 let clips = clips.map(|clip_id| {
514 self.clip_map[&clip_id]
515 }).collect();
516 self.clip_chains.push(ClipChain {
517 parent,
518 clips,
519 });
520 self.clip_chain_map.insert(id, index);
521 }
522
523 pub fn push_clip_chain(
525 &mut self,
526 clip_chain_id: Option<ClipChainId>,
527 reset_seen: bool,
528 ignore_ancestor_clips: bool,
529 ) {
530 let (mut clip_node_id, mut seen_clips) = {
531 let prev = self.clip_stack.last().unwrap();
532 let clip_node_id = if ignore_ancestor_clips {
533 ClipNodeId::NONE
534 } else {
535 prev.clip_node_id
536 };
537 (clip_node_id, prev.seen_clips.clone())
538 };
539
540 if let Some(clip_chain_id) = clip_chain_id {
541 if clip_chain_id != ClipChainId::INVALID {
542 self.clip_handles_buffer.clear();
543
544 let clip_chain_index = self.clip_chain_map[&clip_chain_id];
545 ClipTreeBuilder::add_clips(
546 clip_chain_index,
547 &mut seen_clips,
548 &mut self.clip_handles_buffer,
549 &self.clip_chains,
550 );
551
552 clip_node_id = self.tree.add(
553 clip_node_id,
554 &self.clip_handles_buffer,
555 );
556 }
557 }
558
559 if reset_seen {
560 seen_clips.clear();
561 }
562
563 self.clip_stack.push(ClipStackEntry {
564 last_clip_chain_cache: None,
565 clip_node_id,
566 seen_clips,
567 });
568 }
569
570 pub fn push_clip_id(
572 &mut self,
573 clip_id: ClipId,
574 ) {
575 let (clip_node_id, mut seen_clips) = {
576 let prev = self.clip_stack.last().unwrap();
577 (prev.clip_node_id, prev.seen_clips.clone())
578 };
579
580 self.clip_handles_buffer.clear();
581 let clip_index = self.clip_map[&clip_id];
582
583 if seen_clips.insert(clip_index) {
584 self.clip_handles_buffer.push(clip_index);
585 }
586
587 let clip_node_id = self.tree.add(
588 clip_node_id,
589 &self.clip_handles_buffer,
590 );
591
592 self.clip_stack.push(ClipStackEntry {
593 last_clip_chain_cache: None,
594 seen_clips,
595 clip_node_id,
596 });
597 }
598
599 pub fn pop_clip(&mut self) {
601 self.clip_stack.pop().unwrap();
602 }
603
604 fn add_clips(
606 clip_chain_index: usize,
607 seen_clips: &mut FastHashSet<ClipDataHandle>,
608 output: &mut Vec<ClipDataHandle>,
609 clip_chains: &[ClipChain],
610 ) {
611 let clip_chain = &clip_chains[clip_chain_index];
619
620 if let Some(parent) = clip_chain.parent {
621 ClipTreeBuilder::add_clips(
622 parent,
623 seen_clips,
624 output,
625 clip_chains,
626 );
627 }
628
629 for clip_index in clip_chain.clips.iter().rev() {
630 if seen_clips.insert(*clip_index) {
631 output.push(*clip_index);
632 }
633 }
634 }
635
636 pub fn build_clip_set(
638 &mut self,
639 clip_chain_id: ClipChainId,
640 ) -> ClipNodeId {
641 let clip_stack = self.clip_stack.last_mut().unwrap();
642
643 if clip_chain_id == ClipChainId::INVALID {
644 clip_stack.clip_node_id
645 } else {
646 if let Some((cached_clip_chain, cached_clip_node)) = clip_stack.last_clip_chain_cache {
647 if cached_clip_chain == clip_chain_id {
648 return cached_clip_node;
649 }
650 }
651
652 let clip_chain_index = self.clip_chain_map[&clip_chain_id];
653
654 self.clip_handles_buffer.clear();
655
656 ClipTreeBuilder::add_clips(
657 clip_chain_index,
658 &mut clip_stack.seen_clips,
659 &mut self.clip_handles_buffer,
660 &self.clip_chains,
661 );
662
663 for handle in &self.clip_handles_buffer {
669 clip_stack.seen_clips.remove(handle);
670 }
671
672 let clip_node_id = self.tree.add(
673 clip_stack.clip_node_id,
674 &self.clip_handles_buffer,
675 );
676
677 clip_stack.last_clip_chain_cache = Some((clip_chain_id, clip_node_id));
678
679 clip_node_id
680 }
681 }
682
683 fn has_complex_clips_impl(
685 &self,
686 clip_chain_index: usize,
687 interners: &Interners,
688 ) -> bool {
689 let clip_chain = &self.clip_chains[clip_chain_index];
690
691 for clip_handle in &clip_chain.clips {
692 let clip_info = &interners.clip[*clip_handle];
693
694 if let ClipNodeKind::Complex = clip_info.key.kind.node_kind() {
695 return true;
696 }
697 }
698
699 match clip_chain.parent {
700 Some(parent) => self.has_complex_clips_impl(parent, interners),
701 None => false,
702 }
703 }
704
705 pub fn clip_chain_has_complex_clips(
707 &self,
708 clip_chain_id: ClipChainId,
709 interners: &Interners,
710 ) -> bool {
711 let clip_chain_index = self.clip_chain_map[&clip_chain_id];
712 self.has_complex_clips_impl(clip_chain_index, interners)
713 }
714
715 pub fn clip_node_has_complex_clips(
717 &self,
718 clip_node_id: ClipNodeId,
719 interners: &Interners,
720 ) -> bool {
721 let mut current = clip_node_id;
722
723 while current != ClipNodeId::NONE {
724 let node = &self.tree.nodes[current.0 as usize];
725 let clip_info = &interners.clip[node.handle];
726
727 if let ClipNodeKind::Complex = clip_info.key.kind.node_kind() {
728 return true;
729 }
730
731 current = node.parent;
732 }
733
734 false
735 }
736
737 pub fn get_parent(&self, id: ClipNodeId) -> Option<ClipNodeId> {
738 self.tree.get_parent(id)
739 }
740
741 pub fn finalize(&mut self) -> ClipTree {
743 std::mem::replace(&mut self.tree, ClipTree {
747 nodes: Vec::new(),
748 leaves: Vec::new(),
749 clip_root_stack: Vec::new(),
750 })
751 }
752
753 pub fn get_node(&self, id: ClipNodeId) -> &ClipTreeNode {
755 assert!(id != ClipNodeId::NONE);
756
757 &self.tree.nodes[id.0 as usize]
758 }
759
760 pub fn get_leaf(&self, id: ClipLeafId) -> &ClipTreeLeaf {
762 &self.tree.leaves[id.0 as usize]
763 }
764
765 pub fn build_for_tile_cache(
767 &mut self,
768 clip_node_id: ClipNodeId,
769 extra_clips: &[ClipId],
770 ) -> ClipLeafId {
771 self.clip_handles_buffer.clear();
772
773 for clip_id in extra_clips {
774 let handle = self.clip_map[clip_id];
775 self.clip_handles_buffer.push(handle);
776 }
777
778 let node_id = self.tree.add(
779 clip_node_id,
780 &self.clip_handles_buffer,
781 );
782
783 let clip_leaf_id = ClipLeafId(self.tree.leaves.len() as u32);
784
785 self.tree.leaves.push(ClipTreeLeaf {
786 node_id,
787 local_clip_rect: LayoutRect::max_rect(),
788 });
789
790 clip_leaf_id
791 }
792
793 pub fn build_for_picture(
795 &mut self,
796 clip_node_id: ClipNodeId,
797 ) -> ClipLeafId {
798 let node_id = self.tree.add(
799 clip_node_id,
800 &[],
801 );
802
803 let clip_leaf_id = ClipLeafId(self.tree.leaves.len() as u32);
804
805 self.tree.leaves.push(ClipTreeLeaf {
806 node_id,
807 local_clip_rect: LayoutRect::max_rect(),
808 });
809
810 clip_leaf_id
811 }
812
813 pub fn build_for_prim(
815 &mut self,
816 clip_node_id: ClipNodeId,
817 info: &LayoutPrimitiveInfo,
818 extra_clips: &[ClipItemKey],
819 interners: &mut Interners,
820 ) -> ClipLeafId {
821
822 let node_id = if extra_clips.is_empty() {
823 clip_node_id
824 } else {
825 self.clip_handles_buffer.clear();
828
829 for item in extra_clips {
830 let handle = interners.clip.intern(item, || {
833 ClipInternData {
834 key: item.clone(),
835 }
836 });
837
838 self.clip_handles_buffer.push(handle);
839 }
840
841 self.tree.add(
842 clip_node_id,
843 &self.clip_handles_buffer,
844 )
845 };
846
847 let clip_leaf_id = ClipLeafId(self.tree.leaves.len() as u32);
848
849 self.tree.leaves.push(ClipTreeLeaf {
850 node_id,
851 local_clip_rect: info.clip_rect,
852 });
853
854 clip_leaf_id
855 }
856
857 pub fn find_lowest_common_ancestor(
859 &self,
860 node1: ClipNodeId,
861 node2: ClipNodeId,
862 ) -> ClipNodeId {
863 self.tree.find_lowest_common_ancestor(node1, node2)
864 }
865}
866
867#[derive(Copy, Clone, Debug, MallocSizeOf, PartialEq, Eq, Hash)]
870#[cfg_attr(any(feature = "serde"), derive(Deserialize, Serialize))]
871pub enum ClipIntern {}
872
873pub type ClipDataStore = intern::DataStore<ClipIntern>;
874pub type ClipDataHandle = intern::Handle<ClipIntern>;
875
876#[cfg_attr(feature = "capture", derive(Serialize))]
879#[cfg_attr(feature = "replay", derive(Deserialize))]
880#[derive(Debug, Copy, Clone, MallocSizeOf)]
881pub enum ClipNodeKind {
882 Rectangle,
884 Complex,
886}
887
888#[derive(Debug)]
890enum ClipResult {
891 Accept,
893 Reject,
895 Partial,
898}
899
900#[derive(Debug)]
905#[cfg_attr(feature = "capture", derive(Serialize))]
906#[cfg_attr(feature = "replay", derive(Deserialize))]
907#[derive(MallocSizeOf)]
908pub struct ClipNode {
909 pub item: ClipItem,
910}
911
912impl From<ClipItemKey> for ClipNode {
915 fn from(item: ClipItemKey) -> Self {
916 let kind = match item.kind {
917 ClipItemKeyKind::Rectangle(rect, mode) => {
918 ClipItemKind::Rectangle { rect: rect.into(), mode }
919 }
920 ClipItemKeyKind::RoundedRectangle(rect, radius, mode) => {
921 ClipItemKind::RoundedRectangle {
922 rect: rect.into(),
923 radius: radius.into(),
924 mode,
925 }
926 }
927 ClipItemKeyKind::ImageMask(rect, image, polygon_handle) => {
928 ClipItemKind::Image {
929 image,
930 rect: rect.into(),
931 polygon_handle,
932 }
933 }
934 ClipItemKeyKind::BoxShadow(shadow_rect_fract_offset, shadow_rect_size, shadow_radius, prim_shadow_rect, blur_radius, clip_mode) => {
935 ClipItemKind::new_box_shadow(
936 shadow_rect_fract_offset.into(),
937 shadow_rect_size.into(),
938 shadow_radius.into(),
939 prim_shadow_rect.into(),
940 blur_radius.to_f32_px(),
941 clip_mode,
942 )
943 }
944 };
945
946 ClipNode {
947 item: ClipItem {
948 kind,
949 spatial_node_index: item.spatial_node_index,
950 },
951 }
952 }
953}
954
955#[cfg_attr(feature = "capture", derive(Serialize))]
957#[cfg_attr(feature = "replay", derive(Deserialize))]
958#[derive(Copy, PartialEq, Eq, Clone, PartialOrd, Ord, Hash, MallocSizeOf)]
959pub struct ClipNodeFlags(u8);
960
961bitflags! {
962 impl ClipNodeFlags : u8 {
963 const SAME_SPATIAL_NODE = 0x1;
964 const SAME_COORD_SYSTEM = 0x2;
965 const USE_FAST_PATH = 0x4;
966 }
967}
968
969impl core::fmt::Debug for ClipNodeFlags {
970 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
971 if self.is_empty() {
972 write!(f, "{:#x}", Self::empty().bits())
973 } else {
974 bitflags::parser::to_writer(self, f)
975 }
976 }
977}
978
979#[derive(Debug, Clone, MallocSizeOf)]
986#[cfg_attr(feature = "capture", derive(Serialize))]
987#[cfg_attr(feature = "replay", derive(Deserialize))]
988pub struct ClipNodeInstance {
989 pub handle: ClipDataHandle,
990 pub flags: ClipNodeFlags,
991 pub visible_tiles: Option<ops::Range<usize>>,
992}
993
994impl ClipNodeInstance {
995 pub fn has_visible_tiles(&self) -> bool {
996 self.visible_tiles.is_some()
997 }
998}
999
1000#[derive(Debug, Copy, Clone)]
1003#[cfg_attr(feature = "capture", derive(Serialize))]
1004#[cfg_attr(feature = "replay", derive(Deserialize))]
1005pub struct ClipNodeRange {
1006 pub first: u32,
1007 pub count: u32,
1008}
1009
1010impl ClipNodeRange {
1011 pub fn to_range(&self) -> ops::Range<usize> {
1012 let start = self.first as usize;
1013 let end = start + self.count as usize;
1014
1015 ops::Range {
1016 start,
1017 end,
1018 }
1019 }
1020}
1021
1022#[derive(Debug, MallocSizeOf)]
1029#[cfg_attr(feature = "capture", derive(Serialize))]
1030pub enum ClipSpaceConversion {
1031 Local,
1032 ScaleOffset(ScaleOffset),
1033 Transform(LayoutToVisTransform),
1034}
1035
1036impl ClipSpaceConversion {
1037 pub fn new(
1039 prim_spatial_node_index: SpatialNodeIndex,
1040 clip_spatial_node_index: SpatialNodeIndex,
1041 visibility_spatial_node_index: SpatialNodeIndex,
1042 spatial_tree: &SpatialTree,
1043 ) -> Self {
1044 let clip_spatial_node = spatial_tree.get_spatial_node(clip_spatial_node_index);
1048 let prim_spatial_node = spatial_tree.get_spatial_node(prim_spatial_node_index);
1049
1050 if prim_spatial_node_index == clip_spatial_node_index {
1051 ClipSpaceConversion::Local
1052 } else if prim_spatial_node.coordinate_system_id == clip_spatial_node.coordinate_system_id {
1053 let scale_offset = clip_spatial_node.content_transform
1054 .then(&prim_spatial_node.content_transform.inverse());
1055 ClipSpaceConversion::ScaleOffset(scale_offset)
1056 } else {
1057 ClipSpaceConversion::Transform(
1058 spatial_tree.get_relative_transform(
1059 clip_spatial_node_index,
1060 visibility_spatial_node_index,
1061 ).into_transform().cast_unit()
1062 )
1063 }
1064 }
1065
1066 fn to_flags(&self) -> ClipNodeFlags {
1067 match *self {
1068 ClipSpaceConversion::Local => {
1069 ClipNodeFlags::SAME_SPATIAL_NODE | ClipNodeFlags::SAME_COORD_SYSTEM
1070 }
1071 ClipSpaceConversion::ScaleOffset(..) => {
1072 ClipNodeFlags::SAME_COORD_SYSTEM
1073 }
1074 ClipSpaceConversion::Transform(..) => {
1075 ClipNodeFlags::empty()
1076 }
1077 }
1078 }
1079}
1080
1081#[derive(MallocSizeOf)]
1084#[cfg_attr(feature = "capture", derive(Serialize))]
1085struct ClipNodeInfo {
1086 conversion: ClipSpaceConversion,
1087 handle: ClipDataHandle,
1088}
1089
1090impl ClipNodeInfo {
1091 fn create_instance(
1092 &self,
1093 node: &ClipNode,
1094 clipped_rect: &LayoutRect,
1095 gpu_cache: &mut GpuCache,
1096 resource_cache: &mut ResourceCache,
1097 mask_tiles: &mut Vec<VisibleMaskImageTile>,
1098 spatial_tree: &SpatialTree,
1099 rg_builder: &mut RenderTaskGraphBuilder,
1100 request_resources: bool,
1101 ) -> Option<ClipNodeInstance> {
1102 let mut flags = self.conversion.to_flags();
1105
1106 let is_raster_2d =
1110 flags.contains(ClipNodeFlags::SAME_COORD_SYSTEM) ||
1111 spatial_tree
1112 .get_world_viewport_transform(node.item.spatial_node_index)
1113 .is_2d_axis_aligned();
1114 if is_raster_2d && node.item.kind.supports_fast_path_rendering() {
1115 flags |= ClipNodeFlags::USE_FAST_PATH;
1116 }
1117
1118 let mut visible_tiles = None;
1119
1120 if let ClipItemKind::Image { rect, image, .. } = node.item.kind {
1121 let request = ImageRequest {
1122 key: image,
1123 rendering: ImageRendering::Auto,
1124 tile: None,
1125 };
1126
1127 if let Some(props) = resource_cache.get_image_properties(image) {
1128 if let Some(tile_size) = props.tiling {
1129 let tile_range_start = mask_tiles.len();
1130
1131 let visible_rect =
1136 clipped_rect.intersection(&rect).unwrap_or(*clipped_rect);
1137
1138 let repetitions = image_tiling::repetitions(
1139 &rect,
1140 &visible_rect,
1141 rect.size(),
1142 );
1143
1144 for Repetition { origin, .. } in repetitions {
1145 let layout_image_rect = LayoutRect::from_origin_and_size(
1146 origin,
1147 rect.size(),
1148 );
1149 let tiles = image_tiling::tiles(
1150 &layout_image_rect,
1151 &visible_rect,
1152 &props.visible_rect,
1153 tile_size as i32,
1154 );
1155 for tile in tiles {
1156 let req = request.with_tile(tile.offset);
1157
1158 if request_resources {
1159 resource_cache.request_image(
1160 req,
1161 gpu_cache,
1162 );
1163 }
1164
1165 let task_id = rg_builder.add().init(
1166 RenderTask::new_image(props.descriptor.size, req, false)
1167 );
1168
1169 mask_tiles.push(VisibleMaskImageTile {
1170 tile_offset: tile.offset,
1171 tile_rect: tile.rect,
1172 task_id,
1173 });
1174 }
1175 }
1176 visible_tiles = Some(tile_range_start..mask_tiles.len());
1177 } else {
1178 if request_resources {
1179 resource_cache.request_image(request, gpu_cache);
1180 }
1181
1182 let tile_range_start = mask_tiles.len();
1183
1184 let task_id = rg_builder.add().init(
1185 RenderTask::new_image(props.descriptor.size, request, false)
1186 );
1187
1188 mask_tiles.push(VisibleMaskImageTile {
1189 tile_rect: rect,
1190 tile_offset: TileOffset::zero(),
1191 task_id,
1192 });
1193
1194 visible_tiles = Some(tile_range_start .. mask_tiles.len());
1195 }
1196 } else {
1197 warn!("Clip mask with missing image key {:?}", request.key);
1200 return None;
1201 }
1202 }
1203
1204 Some(ClipNodeInstance {
1205 handle: self.handle,
1206 flags,
1207 visible_tiles,
1208 })
1209 }
1210}
1211
1212impl ClipNode {
1213 pub fn update(
1214 &mut self,
1215 device_pixel_scale: DevicePixelScale,
1216 ) {
1217 match self.item.kind {
1218 ClipItemKind::Image { .. } |
1219 ClipItemKind::Rectangle { .. } |
1220 ClipItemKind::RoundedRectangle { .. } => {}
1221
1222 ClipItemKind::BoxShadow { ref mut source } => {
1223 let blur_radius_dp = source.blur_radius * 0.5;
1227
1228 let mut content_scale = LayoutToWorldScale::new(1.0) * device_pixel_scale;
1230 content_scale.0 = clamp_to_scale_factor(content_scale.0, false);
1231
1232 let cache_size = to_cache_size(source.shadow_rect_alloc_size, &mut content_scale);
1234
1235 let bs_cache_key = BoxShadowCacheKey {
1236 blur_radius_dp: (blur_radius_dp * content_scale.0).round() as i32,
1237 clip_mode: source.clip_mode,
1238 original_alloc_size: (source.original_alloc_size * content_scale).round().to_i32(),
1239 br_top_left: (source.shadow_radius.top_left * content_scale).round().to_i32(),
1240 br_top_right: (source.shadow_radius.top_right * content_scale).round().to_i32(),
1241 br_bottom_right: (source.shadow_radius.bottom_right * content_scale).round().to_i32(),
1242 br_bottom_left: (source.shadow_radius.bottom_left * content_scale).round().to_i32(),
1243 device_pixel_scale: Au::from_f32_px(content_scale.0),
1244 };
1245
1246 source.cache_key = Some((cache_size, bs_cache_key));
1247 }
1248 }
1249 }
1250}
1251
1252#[derive(Default)]
1253pub struct ClipStoreScratchBuffer {
1254 clip_node_instances: Vec<ClipNodeInstance>,
1255 mask_tiles: Vec<VisibleMaskImageTile>,
1256}
1257
1258#[derive(MallocSizeOf)]
1260#[cfg_attr(feature = "capture", derive(Serialize))]
1261pub struct ClipStore {
1262 pub clip_node_instances: Vec<ClipNodeInstance>,
1263 mask_tiles: Vec<VisibleMaskImageTile>,
1264
1265 active_clip_node_info: Vec<ClipNodeInfo>,
1266 active_local_clip_rect: Option<LayoutRect>,
1267 active_pic_coverage_rect: PictureRect,
1268}
1269
1270#[derive(Debug)]
1273#[cfg_attr(feature = "capture", derive(Serialize))]
1274pub struct ClipChainInstance {
1275 pub clips_range: ClipNodeRange,
1276 pub local_clip_rect: LayoutRect,
1279 pub has_non_local_clips: bool,
1280 pub needs_mask: bool,
1283 pub pic_coverage_rect: PictureRect,
1286 pub pic_spatial_node_index: SpatialNodeIndex,
1288}
1289
1290impl ClipChainInstance {
1291 pub fn empty() -> Self {
1292 ClipChainInstance {
1293 clips_range: ClipNodeRange {
1294 first: 0,
1295 count: 0,
1296 },
1297 local_clip_rect: LayoutRect::zero(),
1298 has_non_local_clips: false,
1299 needs_mask: false,
1300 pic_coverage_rect: PictureRect::zero(),
1301 pic_spatial_node_index: SpatialNodeIndex::INVALID,
1302 }
1303 }
1304}
1305
1306impl ClipStore {
1307 pub fn new() -> Self {
1308 ClipStore {
1309 clip_node_instances: Vec::new(),
1310 mask_tiles: Vec::new(),
1311 active_clip_node_info: Vec::new(),
1312 active_local_clip_rect: None,
1313 active_pic_coverage_rect: PictureRect::max_rect(),
1314 }
1315 }
1316
1317 pub fn reset(&mut self) {
1318 self.clip_node_instances.clear();
1319 self.mask_tiles.clear();
1320 self.active_clip_node_info.clear();
1321 self.active_local_clip_rect = None;
1322 self.active_pic_coverage_rect = PictureRect::max_rect();
1323 }
1324
1325 pub fn get_instance_from_range(
1326 &self,
1327 node_range: &ClipNodeRange,
1328 index: u32,
1329 ) -> &ClipNodeInstance {
1330 &self.clip_node_instances[(node_range.first + index) as usize]
1331 }
1332
1333 pub fn set_active_clips(
1335 &mut self,
1336 prim_spatial_node_index: SpatialNodeIndex,
1337 pic_spatial_node_index: SpatialNodeIndex,
1338 visibility_spatial_node_index: SpatialNodeIndex,
1339 clip_leaf_id: ClipLeafId,
1340 spatial_tree: &SpatialTree,
1341 clip_data_store: &ClipDataStore,
1342 clip_tree: &ClipTree,
1343 ) {
1344 self.active_clip_node_info.clear();
1345 self.active_local_clip_rect = None;
1346 self.active_pic_coverage_rect = PictureRect::max_rect();
1347
1348 let clip_root = clip_tree.current_clip_root();
1349 let clip_leaf = clip_tree.get_leaf(clip_leaf_id);
1350
1351 let mut local_clip_rect = clip_leaf.local_clip_rect;
1352 let mut current = clip_leaf.node_id;
1353
1354 while current != clip_root && current != ClipNodeId::NONE {
1355 let node = clip_tree.get_node(current);
1356
1357 if !add_clip_node_to_current_chain(
1358 node.handle,
1359 prim_spatial_node_index,
1360 pic_spatial_node_index,
1361 visibility_spatial_node_index,
1362 &mut local_clip_rect,
1363 &mut self.active_clip_node_info,
1364 &mut self.active_pic_coverage_rect,
1365 clip_data_store,
1366 spatial_tree,
1367 ) {
1368 return;
1369 }
1370
1371 current = node.parent;
1372 }
1373
1374 self.active_local_clip_rect = Some(local_clip_rect);
1375 }
1376
1377 pub fn set_active_clips_from_clip_chain(
1379 &mut self,
1380 prim_clip_chain: &ClipChainInstance,
1381 prim_spatial_node_index: SpatialNodeIndex,
1382 visibility_spatial_node_index: SpatialNodeIndex,
1383 spatial_tree: &SpatialTree,
1384 clip_data_store: &ClipDataStore,
1385 ) {
1386 self.active_clip_node_info.clear();
1391 self.active_local_clip_rect = Some(prim_clip_chain.local_clip_rect);
1392 self.active_pic_coverage_rect = prim_clip_chain.pic_coverage_rect;
1393
1394 let clip_instances = &self
1395 .clip_node_instances[prim_clip_chain.clips_range.to_range()];
1396 for clip_instance in clip_instances {
1397 let clip = &clip_data_store[clip_instance.handle];
1398 let conversion = ClipSpaceConversion::new(
1399 prim_spatial_node_index,
1400 clip.item.spatial_node_index,
1401 visibility_spatial_node_index,
1402 spatial_tree,
1403 );
1404 self.active_clip_node_info.push(ClipNodeInfo {
1405 handle: clip_instance.handle,
1406 conversion,
1407 });
1408 }
1409 }
1410
1411 pub fn get_inner_rect_for_clip_chain(
1416 &self,
1417 clip_chain: &ClipChainInstance,
1418 clip_data_store: &ClipDataStore,
1419 spatial_tree: &SpatialTree,
1420 ) -> Option<PictureRect> {
1421 let mut inner_rect = clip_chain.pic_coverage_rect;
1422 let clip_instances = &self
1423 .clip_node_instances[clip_chain.clips_range.to_range()];
1424
1425 for clip_instance in clip_instances {
1426 if !clip_instance.flags.contains(ClipNodeFlags::SAME_COORD_SYSTEM) {
1428 return None;
1429 }
1430
1431 let clip_node = &clip_data_store[clip_instance.handle];
1432
1433 match clip_node.item.kind {
1434 ClipItemKind::Rectangle { mode: ClipMode::ClipOut, .. } |
1437 ClipItemKind::Image { .. } |
1438 ClipItemKind::BoxShadow { .. } |
1439 ClipItemKind::RoundedRectangle { mode: ClipMode::ClipOut, .. } => {
1440 return None;
1441 }
1442 ClipItemKind::Rectangle { mode: ClipMode::Clip, .. } => {}
1445 ClipItemKind::RoundedRectangle { mode: ClipMode::Clip, rect, radius } => {
1446 let local_inner_rect = match extract_inner_rect_safe(&rect, &radius) {
1448 Some(rect) => rect,
1449 None => return None,
1450 };
1451
1452 let mapper = SpaceMapper::new_with_target(
1454 clip_chain.pic_spatial_node_index,
1455 clip_node.item.spatial_node_index,
1456 PictureRect::max_rect(),
1457 spatial_tree,
1458 );
1459
1460 if let Some(pic_inner_rect) = mapper.map(&local_inner_rect) {
1462 inner_rect = inner_rect.intersection(&pic_inner_rect).unwrap_or(PictureRect::zero());
1463 }
1464 }
1465 }
1466 }
1467
1468 Some(inner_rect)
1469 }
1470
1471 pub fn push_clip_instance(
1477 &mut self,
1478 handle: ClipDataHandle,
1479 ) -> ClipNodeRange {
1480 let first = self.clip_node_instances.len() as u32;
1481
1482 self.clip_node_instances.push(ClipNodeInstance {
1483 handle,
1484 flags: ClipNodeFlags::SAME_COORD_SYSTEM | ClipNodeFlags::SAME_SPATIAL_NODE,
1485 visible_tiles: None,
1486 });
1487
1488 ClipNodeRange {
1489 first,
1490 count: 1,
1491 }
1492 }
1493
1494 pub fn build_clip_chain_instance(
1497 &mut self,
1498 local_prim_rect: LayoutRect,
1499 prim_to_pic_mapper: &SpaceMapper<LayoutPixel, PicturePixel>,
1500 pic_to_vis_mapper: &SpaceMapper<PicturePixel, VisPixel>,
1501 spatial_tree: &SpatialTree,
1502 gpu_cache: &mut GpuCache,
1503 resource_cache: &mut ResourceCache,
1504 device_pixel_scale: DevicePixelScale,
1505 culling_rect: &VisRect,
1506 clip_data_store: &mut ClipDataStore,
1507 rg_builder: &mut RenderTaskGraphBuilder,
1508 request_resources: bool,
1509 ) -> Option<ClipChainInstance> {
1510 let local_clip_rect = match self.active_local_clip_rect {
1511 Some(rect) => rect,
1512 None => return None,
1513 };
1514 profile_scope!("build_clip_chain_instance");
1515
1516 let local_bounding_rect = local_prim_rect.intersection(&local_clip_rect)?;
1517 let mut pic_coverage_rect = prim_to_pic_mapper.map(&local_bounding_rect)?;
1518 let vis_clip_rect = pic_to_vis_mapper.map(&pic_coverage_rect)?;
1519
1520 let first_clip_node_index = self.clip_node_instances.len() as u32;
1526 let mut has_non_local_clips = false;
1527 let mut needs_mask = false;
1528
1529 for node_info in self.active_clip_node_info.drain(..) {
1531 let node = &mut clip_data_store[node_info.handle];
1532
1533 let clip_result = match node_info.conversion {
1535 ClipSpaceConversion::Local => {
1536 node.item.kind.get_clip_result(&local_bounding_rect)
1537 }
1538 ClipSpaceConversion::ScaleOffset(ref scale_offset) => {
1539 has_non_local_clips = true;
1540 node.item.kind.get_clip_result(&scale_offset.unmap_rect(&local_bounding_rect))
1541 }
1542 ClipSpaceConversion::Transform(ref transform) => {
1543 has_non_local_clips = true;
1544 node.item.kind.get_clip_result_complex(
1545 transform,
1546 &vis_clip_rect,
1547 culling_rect,
1548 )
1549 }
1550 };
1551
1552 match clip_result {
1553 ClipResult::Accept => {
1554 }
1556 ClipResult::Reject => {
1557 return None;
1559 }
1560 ClipResult::Partial => {
1561 node.update(device_pixel_scale);
1565
1566 if let Some(instance) = node_info.create_instance(
1568 node,
1569 &local_bounding_rect,
1570 gpu_cache,
1571 resource_cache,
1572 &mut self.mask_tiles,
1573 spatial_tree,
1574 rg_builder,
1575 request_resources,
1576 ) {
1577 needs_mask |= match node.item.kind {
1584 ClipItemKind::Rectangle { mode: ClipMode::ClipOut, .. } |
1585 ClipItemKind::RoundedRectangle { .. } |
1586 ClipItemKind::Image { .. } |
1587 ClipItemKind::BoxShadow { .. } => {
1588 true
1589 }
1590
1591 ClipItemKind::Rectangle { mode: ClipMode::Clip, .. } => {
1592 !instance.flags.contains(ClipNodeFlags::SAME_COORD_SYSTEM)
1593 }
1594 };
1595
1596 self.clip_node_instances.push(instance);
1598 }
1599 }
1600 }
1601 }
1602
1603 let clips_range = ClipNodeRange {
1605 first: first_clip_node_index,
1606 count: self.clip_node_instances.len() as u32 - first_clip_node_index,
1607 };
1608
1609 if needs_mask {
1616 pic_coverage_rect = pic_coverage_rect.intersection(&self.active_pic_coverage_rect)?;
1617 }
1618
1619 Some(ClipChainInstance {
1621 clips_range,
1622 has_non_local_clips,
1623 local_clip_rect,
1624 pic_coverage_rect,
1625 pic_spatial_node_index: prim_to_pic_mapper.ref_spatial_node_index,
1626 needs_mask,
1627 })
1628 }
1629
1630 pub fn begin_frame(&mut self, scratch: &mut ClipStoreScratchBuffer) {
1631 mem::swap(&mut self.clip_node_instances, &mut scratch.clip_node_instances);
1632 mem::swap(&mut self.mask_tiles, &mut scratch.mask_tiles);
1633 self.clip_node_instances.clear();
1634 self.mask_tiles.clear();
1635 }
1636
1637 pub fn end_frame(&mut self, scratch: &mut ClipStoreScratchBuffer) {
1638 mem::swap(&mut self.clip_node_instances, &mut scratch.clip_node_instances);
1639 mem::swap(&mut self.mask_tiles, &mut scratch.mask_tiles);
1640 }
1641
1642 pub fn visible_mask_tiles(&self, instance: &ClipNodeInstance) -> &[VisibleMaskImageTile] {
1643 if let Some(range) = &instance.visible_tiles {
1644 &self.mask_tiles[range.clone()]
1645 } else {
1646 &[]
1647 }
1648 }
1649}
1650
1651impl Default for ClipStore {
1652 fn default() -> Self {
1653 ClipStore::new()
1654 }
1655}
1656
1657#[derive(Copy, Debug, Clone, Eq, MallocSizeOf, PartialEq, Hash)]
1665#[cfg_attr(feature = "capture", derive(Serialize))]
1666#[cfg_attr(feature = "replay", derive(Deserialize))]
1667pub enum ClipItemKeyKind {
1668 Rectangle(RectangleKey, ClipMode),
1669 RoundedRectangle(RectangleKey, BorderRadiusAu, ClipMode),
1670 ImageMask(RectangleKey, ImageKey, Option<PolygonDataHandle>),
1671 BoxShadow(PointKey, SizeKey, BorderRadiusAu, RectangleKey, Au, BoxShadowClipMode),
1672}
1673
1674impl ClipItemKeyKind {
1675 pub fn rectangle(rect: LayoutRect, mode: ClipMode) -> Self {
1676 ClipItemKeyKind::Rectangle(rect.into(), mode)
1677 }
1678
1679 pub fn rounded_rect(rect: LayoutRect, mut radii: BorderRadius, mode: ClipMode) -> Self {
1680 if radii.is_zero() {
1681 ClipItemKeyKind::rectangle(rect, mode)
1682 } else {
1683 ensure_no_corner_overlap(&mut radii, rect.size());
1684 ClipItemKeyKind::RoundedRectangle(
1685 rect.into(),
1686 radii.into(),
1687 mode,
1688 )
1689 }
1690 }
1691
1692 pub fn image_mask(image_mask: &ImageMask, mask_rect: LayoutRect,
1693 polygon_handle: Option<PolygonDataHandle>) -> Self {
1694 ClipItemKeyKind::ImageMask(
1695 mask_rect.into(),
1696 image_mask.image,
1697 polygon_handle,
1698 )
1699 }
1700
1701 pub fn box_shadow(
1702 shadow_rect: LayoutRect,
1703 shadow_radius: BorderRadius,
1704 prim_shadow_rect: LayoutRect,
1705 blur_radius: f32,
1706 clip_mode: BoxShadowClipMode,
1707 ) -> Self {
1708 let fract_offset = LayoutPoint::new(
1711 shadow_rect.min.x.fract().abs(),
1712 shadow_rect.min.y.fract().abs(),
1713 );
1714
1715 ClipItemKeyKind::BoxShadow(
1716 fract_offset.into(),
1717 shadow_rect.size().into(),
1718 shadow_radius.into(),
1719 prim_shadow_rect.into(),
1720 Au::from_f32_px(blur_radius),
1721 clip_mode,
1722 )
1723 }
1724
1725 pub fn node_kind(&self) -> ClipNodeKind {
1726 match *self {
1727 ClipItemKeyKind::Rectangle(_, ClipMode::Clip) => ClipNodeKind::Rectangle,
1728
1729 ClipItemKeyKind::Rectangle(_, ClipMode::ClipOut) |
1730 ClipItemKeyKind::RoundedRectangle(..) |
1731 ClipItemKeyKind::ImageMask(..) |
1732 ClipItemKeyKind::BoxShadow(..) => ClipNodeKind::Complex,
1733 }
1734 }
1735}
1736
1737#[derive(Debug, Copy, Clone, Eq, MallocSizeOf, PartialEq, Hash)]
1738#[cfg_attr(feature = "capture", derive(Serialize))]
1739#[cfg_attr(feature = "replay", derive(Deserialize))]
1740pub struct ClipItemKey {
1741 pub kind: ClipItemKeyKind,
1742 pub spatial_node_index: SpatialNodeIndex,
1743}
1744
1745#[derive(Debug, MallocSizeOf)]
1747#[cfg_attr(feature = "capture", derive(Serialize))]
1748#[cfg_attr(feature = "replay", derive(Deserialize))]
1749pub struct ClipInternData {
1750 pub key: ClipItemKey,
1751}
1752
1753impl intern::InternDebug for ClipItemKey {}
1754
1755impl intern::Internable for ClipIntern {
1756 type Key = ClipItemKey;
1757 type StoreData = ClipNode;
1758 type InternData = ClipInternData;
1759 const PROFILE_COUNTER: usize = crate::profiler::INTERNED_CLIPS;
1760}
1761
1762#[derive(Debug, MallocSizeOf)]
1763#[cfg_attr(feature = "capture", derive(Serialize))]
1764#[cfg_attr(feature = "replay", derive(Deserialize))]
1765pub enum ClipItemKind {
1766 Rectangle {
1767 rect: LayoutRect,
1768 mode: ClipMode,
1769 },
1770 RoundedRectangle {
1771 rect: LayoutRect,
1772 radius: BorderRadius,
1773 mode: ClipMode,
1774 },
1775 Image {
1776 image: ImageKey,
1777 rect: LayoutRect,
1778 polygon_handle: Option<PolygonDataHandle>,
1779 },
1780 BoxShadow {
1781 source: BoxShadowClipSource,
1782 },
1783}
1784
1785#[derive(Debug, MallocSizeOf)]
1786#[cfg_attr(feature = "capture", derive(Serialize))]
1787#[cfg_attr(feature = "replay", derive(Deserialize))]
1788pub struct ClipItem {
1789 pub kind: ClipItemKind,
1790 pub spatial_node_index: SpatialNodeIndex,
1791}
1792
1793fn compute_box_shadow_parameters(
1794 shadow_rect_fract_offset: LayoutPoint,
1795 shadow_rect_size: LayoutSize,
1796 mut shadow_radius: BorderRadius,
1797 prim_shadow_rect: LayoutRect,
1798 blur_radius: f32,
1799 clip_mode: BoxShadowClipMode,
1800) -> BoxShadowClipSource {
1801 ensure_no_corner_overlap(&mut shadow_radius, shadow_rect_size);
1803
1804 let fract_size = LayoutSize::new(
1805 shadow_rect_size.width.fract().abs(),
1806 shadow_rect_size.height.fract().abs(),
1807 );
1808
1809 let max_corner_width = shadow_radius.top_left.width
1814 .max(shadow_radius.bottom_left.width)
1815 .max(shadow_radius.top_right.width)
1816 .max(shadow_radius.bottom_right.width);
1817 let max_corner_height = shadow_radius.top_left.height
1818 .max(shadow_radius.bottom_left.height)
1819 .max(shadow_radius.top_right.height)
1820 .max(shadow_radius.bottom_right.height);
1821
1822 let blur_region = (BLUR_SAMPLE_SCALE * blur_radius).ceil();
1824
1825 let used_corner_width = max_corner_width.max(blur_region);
1828 let used_corner_height = max_corner_height.max(blur_region);
1829
1830 let min_shadow_rect_size = LayoutSize::new(
1832 2.0 * used_corner_width + blur_region,
1833 2.0 * used_corner_height + blur_region,
1834 );
1835
1836 let mut minimal_shadow_rect = LayoutRect::from_origin_and_size(
1838 LayoutPoint::new(
1839 blur_region + shadow_rect_fract_offset.x,
1840 blur_region + shadow_rect_fract_offset.y,
1841 ),
1842 LayoutSize::new(
1843 min_shadow_rect_size.width + fract_size.width,
1844 min_shadow_rect_size.height + fract_size.height,
1845 ),
1846 );
1847
1848 let mut stretch_mode_x = BoxShadowStretchMode::Stretch;
1854 if shadow_rect_size.width < minimal_shadow_rect.width() {
1855 minimal_shadow_rect.max.x = minimal_shadow_rect.min.x + shadow_rect_size.width;
1856 stretch_mode_x = BoxShadowStretchMode::Simple;
1857 }
1858
1859 let mut stretch_mode_y = BoxShadowStretchMode::Stretch;
1860 if shadow_rect_size.height < minimal_shadow_rect.height() {
1861 minimal_shadow_rect.max.y = minimal_shadow_rect.min.y + shadow_rect_size.height;
1862 stretch_mode_y = BoxShadowStretchMode::Simple;
1863 }
1864
1865 let shadow_rect_alloc_size = LayoutSize::new(
1867 2.0 * blur_region + minimal_shadow_rect.width().ceil(),
1868 2.0 * blur_region + minimal_shadow_rect.height().ceil(),
1869 );
1870
1871 BoxShadowClipSource {
1872 original_alloc_size: shadow_rect_alloc_size,
1873 shadow_rect_alloc_size,
1874 shadow_radius,
1875 prim_shadow_rect,
1876 blur_radius,
1877 clip_mode,
1878 stretch_mode_x,
1879 stretch_mode_y,
1880 render_task: None,
1881 cache_key: None,
1882 minimal_shadow_rect,
1883 }
1884}
1885
1886impl ClipItemKind {
1887 pub fn new_box_shadow(
1888 shadow_rect_fract_offset: LayoutPoint,
1889 shadow_rect_size: LayoutSize,
1890 mut shadow_radius: BorderRadius,
1891 prim_shadow_rect: LayoutRect,
1892 blur_radius: f32,
1893 clip_mode: BoxShadowClipMode,
1894 ) -> Self {
1895 let mut source = compute_box_shadow_parameters(
1896 shadow_rect_fract_offset,
1897 shadow_rect_size,
1898 shadow_radius,
1899 prim_shadow_rect,
1900 blur_radius,
1901 clip_mode,
1902 );
1903
1904 fn needed_downscaling(source: &BoxShadowClipSource) -> Option<f32> {
1905 const MAX_SIZE: f32 = 2048.;
1912
1913 let max_dimension =
1914 source.shadow_rect_alloc_size.width.max(source.shadow_rect_alloc_size.height);
1915
1916 if max_dimension > MAX_SIZE {
1917 Some(MAX_SIZE / max_dimension)
1918 } else {
1919 None
1920 }
1921 }
1922
1923 if let Some(downscale) = needed_downscaling(&source) {
1924 shadow_radius.bottom_left.height *= downscale;
1925 shadow_radius.bottom_left.width *= downscale;
1926 shadow_radius.bottom_right.height *= downscale;
1927 shadow_radius.bottom_right.width *= downscale;
1928 shadow_radius.top_left.height *= downscale;
1929 shadow_radius.top_left.width *= downscale;
1930 shadow_radius.top_right.height *= downscale;
1931 shadow_radius.top_right.width *= downscale;
1932
1933 let original_alloc_size = source.shadow_rect_alloc_size;
1934
1935 source = compute_box_shadow_parameters(
1936 shadow_rect_fract_offset * downscale,
1937 shadow_rect_size * downscale,
1938 shadow_radius,
1939 prim_shadow_rect,
1940 blur_radius * downscale,
1941 clip_mode,
1942 );
1943 source.original_alloc_size = original_alloc_size;
1944 }
1945 ClipItemKind::BoxShadow { source }
1946 }
1947
1948 fn supports_fast_path_rendering(&self) -> bool {
1953 match *self {
1954 ClipItemKind::Rectangle { .. } |
1955 ClipItemKind::Image { .. } |
1956 ClipItemKind::BoxShadow { .. } => {
1957 false
1958 }
1959 ClipItemKind::RoundedRectangle { ref rect, ref radius, .. } => {
1960 radius.can_use_fast_path_in(rect)
1961 }
1962 }
1963 }
1964
1965 pub fn get_local_clip_rect(&self) -> Option<LayoutRect> {
1970 match *self {
1971 ClipItemKind::Rectangle { rect, mode: ClipMode::Clip } => Some(rect),
1972 ClipItemKind::Rectangle { mode: ClipMode::ClipOut, .. } => None,
1973 ClipItemKind::RoundedRectangle { rect, mode: ClipMode::Clip, .. } => Some(rect),
1974 ClipItemKind::RoundedRectangle { mode: ClipMode::ClipOut, .. } => None,
1975 ClipItemKind::Image { rect, .. } => {
1976 Some(rect)
1977 }
1978 ClipItemKind::BoxShadow { .. } => None,
1979 }
1980 }
1981
1982 fn get_clip_result_complex(
1983 &self,
1984 transform: &LayoutToVisTransform,
1985 prim_rect: &VisRect,
1986 culling_rect: &VisRect,
1987 ) -> ClipResult {
1988 let visible_rect = match prim_rect.intersection(culling_rect) {
1989 Some(rect) => rect,
1990 None => return ClipResult::Reject,
1991 };
1992
1993 let (clip_rect, inner_rect, mode) = match *self {
1994 ClipItemKind::Rectangle { rect, mode } => {
1995 (rect, Some(rect), mode)
1996 }
1997 ClipItemKind::RoundedRectangle { rect, ref radius, mode } => {
1998 let inner_clip_rect = extract_inner_rect_safe(&rect, radius);
1999 (rect, inner_clip_rect, mode)
2000 }
2001 ClipItemKind::Image { rect, .. } => {
2002 (rect, None, ClipMode::Clip)
2003 }
2004 ClipItemKind::BoxShadow { .. } => {
2005 return ClipResult::Partial;
2006 }
2007 };
2008
2009 if let Some(ref inner_clip_rect) = inner_rect {
2010 if let Some(()) = projected_rect_contains(inner_clip_rect, transform, &visible_rect) {
2011 return match mode {
2012 ClipMode::Clip => ClipResult::Accept,
2013 ClipMode::ClipOut => ClipResult::Reject,
2014 };
2015 }
2016 }
2017
2018 match mode {
2019 ClipMode::Clip => {
2020 let outer_clip_rect = match project_rect(
2021 transform,
2022 &clip_rect,
2023 &culling_rect,
2024 ) {
2025 Some(outer_clip_rect) => outer_clip_rect,
2026 None => return ClipResult::Partial,
2027 };
2028
2029 match outer_clip_rect.intersection(prim_rect) {
2030 Some(..) => {
2031 ClipResult::Partial
2032 }
2033 None => {
2034 ClipResult::Reject
2035 }
2036 }
2037 }
2038 ClipMode::ClipOut => ClipResult::Partial,
2039 }
2040 }
2041
2042 fn get_clip_result(
2044 &self,
2045 prim_rect: &LayoutRect,
2046 ) -> ClipResult {
2047 match *self {
2048 ClipItemKind::Rectangle { rect, mode: ClipMode::Clip } => {
2049 if rect.contains_box(prim_rect) {
2050 return ClipResult::Accept;
2051 }
2052
2053 match rect.intersection(prim_rect) {
2054 Some(..) => {
2055 ClipResult::Partial
2056 }
2057 None => {
2058 ClipResult::Reject
2059 }
2060 }
2061 }
2062 ClipItemKind::Rectangle { rect, mode: ClipMode::ClipOut } => {
2063 if rect.contains_box(prim_rect) {
2064 return ClipResult::Reject;
2065 }
2066
2067 match rect.intersection(prim_rect) {
2068 Some(_) => {
2069 ClipResult::Partial
2070 }
2071 None => {
2072 ClipResult::Accept
2073 }
2074 }
2075 }
2076 ClipItemKind::RoundedRectangle { rect, ref radius, mode: ClipMode::Clip } => {
2077 if rounded_rectangle_contains_box_quick(&rect, radius, &prim_rect) {
2080 return ClipResult::Accept;
2081 }
2082
2083 match rect.intersection(prim_rect) {
2084 Some(..) => {
2085 ClipResult::Partial
2086 }
2087 None => {
2088 ClipResult::Reject
2089 }
2090 }
2091 }
2092 ClipItemKind::RoundedRectangle { rect, ref radius, mode: ClipMode::ClipOut } => {
2093 if rounded_rectangle_contains_box_quick(&rect, radius, &prim_rect) {
2096 return ClipResult::Reject;
2097 }
2098
2099 match rect.intersection(prim_rect) {
2100 Some(_) => {
2101 ClipResult::Partial
2102 }
2103 None => {
2104 ClipResult::Accept
2105 }
2106 }
2107 }
2108 ClipItemKind::Image { rect, .. } => {
2109 match rect.intersection(prim_rect) {
2110 Some(..) => {
2111 ClipResult::Partial
2112 }
2113 None => {
2114 ClipResult::Reject
2115 }
2116 }
2117 }
2118 ClipItemKind::BoxShadow { .. } => {
2119 ClipResult::Partial
2120 }
2121 }
2122 }
2123}
2124
2125pub fn rounded_rectangle_contains_point(
2126 point: &LayoutPoint,
2127 rect: &LayoutRect,
2128 radii: &BorderRadius
2129) -> bool {
2130 if !rect.contains(*point) {
2131 return false;
2132 }
2133
2134 let top_left_center = rect.min + radii.top_left.to_vector();
2135 if top_left_center.x > point.x && top_left_center.y > point.y &&
2136 !Ellipse::new(radii.top_left).contains(*point - top_left_center.to_vector()) {
2137 return false;
2138 }
2139
2140 let bottom_right_center = rect.bottom_right() - radii.bottom_right.to_vector();
2141 if bottom_right_center.x < point.x && bottom_right_center.y < point.y &&
2142 !Ellipse::new(radii.bottom_right).contains(*point - bottom_right_center.to_vector()) {
2143 return false;
2144 }
2145
2146 let top_right_center = rect.top_right() +
2147 LayoutVector2D::new(-radii.top_right.width, radii.top_right.height);
2148 if top_right_center.x < point.x && top_right_center.y > point.y &&
2149 !Ellipse::new(radii.top_right).contains(*point - top_right_center.to_vector()) {
2150 return false;
2151 }
2152
2153 let bottom_left_center = rect.bottom_left() +
2154 LayoutVector2D::new(radii.bottom_left.width, -radii.bottom_left.height);
2155 if bottom_left_center.x > point.x && bottom_left_center.y < point.y &&
2156 !Ellipse::new(radii.bottom_left).contains(*point - bottom_left_center.to_vector()) {
2157 return false;
2158 }
2159
2160 true
2161}
2162
2163fn rounded_rectangle_contains_box_quick(
2167 container: &LayoutRect,
2168 radii: &BorderRadius,
2169 containee: &LayoutRect,
2170) -> bool {
2171 if !container.contains_box(containee) {
2172 return false;
2173 }
2174
2175 fn foul(point: LayoutPoint, corner: LayoutPoint) -> bool {
2178 point.x < corner.x && point.y < corner.y
2179 }
2180
2181 fn flip_x(pt: LayoutPoint) -> LayoutPoint {
2183 LayoutPoint { x: -pt.x, .. pt }
2184 }
2185
2186 fn flip_y(pt: LayoutPoint) -> LayoutPoint {
2188 LayoutPoint { y: -pt.y, .. pt }
2189 }
2190
2191 if foul(containee.top_left(), container.top_left() + radii.top_left) ||
2192 foul(flip_x(containee.top_right()), flip_x(container.top_right()) + radii.top_right) ||
2193 foul(flip_y(containee.bottom_left()), flip_y(container.bottom_left()) + radii.bottom_left) ||
2194 foul(-containee.bottom_right(), -container.bottom_right() + radii.bottom_right)
2195 {
2196 return false;
2197 }
2198
2199 true
2200}
2201
2202pub fn is_left_of_line(
2209 p_x: f32,
2210 p_y: f32,
2211 p0_x: f32,
2212 p0_y: f32,
2213 p1_x: f32,
2214 p1_y: f32,
2215) -> f32 {
2216 (p1_x - p0_x) * (p_y - p0_y) - (p_x - p0_x) * (p1_y - p0_y)
2217}
2218
2219pub fn polygon_contains_point(
2220 point: &LayoutPoint,
2221 rect: &LayoutRect,
2222 polygon: &PolygonKey,
2223) -> bool {
2224 if !rect.contains(*point) {
2225 return false;
2226 }
2227
2228 let p = LayoutPoint::new(point.x - rect.min.x, point.y - rect.min.y);
2231
2232 let mut winding_number: i32 = 0;
2234
2235 let count = polygon.point_count as usize;
2236
2237 for i in 0..count {
2238 let p0 = polygon.points[i];
2239 let p1 = polygon.points[(i + 1) % count];
2240
2241 if p0.y <= p.y {
2242 if p1.y > p.y {
2243 if is_left_of_line(p.x, p.y, p0.x, p0.y, p1.x, p1.y) > 0.0 {
2244 winding_number = winding_number + 1;
2245 }
2246 }
2247 } else if p1.y <= p.y {
2248 if is_left_of_line(p.x, p.y, p0.x, p0.y, p1.x, p1.y) < 0.0 {
2249 winding_number = winding_number - 1;
2250 }
2251 }
2252 }
2253
2254 match polygon.fill_rule {
2255 FillRule::Nonzero => winding_number != 0,
2256 FillRule::Evenodd => winding_number.abs() % 2 == 1,
2257 }
2258}
2259
2260pub fn projected_rect_contains(
2261 source_rect: &LayoutRect,
2262 transform: &LayoutToVisTransform,
2263 target_rect: &VisRect,
2264) -> Option<()> {
2265 let points = [
2266 transform.transform_point2d(source_rect.top_left())?,
2267 transform.transform_point2d(source_rect.top_right())?,
2268 transform.transform_point2d(source_rect.bottom_right())?,
2269 transform.transform_point2d(source_rect.bottom_left())?,
2270 ];
2271 let target_points = [
2272 target_rect.top_left(),
2273 target_rect.top_right(),
2274 target_rect.bottom_right(),
2275 target_rect.bottom_left(),
2276 ];
2277 for (a, b) in points
2279 .iter()
2280 .cloned()
2281 .zip(points[1..].iter().cloned().chain(iter::once(points[0])))
2282 {
2283 if a.approx_eq(&b) || target_points.iter().any(|&c| (b - a).cross(c - a) < 0.0) {
2288 return None
2289 }
2290 }
2291
2292 Some(())
2293}
2294
2295
2296fn add_clip_node_to_current_chain(
2300 handle: ClipDataHandle,
2301 prim_spatial_node_index: SpatialNodeIndex,
2302 pic_spatial_node_index: SpatialNodeIndex,
2303 visibility_spatial_node_index: SpatialNodeIndex,
2304 local_clip_rect: &mut LayoutRect,
2305 clip_node_info: &mut Vec<ClipNodeInfo>,
2306 pic_coverage_rect: &mut PictureRect,
2307 clip_data_store: &ClipDataStore,
2308 spatial_tree: &SpatialTree,
2309) -> bool {
2310 let clip_node = &clip_data_store[handle];
2311
2312 let conversion = ClipSpaceConversion::new(
2315 prim_spatial_node_index,
2316 clip_node.item.spatial_node_index,
2317 visibility_spatial_node_index,
2318 spatial_tree,
2319 );
2320
2321 if let Some(clip_rect) = clip_node.item.kind.get_local_clip_rect() {
2324 match conversion {
2325 ClipSpaceConversion::Local => {
2326 *local_clip_rect = match local_clip_rect.intersection(&clip_rect) {
2327 Some(rect) => rect,
2328 None => return false,
2329 };
2330 }
2331 ClipSpaceConversion::ScaleOffset(ref scale_offset) => {
2332 let clip_rect = scale_offset.map_rect(&clip_rect);
2333 *local_clip_rect = match local_clip_rect.intersection(&clip_rect) {
2334 Some(rect) => rect,
2335 None => return false,
2336 };
2337 }
2338 ClipSpaceConversion::Transform(..) => {
2339 let pic_coord_system = spatial_tree
2349 .get_spatial_node(pic_spatial_node_index)
2350 .coordinate_system_id;
2351
2352 let clip_coord_system = spatial_tree
2353 .get_spatial_node(clip_node.item.spatial_node_index)
2354 .coordinate_system_id;
2355
2356 if pic_coord_system == clip_coord_system {
2357 let mapper = SpaceMapper::new_with_target(
2358 pic_spatial_node_index,
2359 clip_node.item.spatial_node_index,
2360 PictureRect::max_rect(),
2361 spatial_tree,
2362 );
2363
2364 if let Some(pic_clip_rect) = mapper.map(&clip_rect) {
2365 *pic_coverage_rect = pic_clip_rect
2366 .intersection(pic_coverage_rect)
2367 .unwrap_or(PictureRect::zero());
2368 }
2369 }
2370 }
2371 }
2372 }
2373
2374 clip_node_info.push(ClipNodeInfo {
2375 conversion,
2376 handle,
2377 });
2378
2379 true
2380}
2381
2382#[cfg(test)]
2383mod tests {
2384 use super::projected_rect_contains;
2385 use euclid::{Transform3D, rect};
2386
2387 #[test]
2388 fn test_empty_projected_rect() {
2389 assert_eq!(
2390 None,
2391 projected_rect_contains(
2392 &rect(10.0, 10.0, 0.0, 0.0).to_box2d(),
2393 &Transform3D::identity(),
2394 &rect(20.0, 20.0, 10.0, 10.0).to_box2d(),
2395 ),
2396 "Empty rectangle is considered to include a non-empty!"
2397 );
2398 }
2399}
2400
2401#[derive(Copy, Clone, Debug, Hash, MallocSizeOf, PartialEq, Eq)]
2408#[cfg_attr(any(feature = "serde"), derive(Deserialize, Serialize))]
2409pub enum PolygonIntern {}
2410
2411pub type PolygonDataHandle = intern::Handle<PolygonIntern>;
2412
2413impl intern::InternDebug for PolygonKey {}
2414
2415impl intern::Internable for PolygonIntern {
2416 type Key = PolygonKey;
2417 type StoreData = PolygonKey;
2418 type InternData = PolygonKey;
2419 const PROFILE_COUNTER: usize = crate::profiler::INTERNED_POLYGONS;
2420}