Auto merge of #10331 - pcwalton:simplify-complex-clipping-regions, r=glennw

gfx: Simplify complex clipping regions as we construct them.

This allows WebRender to correctly render complex clipping regions that
can be reduced to single rounded rectangles. WebRender still can't
render rounded rectangles with arbitrary intersections yet, but this
allows it to handle many more cases.

Closes servo/webrender#241.

r? @glennw

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="35" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/10331)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2016-04-02 05:03:07 +05:30
commit 4e21517796
4 changed files with 116 additions and 1 deletions

View file

@ -32,7 +32,7 @@ use range::Range;
use serde::de::{self, Deserialize, Deserializer, MapVisitor, Visitor};
use serde::ser::impls::MapIteratorVisitor;
use serde::ser::{Serialize, Serializer};
use std::cmp::Ordering;
use std::cmp::{self, Ordering};
use std::collections::HashMap;
use std::fmt;
use std::hash::{BuildHasherDefault, Hash};
@ -887,6 +887,27 @@ impl ClippingRegion {
/// Intersects this clipping region with the given rounded rectangle.
#[inline]
pub fn intersect_with_rounded_rect(&mut self, rect: &Rect<Au>, radii: &BorderRadii<Au>) {
let new_complex_region = ComplexClippingRegion {
rect: *rect,
radii: *radii,
};
// FIXME(pcwalton): This is O(n²) worst case for disjoint clipping regions. Is that OK?
// They're slow anyway…
//
// Possibly relevant if we want to do better:
//
// http://www.inrg.csie.ntu.edu.tw/algorithm2014/presentation/D&C%20Lee-84.pdf
for existing_complex_region in &mut self.complex {
if existing_complex_region.completely_encloses(&new_complex_region) {
*existing_complex_region = new_complex_region;
return
}
if new_complex_region.completely_encloses(existing_complex_region) {
return
}
}
self.complex.push(ComplexClippingRegion {
rect: *rect,
radii: *radii,
@ -908,6 +929,21 @@ impl ClippingRegion {
}
}
impl ComplexClippingRegion {
// TODO(pcwalton): This could be more aggressive by considering points that touch the inside of
// the border radius ellipse.
fn completely_encloses(&self, other: &ComplexClippingRegion) -> bool {
let left = cmp::max(self.radii.top_left.width, self.radii.bottom_left.width);
let top = cmp::max(self.radii.top_left.height, self.radii.top_right.height);
let right = cmp::max(self.radii.top_right.width, self.radii.bottom_right.width);
let bottom = cmp::max(self.radii.bottom_left.height, self.radii.bottom_right.height);
let interior = Rect::new(Point2D::new(self.rect.origin.x + left, self.rect.origin.y + top),
Size2D::new(self.rect.size.width - left - right,
self.rect.size.height - top - bottom));
interior.origin.x <= other.rect.origin.x && interior.origin.y <= other.rect.origin.y &&
interior.max_x() >= other.rect.max_x() && interior.max_y() >= other.rect.max_y()
}
}
/// Metadata attached to each display item. This is useful for performing auxiliary threads with
/// the display list involving hit testing: finding the originating DOM node and determining the

View file

@ -827,6 +827,18 @@
"url": "/_mozilla/css/border_radius_elliptical_a.html"
}
],
"css/border_radius_in_border_radius_a.html": [
{
"path": "css/border_radius_in_border_radius_a.html",
"references": [
[
"/_mozilla/css/border_radius_in_border_radius_ref.html",
"=="
]
],
"url": "/_mozilla/css/border_radius_in_border_radius_a.html"
}
],
"css/border_radius_overlapping_a.html": [
{
"path": "css/border_radius_overlapping_a.html",
@ -7249,6 +7261,18 @@
"url": "/_mozilla/css/border_radius_elliptical_a.html"
}
],
"css/border_radius_in_border_radius_a.html": [
{
"path": "css/border_radius_in_border_radius_a.html",
"references": [
[
"/_mozilla/css/border_radius_in_border_radius_ref.html",
"=="
]
],
"url": "/_mozilla/css/border_radius_in_border_radius_a.html"
}
],
"css/border_radius_overlapping_a.html": [
{
"path": "css/border_radius_overlapping_a.html",

View file

@ -0,0 +1,26 @@
<!DOCTYPE html>
<meta charset="utf-8">
<link rel="match" href="border_radius_in_border_radius_ref.html">
<style>
html, body {
margin: 0;
padding: 0;
}
.green {
overflow: hidden;
border-radius: 50px;
background: green;
padding: 50px;
width: 100px;
}
.red {
background: red;
border-radius: 50%;
width: 100px;
height: 100px
}
</style>
<div class="green"><div class="red"></div></div>

View file

@ -0,0 +1,29 @@
<!DOCTYPE html>
<meta charset="utf-8">
<style>
html, body {
margin: 0;
padding: 0;
}
.green {
position: absolute;
border-radius: 50px;
background: green;
padding: 50px;
width: 100px;
height: 100px;
}
.red {
position: absolute;
top: 50px;
left: 50px;
width: 100px;
height: 100px;
background: red;
border-radius: 50%;
}
</style>
<div class="green"></div><div class="red"></div>