auto merge of #4656 : PeterReid/servo/issue4125, r=mbrubeck

Fixes #4125

Conforming to section 5.5 (Rounded Corners/Overlapping Curves) of "CSS Background and Borders Module Level 3", border radii on elements whose border curves would have overlapped are uniformly scaled down to the point that they no longer do.

http://dev.w3.org/csswg/css-backgrounds/#corner-overlap
This commit is contained in:
bors-servo 2015-01-28 10:18:52 -07:00
commit 6dc2b895b8
4 changed files with 46 additions and 3 deletions

View file

@ -40,7 +40,7 @@ use servo_msg::constellation_msg::Msg as ConstellationMsg;
use servo_msg::constellation_msg::ConstellationChan;
use servo_net::image::holder::ImageHolder;
use servo_util::cursor::Cursor;
use servo_util::geometry::{self, Au, to_px};
use servo_util::geometry::{self, Au, to_px, to_frac_px};
use servo_util::logical_geometry::{LogicalPoint, LogicalRect, LogicalSize};
use servo_util::opts;
use std::default::Default;
@ -218,12 +218,42 @@ pub trait FragmentDisplayListBuilding {
clip: &ClippingRegion);
}
fn handle_overlapping_radii(size: &Size2D<Au>, radii: &BorderRadii<Au>) -> BorderRadii<Au> {
// No two corners' border radii may add up to more than the length of the edge
// between them. To prevent that, all radii are scaled down uniformly.
fn scale_factor(radius_a: Au, radius_b: Au, edge_length: Au) -> f64 {
let required = radius_a + radius_b;
if required <= edge_length {
1.0
} else {
to_frac_px(edge_length) / to_frac_px(required)
}
}
let top_factor = scale_factor(radii.top_left, radii.top_right, size.width);
let bottom_factor = scale_factor(radii.bottom_left, radii.bottom_right, size.width);
let left_factor = scale_factor(radii.top_left, radii.bottom_left, size.height);
let right_factor = scale_factor(radii.top_right, radii.bottom_right, size.height);
let min_factor = top_factor.min(bottom_factor).min(left_factor).min(right_factor);
if min_factor < 1.0 {
BorderRadii {
top_left: radii.top_left .scale_by(min_factor),
top_right: radii.top_right .scale_by(min_factor),
bottom_left: radii.bottom_left .scale_by(min_factor),
bottom_right: radii.bottom_right.scale_by(min_factor),
}
} else {
*radii
}
}
fn build_border_radius(abs_bounds: &Rect<Au>, border_style: &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.
BorderRadii {
handle_overlapping_radii(&abs_bounds.size, &BorderRadii {
top_left: model::specified(border_style.border_top_left_radius,
abs_bounds.size.width),
top_right: model::specified(border_style.border_top_right_radius,
@ -232,7 +262,7 @@ fn build_border_radius(abs_bounds: &Rect<Au>, border_style: &Border) -> BorderRa
abs_bounds.size.width),
bottom_left: model::specified(border_style.border_bottom_left_radius,
abs_bounds.size.width),
}
})
}
impl FragmentDisplayListBuilding for Fragment {

View file

@ -223,6 +223,7 @@ fragment=top != ../html/acid2.html acid2_ref.html
!= inset_blackborder.html blackborder_ref.html
!= outset_blackborder.html blackborder_ref.html
== border_radius_clip_a.html border_radius_clip_ref.html
== border_radius_overlapping_a.html border_radius_overlapping_ref.html
== stacking_context_overflow_a.html stacking_context_overflow_ref.html
== stacking_context_overflow_relative_outline_a.html stacking_context_overflow_relative_outline_ref.html
== word_break_a.html word_break_ref.html

View file

@ -0,0 +1,6 @@
<!DOCTYPE html>
<html>
<body>
<div style='box-sizing:border-box; width:6em; height:2em; border-radius:.5em 2em .5em 2em; background-color:red;'></div>
</body>
</html>

View file

@ -0,0 +1,6 @@
<!DOCTYPE html>
<html>
<body>
<div style='box-sizing:border-box; width:6em; height:2em; border-radius:.4em 1.6em .4em 1.6em; background-color:red;'></div>
</body>
</html>