aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbors-servo <metajack+bors@gmail.com>2015-08-31 14:58:33 -0600
committerbors-servo <metajack+bors@gmail.com>2015-08-31 14:58:33 -0600
commitafc2c381db9c85eba3c10e87966351f77678dc6e (patch)
treec10fcf1e54e871fd68eaeb691b58c50c34329226
parent60c72f601c4dd7cfbc8a4a983099a4b323f1516a (diff)
parentd539b9b2e6e07d9064b4ad55a242a5691bc70746 (diff)
downloadservo-afc2c381db9c85eba3c10e87966351f77678dc6e.tar.gz
servo-afc2c381db9c85eba3c10e87966351f77678dc6e.zip
Auto merge of #7370 - bjwbell:bugfix-unequal-borders, r=pcwalton
gfx: Border radius support for asymmetric sized borders When the border-top/right/bottom/left-widths are not equal, the angle on the border corner arc separating the borders isn't PI/4. For instance if the top border width is much larger than the left border width then most of the border corner should be drawn using the top border color. This change adds support for calculating the correct angle in the border corner arc for switching from one border to another e.g. the left border to the top border. It supports elliptical border radii for when elliptical border radii are added. A ref test is also included. r? @Ms2ger <!-- Reviewable:start --> [<img src="https://reviewable.io/review_button.png" height=40 alt="Review on Reviewable"/>](https://reviewable.io/reviews/servo/servo/7370) <!-- Reviewable:end -->
-rw-r--r--components/gfx/paint_context.rs304
-rw-r--r--tests/ref/basic.list1
-rw-r--r--tests/ref/border_radius_asymmetric_sizes_a.html71
-rw-r--r--tests/ref/border_radius_asymmetric_sizes_ref.html217
4 files changed, 549 insertions, 44 deletions
diff --git a/components/gfx/paint_context.rs b/components/gfx/paint_context.rs
index a96d413cafc..9ebe86b1f38 100644
--- a/components/gfx/paint_context.rs
+++ b/components/gfx/paint_context.rs
@@ -72,6 +72,19 @@ enum DashSize {
DashedBorder = 3
}
+#[derive(Copy, Clone, Debug)]
+struct Ellipse {
+ origin: Point2D<f32>,
+ width: f32,
+ height: f32,
+}
+
+#[derive(Copy, Clone, Debug)]
+struct Line {
+ start: Point2D<f32>,
+ end: Point2D<f32>,
+}
+
impl<'a> PaintContext<'a> {
pub fn draw_target(&self) -> &DrawTarget {
&self.draw_target
@@ -355,6 +368,104 @@ impl<'a> PaintContext<'a> {
self.draw_target.push_clip(&path_builder.finish());
}
+ fn solve_quadratic(a: f32, b: f32, c: f32) -> (Option<f32>, Option<f32>) {
+ let discriminant = b * b - 4. * a * c;
+ if discriminant < 0. {
+ return (None, None);
+ }
+ let x1 = (-b + discriminant.sqrt())/(2. * a);
+ let x2 = (-b - discriminant.sqrt())/(2. * a);
+ if discriminant == 0. {
+ return (Some(x1), None);
+ }
+ return (Some(x1), Some(x2));
+ }
+
+ fn intersect_ellipse_line(e: Ellipse, l: Line) -> (Option<Point2D<f32>>, Option<Point2D<f32>>) {
+ debug_assert!(l.end.x - l.start.x > f32::EPSILON, "Error line segment end.x > start.x!!");
+ // shift the origin to center of the ellipse.
+ let line = Line { start: l.start - e.origin,
+ end: l.end - e.origin };
+
+ let a = (line.end.y - line.start.y)/(line.end.x - line.start.x);
+ let b = line.start.y - (a * line.start.x);
+ // given the equation of a line,
+ // y = a * x + b,
+ // and the equation of an ellipse,
+ // x^2/w^2 + y^2/h^2 = 1,
+ // substitute y = a * x + b, giving
+ // x^2/w^2 + (a^2x^2 + 2abx + b^2)/h^2 = 1
+ // then simplify to
+ // (h^2 + w^2a^2)x^2 + 2abw^2x + (b^2w^2 - w^2h^2) = 0
+ // finally solve for w using the quadratic equation.
+ let w = e.width;
+ let h = e.height;
+ let quad_a = h * h + w * w * a * a;
+ let quad_b = 2. * a * b * w * w;
+ let quad_c = b * b * w * w - w * w * h * h;
+ let intersections = PaintContext::solve_quadratic(quad_a, quad_b, quad_c);
+ match intersections {
+ (Some(x0), Some(x1)) => {
+ let mut p0 = Point2D::new(x0, a * x0 + b) + e.origin;
+ let mut p1 = Point2D::new(x1, a * x1 + b) + e.origin;
+ if x0 > x1 {
+ mem::swap(&mut p0, &mut p1);
+ }
+ (Some(p0), Some(p1))
+ },
+ (Some(x0), None) => {
+ let p = Point2D::new(x0, a * x0 + b) + e.origin;
+ (Some(p), None)
+ },
+ (None, Some(x1)) => {
+ let p = Point2D::new(x1, a * x1 + b) + e.origin;
+ (Some(p), None)
+ },
+ (None, None) => (None, None),
+ }
+ }
+
+ // Given an ellipse and line segment, the line segment may intersect the
+ // ellipse at 0, 1, or 2 points. We compute those intersection points.
+ // For each intersection point the angle of the point on the ellipse relative to
+ // the top|bottom of the ellipse is computed.
+ // Examples:
+ // - intersection at ellipse.center + (0, ellipse.height), the angle is 0 rad.
+ // - intersection at ellipse.center + (0, -ellipse.height), the angle is 0 rad.
+ // - intersection at ellipse.center + (+-ellipse.width, 0), the angle is pi/2.
+ fn ellipse_line_intersection_angles(e: Ellipse, l: Line)
+ -> (Option<(Point2D<f32>, f32)>, Option<(Point2D<f32>, f32)>) {
+ fn point_angle(e: Ellipse, intersect_point: Point2D<f32>) -> f32 {
+ ((intersect_point.y - e.origin.y).abs() / e.height).asin()
+ }
+
+ let intersection = PaintContext::intersect_ellipse_line(e, l);
+ match intersection {
+ (Some(p0), Some(p1)) => (Some((p0, point_angle(e, p0))), Some((p1, point_angle(e, p1)))),
+ (Some(p0), None) => (Some((p0, point_angle(e, p0))), None),
+ (None, Some(p1)) => (None, Some((p1, point_angle(e, p1)))),
+ (None, None) => (None, None),
+ }
+ }
+
+ fn ellipse_rightmost_line_intersection_angle(e: Ellipse, l: Line) -> Option<f32> {
+ match PaintContext::ellipse_line_intersection_angles(e, l) {
+ (Some((p0, angle0)), Some((p1, _))) if p0.x > p1.x => Some(angle0),
+ (_, Some((_, angle1))) => Some(angle1),
+ (Some((_, angle0)), None) => Some(angle0),
+ (None, None) => None,
+ }
+ }
+
+ fn ellipse_leftmost_line_intersection_angle(e: Ellipse, l: Line) -> Option<f32> {
+ match PaintContext::ellipse_line_intersection_angles(e, l) {
+ (Some((p0, angle0)), Some((p1, _))) if p0.x < p1.x => Some(angle0),
+ (_, Some((_, angle1))) => Some(angle1),
+ (Some((_, angle0)), None) => Some(angle0),
+ (None, None) => None,
+ }
+ }
+
// The following comment is wonderful, and stolen from
// gecko:gfx/thebes/gfxContext.cpp:RoundedRectangle for reference.
//
@@ -450,6 +561,11 @@ impl<'a> PaintContext<'a> {
let box_BL = box_TL + Point2D::new(0.0, bounds.size.height);
let box_BR = box_TL + Point2D::new(bounds.size.width, bounds.size.height);
+ let inner_TL = box_TL + Point2D::new(border.left, border.top);
+ let inner_TR = box_TR + Point2D::new(-border.right, border.top);
+ let inner_BR = box_BR + Point2D::new(-border.right, -border.bottom);
+ let inner_BL = box_BL + Point2D::new(border.left, -border.bottom);
+
let rad_R: AzFloat = 0.;
let rad_BR = rad_R + f32::consts::FRAC_PI_4;
let rad_B = rad_BR + f32::consts::FRAC_PI_4;
@@ -457,7 +573,6 @@ impl<'a> PaintContext<'a> {
let rad_L = rad_BL + f32::consts::FRAC_PI_4;
let rad_TL = rad_L + f32::consts::FRAC_PI_4;
let rad_T = rad_TL + f32::consts::FRAC_PI_4;
- let rad_TR = rad_T + f32::consts::FRAC_PI_4;
fn dx(x: AzFloat) -> Point2D<AzFloat> {
Point2D::new(x, 0.)
@@ -475,12 +590,41 @@ impl<'a> PaintContext<'a> {
Point2D::new(0., if cond { dy } else { 0. })
}
+ fn compatible_borders_corner(border1_width: f32, border2_width: f32) -> bool {
+ (border1_width - border2_width).abs() <= f32::EPSILON
+ }
+
+ let distance_to_elbow_TL =
+ if border.top == border.left {
+ (radius.top_left - border.top).max(0.)
+ } else {
+ 0.
+ };
+ let distance_to_elbow_TR =
+ if border.top == border.right {
+ (radius.top_right - border.top).max(0.)
+ } else {
+ 0.
+ };
+ let distance_to_elbow_BR =
+ if border.right == border.bottom {
+ (radius.bottom_right - border.bottom).max(0.)
+ } else {
+ 0.
+ };
+ let distance_to_elbow_BL =
+ if border.left == border.bottom {
+ (radius.bottom_left - border.bottom).max(0.)
+ } else {
+ 0.
+ };
+
match direction {
Direction::Top => {
let edge_TL = box_TL + dx(radius.top_left.max(border.left));
let edge_TR = box_TR + dx(-radius.top_right.max(border.right));
- let edge_BR = edge_TR + dy(border.top);
- let edge_BL = edge_TL + dy(border.top);
+ let edge_BR = box_TR + dx(-border.right - distance_to_elbow_TR) + dy(border.top);
+ let edge_BL = box_TL + dx(border.left + distance_to_elbow_TL) + dy(border.top);
let corner_TL = edge_TL + dx_if(radius.top_left == 0., -border.left);
let corner_TR = edge_TR + dx_if(radius.top_right == 0., border.right);
@@ -497,11 +641,18 @@ impl<'a> PaintContext<'a> {
// the origin is the center of the arcs we're about to draw.
let origin = edge_TR + Point2D::new((border.right - radius.top_right).max(0.),
radius.top_right);
- // the elbow is the inside of the border's curve.
- let distance_to_elbow = (radius.top_right - border.top).max(0.);
-
- path_builder.arc(origin, radius.top_right, rad_T, rad_TR, false);
- path_builder.arc(origin, distance_to_elbow, rad_TR, rad_T, true);
+ let angle = if compatible_borders_corner(border.top, border.right) {
+ f32::consts::FRAC_PI_4
+ } else {
+ let line = Line { start: inner_TR, end: box_TR };
+ let ellipse = Ellipse { origin: origin, width: radius.top_right, height: radius.top_right };
+ PaintContext::ellipse_rightmost_line_intersection_angle(ellipse, line).unwrap()
+ };
+
+ path_builder.arc(origin, radius.top_right, rad_T, rad_R - angle, false);
+ if distance_to_elbow_TR != 0. {
+ path_builder.arc(origin, distance_to_elbow_TR, rad_R - angle, rad_T, true);
+ }
}
match mode {
@@ -514,18 +665,26 @@ impl<'a> PaintContext<'a> {
if radius.top_left != 0. {
let origin = edge_TL + Point2D::new(-(border.left - radius.top_left).max(0.),
- radius.top_left);
- let distance_to_elbow = (radius.top_left - border.top).max(0.);
+ radius.top_left);
+ let angle = if compatible_borders_corner(border.top, border.left) {
+ f32::consts::FRAC_PI_4
+ } else {
+ let line = Line { start: box_TL, end: inner_TL };
+ let ellipse = Ellipse { origin: origin, width: radius.top_left, height: radius.top_left };
+ PaintContext::ellipse_leftmost_line_intersection_angle(ellipse, line).unwrap()
+ };
- path_builder.arc(origin, distance_to_elbow, rad_T, rad_TL, true);
- path_builder.arc(origin, radius.top_left, rad_TL, rad_T, false);
+ if distance_to_elbow_TL != 0. {
+ path_builder.arc(origin, distance_to_elbow_TL, rad_T, rad_L + angle, true);
+ }
+ path_builder.arc(origin, radius.top_left, rad_L + angle, rad_T, false);
}
}
Direction::Left => {
let edge_TL = box_TL + dy(radius.top_left.max(border.top));
let edge_BL = box_BL + dy(-radius.bottom_left.max(border.bottom));
- let edge_TR = edge_TL + dx(border.left);
- let edge_BR = edge_BL + dx(border.left);
+ let edge_TR = box_TL + dx(border.left) + dy(border.top + distance_to_elbow_TL);
+ let edge_BR = box_BL + dx(border.left) + dy(-border.bottom - distance_to_elbow_BL);
let corner_TL = edge_TL + dy_if(radius.top_left == 0., -border.top);
let corner_BL = edge_BL + dy_if(radius.bottom_left == 0., border.bottom);
@@ -540,11 +699,20 @@ impl<'a> PaintContext<'a> {
if radius.top_left != 0. {
let origin = edge_TL + Point2D::new(radius.top_left,
- -(border.top - radius.top_left).max(0.));
- let distance_to_elbow = (radius.top_left - border.left).max(0.);
+ -(border.top - radius.top_left).max(0.));
- path_builder.arc(origin, radius.top_left, rad_L, rad_TL, false);
- path_builder.arc(origin, distance_to_elbow, rad_TL, rad_L, true);
+ let angle = if compatible_borders_corner(border.top, border.left) {
+ f32::consts::FRAC_PI_4
+ } else {
+ let line = Line { start: box_TL, end: inner_TL };
+ let ellipse = Ellipse { origin: origin, width: radius.top_left, height: radius.top_left };
+ PaintContext::ellipse_leftmost_line_intersection_angle(ellipse, line).unwrap()
+ };
+
+ path_builder.arc(origin, radius.top_left, rad_L, rad_L + angle, false);
+ if distance_to_elbow_TL != 0. {
+ path_builder.arc(origin, distance_to_elbow_TL, rad_L + angle, rad_L, true);
+ }
}
match mode {
@@ -558,18 +726,28 @@ impl<'a> PaintContext<'a> {
if radius.bottom_left != 0. {
let origin = edge_BL +
Point2D::new(radius.bottom_left,
- (border.bottom - radius.bottom_left).max(0.));
- let distance_to_elbow = (radius.bottom_left - border.left).max(0.);
-
- path_builder.arc(origin, distance_to_elbow, rad_L, rad_BL, true);
- path_builder.arc(origin, radius.bottom_left, rad_BL, rad_L, false);
+ (border.bottom - radius.bottom_left).max(0.));
+ let angle = if compatible_borders_corner(border.bottom, border.left) {
+ f32::consts::FRAC_PI_4
+ } else {
+ let line = Line { start: box_BL, end: inner_BL };
+ let ellipse = Ellipse { origin: origin,
+ width: radius.bottom_left,
+ height: radius.bottom_left };
+ PaintContext::ellipse_leftmost_line_intersection_angle(ellipse, line).unwrap()
+ };
+
+ if distance_to_elbow_BL != 0. {
+ path_builder.arc(origin, distance_to_elbow_BL, rad_L, rad_L - angle, true);
+ }
+ path_builder.arc(origin, radius.bottom_left, rad_L - angle, rad_L, false);
}
}
Direction::Right => {
let edge_TR = box_TR + dy(radius.top_right.max(border.top));
let edge_BR = box_BR + dy(-radius.bottom_right.max(border.bottom));
- let edge_TL = edge_TR + dx(-border.right);
- let edge_BL = edge_BR + dx(-border.right);
+ let edge_TL = box_TR + dx(-border.right) + dy(border.top + distance_to_elbow_TR);
+ let edge_BL = box_BR + dx(-border.right) + dy(-border.bottom - distance_to_elbow_BR);
let corner_TR = edge_TR + dy_if(radius.top_right == 0., -border.top);
let corner_BR = edge_BR + dy_if(radius.bottom_right == 0., border.bottom);
@@ -585,10 +763,18 @@ impl<'a> PaintContext<'a> {
if radius.top_right != 0. {
let origin = edge_TR + Point2D::new(-radius.top_right,
-(border.top - radius.top_right).max(0.));
- let distance_to_elbow = (radius.top_right - border.right).max(0.);
+ let angle = if compatible_borders_corner(border.top, border.right) {
+ f32::consts::FRAC_PI_4
+ } else {
+ let line = Line { start: inner_TR, end: box_TR };
+ let ellipse = Ellipse { origin: origin, width: radius.top_right, height: radius.top_right };
+ PaintContext::ellipse_rightmost_line_intersection_angle(ellipse, line).unwrap()
+ };
- path_builder.arc(origin, distance_to_elbow, rad_R, rad_TR, true);
- path_builder.arc(origin, radius.top_right, rad_TR, rad_R, false);
+ if distance_to_elbow_TR != 0. {
+ path_builder.arc(origin, distance_to_elbow_TR, rad_R, rad_R - angle, true);
+ }
+ path_builder.arc(origin, radius.top_right, rad_R - angle, rad_R, false);
}
match mode {
@@ -602,18 +788,28 @@ impl<'a> PaintContext<'a> {
if radius.bottom_right != 0. {
let origin = edge_BR +
Point2D::new(-radius.bottom_right,
- (border.bottom - radius.bottom_right).max(0.));
- let distance_to_elbow = (radius.bottom_right - border.right).max(0.);
-
- path_builder.arc(origin, radius.bottom_right, rad_R, rad_BR, false);
- path_builder.arc(origin, distance_to_elbow, rad_BR, rad_R, true);
+ (border.bottom - radius.bottom_right).max(0.));
+ let angle = if compatible_borders_corner(border.bottom, border.right) {
+ f32::consts::FRAC_PI_4
+ } else {
+ let line = Line { start: inner_BR, end: box_BR };
+ let ellipse = Ellipse { origin: origin,
+ width: radius.bottom_right,
+ height: radius.bottom_right };
+ PaintContext::ellipse_rightmost_line_intersection_angle(ellipse, line).unwrap()
+ };
+
+ path_builder.arc(origin, radius.bottom_right, rad_R, rad_R + angle, false);
+ if distance_to_elbow_BR != 0. {
+ path_builder.arc(origin, distance_to_elbow_BR, rad_R + angle, rad_R, true);
+ }
}
}
Direction::Bottom => {
let edge_BL = box_BL + dx(radius.bottom_left.max(border.left));
let edge_BR = box_BR + dx(-radius.bottom_right.max(border.right));
- let edge_TL = edge_BL + dy(-border.bottom);
- let edge_TR = edge_BR + dy(-border.bottom);
+ let edge_TL = box_BL + dy(-border.bottom) + dx(border.left + distance_to_elbow_BL);
+ let edge_TR = box_BR + dy(-border.bottom) + dx(-border.right - distance_to_elbow_BR);
let corner_BR = edge_BR + dx_if(radius.bottom_right == 0., border.right);
let corner_BL = edge_BL + dx_if(radius.bottom_left == 0., -border.left);
@@ -629,10 +825,20 @@ impl<'a> PaintContext<'a> {
if radius.bottom_right != 0. {
let origin = edge_BR + Point2D::new((border.right - radius.bottom_right).max(0.),
-radius.bottom_right);
- let distance_to_elbow = (radius.bottom_right - border.bottom).max(0.);
-
- path_builder.arc(origin, distance_to_elbow, rad_B, rad_BR, true);
- path_builder.arc(origin, radius.bottom_right, rad_BR, rad_B, false);
+ let angle = if compatible_borders_corner(border.bottom, border.right) {
+ f32::consts::FRAC_PI_4
+ } else {
+ let line = Line { start: inner_BR, end: box_BR };
+ let ellipse = Ellipse { origin: origin,
+ width: radius.bottom_right,
+ height: radius.bottom_right };
+ PaintContext::ellipse_rightmost_line_intersection_angle(ellipse, line).unwrap()
+ };
+
+ if distance_to_elbow_BR != 0. {
+ path_builder.arc(origin, distance_to_elbow_BR, rad_B, rad_R + angle, true);
+ }
+ path_builder.arc(origin, radius.bottom_right, rad_R + angle, rad_B, false);
}
match mode {
@@ -645,11 +851,21 @@ impl<'a> PaintContext<'a> {
if radius.bottom_left != 0. {
let origin = edge_BL - Point2D::new((border.left - radius.bottom_left).max(0.),
- radius.bottom_left);
- let distance_to_elbow = (radius.bottom_left - border.bottom).max(0.);
-
- path_builder.arc(origin, radius.bottom_left, rad_B, rad_BL, false);
- path_builder.arc(origin, distance_to_elbow, rad_BL, rad_B, true);
+ radius.bottom_left);
+ let angle = if compatible_borders_corner(border.bottom, border.left) {
+ f32::consts::FRAC_PI_4
+ } else {
+ let line = Line { start: box_BL, end: inner_BL };
+ let ellipse = Ellipse { origin: origin,
+ width: radius.bottom_left,
+ height: radius.bottom_left };
+ PaintContext::ellipse_leftmost_line_intersection_angle(ellipse, line).unwrap()
+ };
+
+ path_builder.arc(origin, radius.bottom_left, rad_B, rad_L - angle, false);
+ if distance_to_elbow_BL != 0. {
+ path_builder.arc(origin, distance_to_elbow_BL, rad_L - angle, rad_B, true);
+ }
}
}
}
diff --git a/tests/ref/basic.list b/tests/ref/basic.list
index ed4e0d91a4b..a7e3d2154ba 100644
--- a/tests/ref/basic.list
+++ b/tests/ref/basic.list
@@ -61,6 +61,7 @@ flaky_cpu == append_style_a.html append_style_b.html
== border_code_tag.html border_code_tag_ref.html
== border_collapse_missing_cell_a.html border_collapse_missing_cell_ref.html
== border_collapse_simple_a.html border_collapse_simple_ref.html
+== border_radius_asymmetric_sizes_a.html border_radius_asymmetric_sizes_ref.html
== border_radius_clip_a.html border_radius_clip_ref.html
!= border_radius_dashed_a.html border_radius_dashed_ref.html
== border_radius_overlapping_a.html border_radius_overlapping_ref.html
diff --git a/tests/ref/border_radius_asymmetric_sizes_a.html b/tests/ref/border_radius_asymmetric_sizes_a.html
new file mode 100644
index 00000000000..94676b11941
--- /dev/null
+++ b/tests/ref/border_radius_asymmetric_sizes_a.html
@@ -0,0 +1,71 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta content="text/html;charset=utf-8" http-equiv="Content-Type">
+ <meta content="utf-8" http-equiv="encoding">
+ <style type="text/css">
+ div.box {
+ background: white;
+ border-width: 10px 10px 10px 10px;
+ border-color: yellow red green blue;
+ border-radius: 10px;
+ border-style: solid;
+ height: 190px;
+ width: 190px;
+ }
+ div.top {
+ border-top-width: 30px;
+ }
+ div.right {
+ border-right-width: 30px;
+ }
+ div.bottom {
+ border-bottom-width: 30px;
+ }
+ div.left {
+ border-left-width: 30px;
+ }
+ div.radius10px {
+ border-radius: 10px;
+ }
+ div.radius20px {
+ border-radius: 20px;
+ }
+ div.radius30px {
+ border-radius: 30px;
+ }
+ div.radius40px {
+ border-radius: 40px;
+ }
+
+ #box2, #box4, #box6, #box8, #box10, #box12, #box14 {
+ width: 170px;
+ }
+ </style>
+ </head>
+ <body>
+ <h2>Border Radius - 10px</h2>
+ Box#1<div id="box1" class="box top"></div><br>
+ Box#2<div id="box2" class="box right"></div><br>
+ Box#3<div id="box3" class="box bottom"></div><br>
+ Box#4<div id="box4" class="box left"></div><br>
+
+ <h2>Border Radius - 20px</h2>
+ Box#5<div id="box5" class="box top radius20px"></div><br>
+ Box#6<div id="box6" class="box right radius20px"></div><br>
+ Box#7<div id="box7" class="box bottom radius20px"></div><br>
+ Box#8<div id="box8" class="box left radius20px"></div><br>
+
+ <h2>Border Radius - 30px</h2>
+ Box#9<div id="box9" class="box top radius30px"></div><br>
+ Box#10<div id="box10" class="box right radius30px"></div><br>
+ Box#11<div id="box11" class="box bottom radius30px"></div><br>
+ Box#12<div id="box12" class="box left radius30px"></div><br>
+
+ <h2>Border Radius - 40px</h2>
+ Box#13<div id="box13" class="box top radius40px"></div><br>
+ Box#14<div id="box14" class="box right radius40px"></div><br>
+ Box#15<div id="box15" class="box bottom radius40px"></div><br>
+ Box#16<div id="box16" class="box left radius40px"></div><br>
+ </body>
+</html>
diff --git a/tests/ref/border_radius_asymmetric_sizes_ref.html b/tests/ref/border_radius_asymmetric_sizes_ref.html
new file mode 100644
index 00000000000..4993ae6fd7d
--- /dev/null
+++ b/tests/ref/border_radius_asymmetric_sizes_ref.html
@@ -0,0 +1,217 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta content="text/html;charset=utf-8" http-equiv="Content-Type">
+ <meta content="utf-8" http-equiv="encoding">
+ <style type="text/css">
+ .box-top {
+ background: white;
+ width: 190px;
+ height: 0px;
+ margin: 0px;
+ border-style: solid;
+ border-color: yellow red green blue;
+ }
+ .box-middle {
+ background: white;
+ width: 190px;
+ height: 190px;
+ margin: 0px;
+ border-style: solid;
+ border-color: yellow red green blue;
+ }
+ .box-bottom {
+ background: white;
+ width: 190px;
+ height: 0px;
+ margin: 0px;
+ border-style: solid;
+ border-color: yellow red green blue;
+ }
+ .top-radius-10 {
+ border-top-left-radius: 10px;
+ border-top-right-radius: 10px;
+ }
+ .bottom-radius-10 {
+ border-bottom-left-radius: 10px;
+ border-bottom-right-radius: 10px;
+ }
+ .top-radius-20 {
+ border-top-left-radius: 20px;
+ border-top-right-radius: 20px;
+ }
+ .bottom-radius-20 {
+ border-bottom-left-radius: 20px;
+ border-bottom-right-radius: 20px;
+ }
+ .top-radius-30 {
+ border-top-left-radius: 30px;
+ border-top-right-radius: 30px;
+ }
+ .bottom-radius-30 {
+ border-bottom-left-radius: 30px;
+ border-bottom-right-radius: 30px;
+ }
+ .top-radius-40 {
+ border-top-left-radius: 40px;
+ border-top-right-radius: 40px;
+ }
+ .bottom-radius-40 {
+ border-bottom-left-radius: 40px;
+ border-bottom-right-radius: 40px;
+ }
+ .box1-top {
+ border-top-width: 30px;
+ border-right-width: 10px;
+ border-bottom-width: 0px;
+ border-left-width: 10px;
+ }
+ .box1-middle {
+ border-width: 0px 10px 0px 10px;
+ }
+ .box1-bottom {
+ border-width: 0px 10px 10px 10px;
+ }
+ .box2-top {
+ width: 170px;
+ border-width: 10px 30px 0px 10px;
+ }
+ .box2-middle {
+ width: 170px;
+ border-width: 0px 30px 0px 10px;
+ }
+ .box2-bottom {
+ width: 170px;
+ border-width: 0px 30px 10px 10px;
+ }
+ .box3-top {
+ border-width: 10px 10px 0px 10px;
+ }
+ .box3-middle {
+ border-width: 0px 10px 0px 10px;
+ }
+ .box3-bottom {
+ border-top-width: 0px;
+ border-left-width: 10px;
+ border-right-width: 10px;
+ border-bottom-width: 30px;
+ }
+ .box4-top {
+ width: 170px;
+ border-width: 10px 10px 0px 30px;
+ }
+ .box4-middle {
+ width: 170px;
+ border-width: 0px 10px 0px 30px;
+ }
+ .box4-bottom {
+ width: 170px;
+ border-top-width: 0px;
+ border-left-width: 30px;
+ border-right-width: 10px;
+ border-bottom-width: 10px;
+ }
+ </style>
+ </head>
+ <body>
+ <h2>Border Radius - 10px</h2>
+ Box#1
+ <div id="box1-top" class="box-top box1-top top-radius-10"></div>
+ <div id="box1-middle" class="box-middle box1-middle middle-radius-10"></div>
+ <div id="box1-bottom" class="box-bottom box1-bottom bottom-radius-10"></div>
+ <br>
+
+ Box#2
+ <div id="box2-top" class="box-top box2-top top-radius-10"></div>
+ <div id="box2-middle" class="box-middle box2-middle middle-radius-10"></div>
+ <div id="box2-bottom" class="box-bottom box2-bottom bottom-radius-10"></div>
+ <br>
+
+ Box#3
+ <div id="box3-top" class="box-top box3-top top-radius-10"></div>
+ <div id="box3-middle" class="box-middle box3-middle middle-radius-10"></div>
+ <div id="box3-bottom" class="box-bottom box3-bottom bottom-radius-10"></div>
+ <br>
+
+ Box#4
+ <div id="box4-top" class="box-top box4-top top-radius-10"></div>
+ <div id="box4-middle" class="box-middle box4-middle middle-radius-10"></div>
+ <div id="box4-bottom" class="box-bottom box4-bottom bottom-radius-10"></div>
+ <br>
+
+ <h2>Border Radius - 20px</h2>
+ Box#5
+ <div id="box5-top" class="box-top box1-top top-radius-20"></div>
+ <div id="box5-middle" class="box-middle box1-middle middle-radius-20"></div>
+ <div id="box5-bottom" class="box-bottom box1-bottom bottom-radius-20"></div>
+ <br>
+
+ Box#6
+ <div id="box6-top" class="box-top box2-top top-radius-20"></div>
+ <div id="box6-middle" class="box-middle box2-middle middle-radius-20"></div>
+ <div id="box6-bottom" class="box-bottom box2-bottom bottom-radius-20"></div>
+ <br>
+
+ Box#7
+ <div id="box7-top" class="box-top box3-top top-radius-20"></div>
+ <div id="box7-middle" class="box-middle box3-middle middle-radius-20"></div>
+ <div id="box7-bottom" class="box-bottom box3-bottom bottom-radius-20"></div>
+ <br>
+
+ Box#8
+ <div id="box8-top" class="box-top box4-top top-radius-20"></div>
+ <div id="box8-middle" class="box-middle box4-middle middle-radius-20"></div>
+ <div id="box8-bottom" class="box-bottom box4-bottom bottom-radius-20"></div>
+ <br>
+
+ <h2>Border Radius - 30px</h2>
+ Box#9
+ <div id="box9-top" class="box-top box1-top top-radius-30"></div>
+ <div id="box9-middle" class="box-middle box1-middle middle-radius-30"></div>
+ <div id="box9-bottom" class="box-bottom box1-bottom bottom-radius-30"></div>
+ <br>
+
+ Box#10
+ <div id="box10-top" class="box-top box2-top top-radius-30"></div>
+ <div id="box10-middle" class="box-middle box2-middle middle-radius-30"></div>
+ <div id="box10-bottom" class="box-bottom box2-bottom bottom-radius-30"></div>
+ <br>
+
+ Box#11
+ <div id="box11-top" class="box-top box3-top top-radius-30"></div>
+ <div id="box11-middle" class="box-middle box3-middle middle-radius-30"></div>
+ <div id="box11-bottom" class="box-bottom box3-bottom bottom-radius-30"></div>
+ <br>
+
+ Box#12
+ <div id="box12-top" class="box-top box4-top top-radius-30"></div>
+ <div id="box12-middle" class="box-middle box4-middle middle-radius-30"></div>
+ <div id="box12-bottom" class="box-bottom box4-bottom bottom-radius-30"></div>
+ <br>
+
+ <h2>Border Radius - 40px</h2>
+ Box#13
+ <div id="box13-top" class="box-top box1-top top-radius-40"></div>
+ <div id="box13-middle" class="box-middle box1-middle middle-radius-40"></div>
+ <div id="box13-bottom" class="box-bottom box1-bottom bottom-radius-40"></div>
+ <br>
+
+ Box#14
+ <div id="box14-top" class="box-top box2-top top-radius-40"></div>
+ <div id="box14-middle" class="box-middle box2-middle middle-radius-40"></div>
+ <div id="box14-bottom" class="box-bottom box2-bottom bottom-radius-40"></div>
+ <br>
+
+ Box#15
+ <div id="box15-top" class="box-top box3-top top-radius-40"></div>
+ <div id="box15-middle" class="box-middle box3-middle middle-radius-40"></div>
+ <div id="box15-bottom" class="box-bottom box3-bottom bottom-radius-40"></div>
+ <br>
+
+ Box#16
+ <div id="box16-top" class="box-top box4-top top-radius-40"></div>
+ <div id="box16-middle" class="box-middle box4-middle middle-radius-40"></div>
+ <div id="box16-bottom" class="box-bottom box4-bottom bottom-radius-40"></div>
+ <br>
+ </body>
+</html>