Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gfx: Simplify complex clipping regions as we construct them. #10331

Merged
Merged
Changes from all commits
Commits
File filter...
Filter file types
Jump to…
Jump to file
Failed to load files.

Always

Just for now

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.
  • Loading branch information
pcwalton committed Apr 1, 2016
commit 22a1c112d50e0c7f82937cc66afd8659b80d5574
@@ -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
@@ -836,6 +836,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",
@@ -7246,6 +7258,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",
@@ -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>

@@ -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>

ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.