mirror of
https://github.com/servo/servo.git
synced 2025-08-06 06:00:15 +01:00
Auto merge of #24201 - pylbrecht:raqote, r=jdm
Implement raqote backend for 2D canvas rendering <!-- Please describe your changes on the following line: --> --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `___` with appropriate data: --> - [X] `./mach build -d` does not report any errors - [X] `./mach test-tidy` does not report any errors - [ ] These changes fix (part of) #23431 <!-- Either: --> - [ ] There are tests for these changes <!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.--> <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/24201) <!-- Reviewable:end -->
This commit is contained in:
commit
e431a7baf7
2 changed files with 122 additions and 16 deletions
8
Cargo.lock
generated
8
Cargo.lock
generated
|
@ -405,7 +405,7 @@ dependencies = [
|
|||
"num-traits 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"offscreen_gl_context 0.25.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pixels 0.0.1",
|
||||
"raqote 0.6.2-alpha.0 (git+https://github.com/jrmuizel/raqote)",
|
||||
"raqote 0.6.5-alpha.0 (git+https://github.com/jrmuizel/raqote)",
|
||||
"serde_bytes 0.10.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"servo_config 0.0.1",
|
||||
"sparkle 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -3688,8 +3688,8 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "raqote"
|
||||
version = "0.6.2-alpha.0"
|
||||
source = "git+https://github.com/jrmuizel/raqote#b1437ce88d27d376520485a1f8d60c5a480be5c1"
|
||||
version = "0.6.5-alpha.0"
|
||||
source = "git+https://github.com/jrmuizel/raqote#c9d6d9c65ffac5fe91e2699f9854b3fbaa3c85c2"
|
||||
dependencies = [
|
||||
"euclid 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"font-kit 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -6170,7 +6170,7 @@ dependencies = [
|
|||
"checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071"
|
||||
"checksum rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44"
|
||||
"checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c"
|
||||
"checksum raqote 0.6.2-alpha.0 (git+https://github.com/jrmuizel/raqote)" = "<none>"
|
||||
"checksum raqote 0.6.5-alpha.0 (git+https://github.com/jrmuizel/raqote)" = "<none>"
|
||||
"checksum rayon 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "83a27732a533a1be0a0035a111fe76db89ad312f6f0347004c220c57f209a123"
|
||||
"checksum rayon-core 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "98dcf634205083b17d0861252431eb2acbfb698ab7478a2d20de07954f47ec7b"
|
||||
"checksum rayon_croissant 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5b725e815f3aa08718063883a75003336889debafe2f8fa67fbe91563ddc4efa"
|
||||
|
|
|
@ -12,6 +12,7 @@ use canvas_traits::canvas::*;
|
|||
use cssparser::RGBA;
|
||||
use euclid::default::{Point2D, Rect, Size2D, Transform2D, Vector2D};
|
||||
use raqote::PathOp;
|
||||
use std::f32::consts::PI;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
pub struct RaqoteBackend;
|
||||
|
@ -185,8 +186,7 @@ impl Path {
|
|||
}
|
||||
|
||||
pub fn contains_point(&self, x: f64, y: f64, _path_transform: &Transform2D<f32>) -> bool {
|
||||
let path = self.as_raqote();
|
||||
path.contains_point(0.1, path.winding, x as f32, y as f32)
|
||||
self.as_raqote().contains_point(0.1, x as f32, y as f32)
|
||||
}
|
||||
|
||||
pub fn copy_to_builder(&self) -> Box<dyn GenericPathBuilder> {
|
||||
|
@ -483,16 +483,82 @@ impl GenericPathBuilder for PathBuilder {
|
|||
}
|
||||
fn ellipse(
|
||||
&mut self,
|
||||
_origin: Point2D<f32>,
|
||||
_radius_x: f32,
|
||||
_radius_y: f32,
|
||||
origin: Point2D<f32>,
|
||||
radius_x: f32,
|
||||
radius_y: f32,
|
||||
_rotation_angle: f32,
|
||||
_start_angle: f32,
|
||||
_end_angle: f32,
|
||||
_anticlockwise: bool,
|
||||
start_angle: f32,
|
||||
mut end_angle: f32,
|
||||
anticlockwise: bool,
|
||||
) {
|
||||
unimplemented!();
|
||||
let start_point = Point2D::new(
|
||||
origin.x + start_angle.cos() * radius_x,
|
||||
origin.y + end_angle.sin() * radius_y,
|
||||
);
|
||||
self.line_to(start_point);
|
||||
|
||||
if !anticlockwise && (end_angle < start_angle) {
|
||||
let correction = ((start_angle - end_angle) / (2.0 * PI)).ceil();
|
||||
end_angle += correction * 2.0 * PI;
|
||||
} else if anticlockwise && (start_angle < end_angle) {
|
||||
let correction = ((end_angle - start_angle) / (2.0 * PI)).ceil();
|
||||
end_angle += correction * 2.0 * PI;
|
||||
}
|
||||
// Sweeping more than 2 * pi is a full circle.
|
||||
if !anticlockwise && (end_angle - start_angle > 2.0 * PI) {
|
||||
end_angle = start_angle + 2.0 * PI;
|
||||
} else if anticlockwise && (start_angle - end_angle > 2.0 * PI) {
|
||||
end_angle = start_angle - 2.0 * PI;
|
||||
}
|
||||
|
||||
// Calculate the total arc we're going to sweep.
|
||||
let mut arc_sweep_left = (end_angle - start_angle).abs();
|
||||
let sweep_direction = match anticlockwise {
|
||||
true => -1.0,
|
||||
false => 1.0,
|
||||
};
|
||||
let mut current_start_angle = start_angle;
|
||||
while arc_sweep_left > 0.0 {
|
||||
// We guarantee here the current point is the start point of the next
|
||||
// curve segment.
|
||||
let current_end_angle;
|
||||
if arc_sweep_left > PI / 2.0 {
|
||||
current_end_angle = current_start_angle + PI / 2.0 * sweep_direction;
|
||||
} else {
|
||||
current_end_angle = current_start_angle + arc_sweep_left * sweep_direction;
|
||||
}
|
||||
let current_start_point = Point2D::new(
|
||||
origin.x + current_start_angle.cos() * radius_x,
|
||||
origin.y + current_start_angle.sin() * radius_y,
|
||||
);
|
||||
let current_end_point = Point2D::new(
|
||||
origin.x + current_end_angle.cos() * radius_x,
|
||||
origin.y + current_end_angle.sin() * radius_y,
|
||||
);
|
||||
// Calculate kappa constant for partial curve. The sign of angle in the
|
||||
// tangent will actually ensure this is negative for a counter clockwise
|
||||
// sweep, so changing signs later isn't needed.
|
||||
let kappa_factor =
|
||||
(4.0 / 3.0) * ((current_end_angle - current_start_angle) / 4.0).tan();
|
||||
let kappa_x = kappa_factor * radius_x;
|
||||
let kappa_y = kappa_factor * radius_y;
|
||||
|
||||
let tangent_start =
|
||||
Point2D::new(-(current_start_angle.sin()), current_start_angle.cos());
|
||||
let mut cp1 = current_start_point;
|
||||
cp1 += Point2D::new(tangent_start.x * kappa_x, tangent_start.y * kappa_y).to_vector();
|
||||
let rev_tangent_end = Point2D::new(current_end_angle.sin(), -(current_end_angle.cos()));
|
||||
let mut cp2 = current_end_point;
|
||||
cp2 +=
|
||||
Point2D::new(rev_tangent_end.x * kappa_x, rev_tangent_end.y * kappa_y).to_vector();
|
||||
|
||||
self.bezier_curve_to(&cp1, &cp2, ¤t_end_point);
|
||||
|
||||
arc_sweep_left -= PI / 2.0;
|
||||
current_start_angle = current_end_angle;
|
||||
}
|
||||
}
|
||||
|
||||
fn get_current_point(&mut self) -> Point2D<f32> {
|
||||
let path = self.finish();
|
||||
|
||||
|
@ -561,6 +627,22 @@ pub trait ToRaqoteSource<'a> {
|
|||
fn to_raqote_source(self) -> Option<raqote::Source<'a>>;
|
||||
}
|
||||
|
||||
pub trait ToRaqoteGradientStop {
|
||||
fn to_raqote(&self) -> raqote::GradientStop;
|
||||
}
|
||||
|
||||
impl ToRaqoteGradientStop for CanvasGradientStop {
|
||||
fn to_raqote(&self) -> raqote::GradientStop {
|
||||
let color: u32 = ((self.color.alpha as u32) << 8 * 3 |
|
||||
(self.color.red as u32) << 8 * 2 |
|
||||
(self.color.green as u32) << 8 * 1 |
|
||||
(self.color.blue as u32) << 8 * 0)
|
||||
.into();
|
||||
let position = self.offset as f32;
|
||||
raqote::GradientStop { position, color }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ToRaqoteSource<'a> for FillOrStrokeStyle {
|
||||
#[allow(unsafe_code)]
|
||||
fn to_raqote_source(self) -> Option<raqote::Source<'a>> {
|
||||
|
@ -573,8 +655,32 @@ impl<'a> ToRaqoteSource<'a> for FillOrStrokeStyle {
|
|||
b: rgba.blue,
|
||||
a: rgba.alpha,
|
||||
})),
|
||||
LinearGradient(_) => unimplemented!(),
|
||||
RadialGradient(_) => unimplemented!(),
|
||||
LinearGradient(style) => {
|
||||
let stops = style.stops.into_iter().map(|s| s.to_raqote()).collect();
|
||||
let gradient = raqote::Gradient { stops };
|
||||
let start = Point2D::new(style.x0 as f32, style.y0 as f32);
|
||||
let end = Point2D::new(style.x1 as f32, style.y1 as f32);
|
||||
Some(raqote::Source::new_linear_gradient(
|
||||
gradient,
|
||||
start,
|
||||
end,
|
||||
raqote::Spread::Pad,
|
||||
))
|
||||
},
|
||||
RadialGradient(style) => {
|
||||
let stops = style.stops.into_iter().map(|s| s.to_raqote()).collect();
|
||||
let gradient = raqote::Gradient { stops };
|
||||
let center1 = Point2D::new(style.x0 as f32, style.y0 as f32);
|
||||
let center2 = Point2D::new(style.x1 as f32, style.y1 as f32);
|
||||
Some(raqote::Source::new_two_circle_radial_gradient(
|
||||
gradient,
|
||||
center1,
|
||||
style.r0 as f32,
|
||||
center2,
|
||||
style.r1 as f32,
|
||||
raqote::Spread::Pad,
|
||||
))
|
||||
},
|
||||
Surface(ref surface) => {
|
||||
let data = &surface.surface_data[..];
|
||||
Some(raqote::Source::Image(
|
||||
|
@ -645,7 +751,7 @@ impl ToRaqoteStyle for BlendingStyle {
|
|||
BlendingStyle::Saturation => raqote::BlendMode::Saturation,
|
||||
BlendingStyle::Color => raqote::BlendMode::Color,
|
||||
BlendingStyle::Luminosity => raqote::BlendMode::Luminosity,
|
||||
BlendingStyle::ColorBurn => unimplemented!("raqote doesn't support colorburn"),
|
||||
BlendingStyle::ColorBurn => raqote::BlendMode::ColorBurn,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue