servo: Merge #16284 - Use real clips when generating scroll roots (from mrobinson:scroll-root-clip); r=glennw

This is the first step toward removing inherited clips in favor of
scroll roots for handling overflow and CSS clipping. This will allow us
to more easily handle elements that should not be clipped. While we are
still using inherited clips here, we now properly clip some types of
content that wasn't clipped before.

<!-- Please describe your changes on the following line: -->

---
<!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: -->
- [x] `./mach build -d` does not report any errors
- [x] `./mach test-tidy` does not report any errors
- [ ] These changes fix #__ (github issue number if applicable).

<!-- Either: -->
- [x] There are tests for these changes OR
- [ ] These changes do not require tests because _____

<!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.-->

<!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->

Source-Repo: https://github.com/servo/servo
Source-Revision: 24cea409f24135769c4fbedddd0f87da9d7bd12b

--HG--
extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear
extra : subtree_revision : 9e1db3f7fa3de95574acbef51d5c5ac63de1a8fa
This commit is contained in:
Martin Robinson 2017-04-06 14:32:16 -05:00
parent 57e4f4c27c
commit e6c81765aa
3 changed files with 47 additions and 12 deletions

View File

@ -508,7 +508,7 @@ pub struct ScrollRoot {
pub parent_id: ScrollRootId,
/// The position of this scroll root's frame in the parent stacking context.
pub clip: Rect<Au>,
pub clip: ClippingRegion,
/// The rect of the contents that can be scrolled inside of the scroll root.
pub content_rect: Rect<Au>,

View File

@ -520,7 +520,9 @@ fn handle_overlapping_radii(size: &Size2D<Au>, radii: &BorderRadii<Au>) -> Borde
}
}
fn build_border_radius(abs_bounds: &Rect<Au>, border_style: &style_structs::Border) -> BorderRadii<Au> {
fn build_border_radius(abs_bounds: &Rect<Au>,
border_style: &style_structs::Border)
-> BorderRadii<Au> {
// TODO(cgaebel): Support border radii even in the case of multiple border widths.
// This is an extension of supporting elliptical radii. For now, all percentage
// radii will be relative to the width.
@ -537,6 +539,34 @@ fn build_border_radius(abs_bounds: &Rect<Au>, border_style: &style_structs::Bord
})
}
/// Get the border radius for the rectangle inside of a rounded border. This is useful
/// for building the clip for the content inside the border.
fn build_border_radius_for_inner_rect(outer_rect: &Rect<Au>,
style: Arc<ServoComputedValues>)
-> BorderRadii<Au> {
let mut radii = build_border_radius(&outer_rect, style.get_border());
if radii.is_square() {
return radii;
}
// Since we are going to using the inner rectangle (outer rectangle minus
// border width), we need to adjust to border radius so that we are smaller
// rectangle with the same border curve.
let border_widths = style.logical_border_width().to_physical(style.writing_mode);
radii.top_left.width = cmp::max(Au(0), radii.top_left.width - border_widths.left);
radii.bottom_left.width = cmp::max(Au(0), radii.bottom_left.width - border_widths.left);
radii.top_right.width = cmp::max(Au(0), radii.top_right.width - border_widths.right);
radii.bottom_right.width = cmp::max(Au(0), radii.bottom_right.width - border_widths.right);
radii.top_left.height = cmp::max(Au(0), radii.top_left.height - border_widths.top);
radii.top_right.height = cmp::max(Au(0), radii.top_right.height - border_widths.top);
radii.bottom_left.height = cmp::max(Au(0), radii.bottom_left.height - border_widths.bottom);
radii.bottom_right.height = cmp::max(Au(0), radii.bottom_right.height - border_widths.bottom);
radii
}
impl FragmentDisplayListBuilding for Fragment {
fn build_display_list_for_background_if_applicable(&self,
state: &mut DisplayListBuildState,
@ -1978,12 +2008,21 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
let new_scroll_root_id = ScrollRootId::new_of_type(self.fragment.node.id() as usize,
self.fragment.fragment_type());
let clip_rect = Rect::new(Point2D::zero(), content_box.size);
let mut clip = ClippingRegion::from_rect(&clip_rect);
let border_radii = build_border_radius_for_inner_rect(&border_box,
self.fragment.style.clone());
if !border_radii.is_square() {
clip.intersect_with_rounded_rect(&clip_rect, &border_radii)
}
let content_size = self.base.overflow.scroll.origin + self.base.overflow.scroll.size;
state.add_scroll_root(
ScrollRoot {
id: new_scroll_root_id,
parent_id: containing_scroll_root_id,
clip: Rect::new(Point2D::zero(), content_box.size),
clip: clip,
content_rect: Rect::new(content_box.origin,
Size2D::new(content_size.x, content_size.y)),
},

View File

@ -421,15 +421,11 @@ impl WebRenderDisplayItemConverter for DisplayItem {
}
DisplayItem::PopStackingContext(_) => builder.pop_stacking_context(),
DisplayItem::PushScrollRoot(ref item) => {
let clip = builder.new_clip_region(&item.scroll_root.clip.to_rectf(),
vec![],
None);
let provided_id = ScrollLayerId::new(item.scroll_root.id.0 as u64, builder.pipeline_id);
let id = builder.define_clip(item.scroll_root.content_rect.to_rectf(),
clip,
Some(provided_id));
debug_assert!(provided_id == id);
let our_id = ScrollLayerId::new(item.scroll_root.id.0 as u64, builder.pipeline_id);
let clip = item.scroll_root.clip.to_clip_region(builder);
let content_rect = item.scroll_root.content_rect.to_rectf();
let webrender_id = builder.define_clip(content_rect, clip, Some(our_id));
debug_assert!(our_id == webrender_id);
}
DisplayItem::PopScrollRoot(_) => {} //builder.pop_scroll_layer(),
}