mirror of
https://github.com/servo/servo.git
synced 2025-08-04 13:10:20 +01:00
layout: Correctly calculate the angle for gradients with corners
The previous code assumed that the diagonals of the elements were perpendicular, which only happens with squares. tests: layout: Test linear gradient corners
This commit is contained in:
parent
5668a55ef4
commit
37d1c749aa
4 changed files with 114 additions and 26 deletions
|
@ -592,35 +592,41 @@ impl FragmentDisplayListBuilding for Fragment {
|
||||||
let mut clip = clip.clone();
|
let mut clip = clip.clone();
|
||||||
clip.intersect_rect(absolute_bounds);
|
clip.intersect_rect(absolute_bounds);
|
||||||
|
|
||||||
// This is the distance between the center and the ending point; i.e. half of the distance
|
|
||||||
// between the starting point and the ending point.
|
let angle = match gradient.angle_or_corner {
|
||||||
let delta = match gradient.angle_or_corner {
|
AngleOrCorner::Angle(angle) => angle.radians(),
|
||||||
AngleOrCorner::Angle(angle) => {
|
AngleOrCorner::Corner(horizontal, vertical) => {
|
||||||
|
// This the angle for one of the diagonals of the box. Our angle
|
||||||
|
// will either be this one, this one + PI, or one of the other
|
||||||
|
// two perpendicular angles.
|
||||||
|
let atan = (absolute_bounds.size.height.to_f32_px() /
|
||||||
|
absolute_bounds.size.width.to_f32_px()).atan();
|
||||||
|
match (horizontal, vertical) {
|
||||||
|
(HorizontalDirection::Right, VerticalDirection::Bottom)
|
||||||
|
=> f32::consts::PI - atan,
|
||||||
|
(HorizontalDirection::Left, VerticalDirection::Bottom)
|
||||||
|
=> f32::consts::PI + atan,
|
||||||
|
(HorizontalDirection::Right, VerticalDirection::Top)
|
||||||
|
=> atan,
|
||||||
|
(HorizontalDirection::Left, VerticalDirection::Top)
|
||||||
|
=> -atan,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Get correct gradient line length, based on:
|
// Get correct gradient line length, based on:
|
||||||
// https://drafts.csswg.org/css-images-3/#linear-gradients
|
// https://drafts.csswg.org/css-images-3/#linear-gradients
|
||||||
let dir = Point2D::new(angle.radians().sin(), -angle.radians().cos());
|
let dir = Point2D::new(angle.sin(), -angle.cos());
|
||||||
|
|
||||||
let line_length = (dir.x * absolute_bounds.size.width.to_f32_px()).abs() +
|
let line_length = (dir.x * absolute_bounds.size.width.to_f32_px()).abs() +
|
||||||
(dir.y * absolute_bounds.size.height.to_f32_px()).abs();
|
(dir.y * absolute_bounds.size.height.to_f32_px()).abs();
|
||||||
|
|
||||||
let inv_dir_length = 1.0 / (dir.x * dir.x + dir.y * dir.y).sqrt();
|
let inv_dir_length = 1.0 / (dir.x * dir.x + dir.y * dir.y).sqrt();
|
||||||
|
|
||||||
Point2D::new(Au::from_f32_px(dir.x * inv_dir_length * line_length / 2.0),
|
// This is the vector between the center and the ending point; i.e. half
|
||||||
Au::from_f32_px(dir.y * inv_dir_length * line_length / 2.0))
|
// of the distance between the starting point and the ending point.
|
||||||
}
|
let delta = Point2D::new(Au::from_f32_px(dir.x * inv_dir_length * line_length / 2.0),
|
||||||
AngleOrCorner::Corner(horizontal, vertical) => {
|
Au::from_f32_px(dir.y * inv_dir_length * line_length / 2.0));
|
||||||
let x_factor = match horizontal {
|
|
||||||
HorizontalDirection::Left => -1,
|
|
||||||
HorizontalDirection::Right => 1,
|
|
||||||
};
|
|
||||||
let y_factor = match vertical {
|
|
||||||
VerticalDirection::Top => -1,
|
|
||||||
VerticalDirection::Bottom => 1,
|
|
||||||
};
|
|
||||||
Point2D::new(absolute_bounds.size.width * x_factor / 2,
|
|
||||||
absolute_bounds.size.height * y_factor / 2)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// This is the length of the gradient line.
|
// This is the length of the gradient line.
|
||||||
let length = Au::from_f32_px(
|
let length = Au::from_f32_px(
|
||||||
|
@ -629,7 +635,8 @@ impl FragmentDisplayListBuilding for Fragment {
|
||||||
// Determine the position of each stop per CSS-IMAGES § 3.4.
|
// Determine the position of each stop per CSS-IMAGES § 3.4.
|
||||||
//
|
//
|
||||||
// FIXME(#3908, pcwalton): Make sure later stops can't be behind earlier stops.
|
// FIXME(#3908, pcwalton): Make sure later stops can't be behind earlier stops.
|
||||||
let (mut stops, mut stop_run) = (Vec::new(), None);
|
let mut stops = Vec::with_capacity(gradient.stops.len());
|
||||||
|
let mut stop_run = None;
|
||||||
for (i, stop) in gradient.stops.iter().enumerate() {
|
for (i, stop) in gradient.stops.iter().enumerate() {
|
||||||
let offset = match stop.position {
|
let offset = match stop.position {
|
||||||
None => {
|
None => {
|
||||||
|
|
|
@ -3120,6 +3120,18 @@
|
||||||
"url": "/_mozilla/css/linear_gradients_lengths_a.html"
|
"url": "/_mozilla/css/linear_gradients_lengths_a.html"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"css/linear_gradients_non_square_a.html": [
|
||||||
|
{
|
||||||
|
"path": "css/linear_gradients_non_square_a.html",
|
||||||
|
"references": [
|
||||||
|
[
|
||||||
|
"/_mozilla/css/linear_gradients_non_square_ref.html",
|
||||||
|
"=="
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"url": "/_mozilla/css/linear_gradients_non_square_a.html"
|
||||||
|
}
|
||||||
|
],
|
||||||
"css/linear_gradients_parsing_a.html": [
|
"css/linear_gradients_parsing_a.html": [
|
||||||
{
|
{
|
||||||
"path": "css/linear_gradients_parsing_a.html",
|
"path": "css/linear_gradients_parsing_a.html",
|
||||||
|
@ -10124,6 +10136,18 @@
|
||||||
"url": "/_mozilla/css/linear_gradients_lengths_a.html"
|
"url": "/_mozilla/css/linear_gradients_lengths_a.html"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"css/linear_gradients_non_square_a.html": [
|
||||||
|
{
|
||||||
|
"path": "css/linear_gradients_non_square_a.html",
|
||||||
|
"references": [
|
||||||
|
[
|
||||||
|
"/_mozilla/css/linear_gradients_non_square_ref.html",
|
||||||
|
"=="
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"url": "/_mozilla/css/linear_gradients_non_square_a.html"
|
||||||
|
}
|
||||||
|
],
|
||||||
"css/linear_gradients_parsing_a.html": [
|
"css/linear_gradients_parsing_a.html": [
|
||||||
{
|
{
|
||||||
"path": "css/linear_gradients_parsing_a.html",
|
"path": "css/linear_gradients_parsing_a.html",
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
<!doctype html>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>Linear gradients for non-square elements</title>
|
||||||
|
<link rel="match" href="linear_gradients_non_square_ref.html">
|
||||||
|
<style>
|
||||||
|
.a,
|
||||||
|
.b,
|
||||||
|
.c,
|
||||||
|
.d {
|
||||||
|
width: 200px;
|
||||||
|
height: 100px;
|
||||||
|
}
|
||||||
|
.a {
|
||||||
|
background: linear-gradient(to right bottom, black 50%, lightgray 50%);
|
||||||
|
}
|
||||||
|
.b {
|
||||||
|
background: linear-gradient(to left bottom, black 50%, lightgray 50%);
|
||||||
|
}
|
||||||
|
.c {
|
||||||
|
background: linear-gradient(to left top, black 50%, lightgray 50%);
|
||||||
|
}
|
||||||
|
.d {
|
||||||
|
background: linear-gradient(to right top, black 50%, lightgray 50%);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div class="a"></div>
|
||||||
|
<div class="b"></div>
|
||||||
|
<div class="c"></div>
|
||||||
|
<div class="d"></div>
|
|
@ -0,0 +1,28 @@
|
||||||
|
<!doctype html>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>Linear gradients for non-square elements reference</title>
|
||||||
|
<style>
|
||||||
|
.a,
|
||||||
|
.b,
|
||||||
|
.c,
|
||||||
|
.d {
|
||||||
|
width: 200px;
|
||||||
|
height: 100px;
|
||||||
|
}
|
||||||
|
.a {
|
||||||
|
background: linear-gradient(-206.56505118deg, black 50%, lightgray 50%);
|
||||||
|
}
|
||||||
|
.b {
|
||||||
|
background: linear-gradient(206.56505118deg, black 50%, lightgray 50%);
|
||||||
|
}
|
||||||
|
.c {
|
||||||
|
background: linear-gradient(-26.56505118deg, black 50%, lightgray 50%);
|
||||||
|
}
|
||||||
|
.d {
|
||||||
|
background: linear-gradient(26.56505118deg, black 50%, lightgray 50%);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div class="a"></div>
|
||||||
|
<div class="b"></div>
|
||||||
|
<div class="c"></div>
|
||||||
|
<div class="d"></div>
|
Loading…
Add table
Add a link
Reference in a new issue