mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
Add a layer to store Pattern related information
Some information of `canvas_data::Pattern` was lost by converting it to `raqote::Source` due to the fact that Raqote did not store this information (e.g. linear gradient's start/end points). We introduce another layer to keep this information for later use (like in `is_zero_size_gradient()`).
This commit is contained in:
parent
1aecf40922
commit
a50aef6f00
2 changed files with 249 additions and 175 deletions
|
@ -358,15 +358,7 @@ pub enum Pattern<'a> {
|
||||||
#[cfg(feature = "canvas2d-azure")]
|
#[cfg(feature = "canvas2d-azure")]
|
||||||
Azure(azure::azure_hl::Pattern, PhantomData<&'a ()>),
|
Azure(azure::azure_hl::Pattern, PhantomData<&'a ()>),
|
||||||
#[cfg(feature = "canvas2d-raqote")]
|
#[cfg(feature = "canvas2d-raqote")]
|
||||||
Raqote(raqote::Source<'a>, Option<Repetition>),
|
Raqote(crate::raqote_backend::Pattern<'a>),
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub enum Repetition {
|
|
||||||
Repeat,
|
|
||||||
RepeatX,
|
|
||||||
RepeatY,
|
|
||||||
NoRepeat,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum DrawSurfaceOptions {
|
pub enum DrawSurfaceOptions {
|
||||||
|
|
|
@ -2,10 +2,11 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
use crate::canvas_data;
|
||||||
use crate::canvas_data::{
|
use crate::canvas_data::{
|
||||||
Backend, CanvasPaintState, Color, CompositionOp, DrawOptions, ExtendMode, Filter,
|
Backend, CanvasPaintState, Color, CompositionOp, DrawOptions, ExtendMode, Filter,
|
||||||
GenericDrawTarget, GenericPathBuilder, GradientStop, GradientStops, Path, Pattern, Repetition,
|
GenericDrawTarget, GenericPathBuilder, GradientStop, GradientStops, Path, SourceSurface,
|
||||||
SourceSurface, StrokeOptions, SurfaceFormat,
|
StrokeOptions, SurfaceFormat,
|
||||||
};
|
};
|
||||||
use crate::canvas_paint_thread::AntialiasMode;
|
use crate::canvas_paint_thread::AntialiasMode;
|
||||||
use canvas_traits::canvas::*;
|
use canvas_traits::canvas::*;
|
||||||
|
@ -26,25 +27,26 @@ impl Backend for RaqoteBackend {
|
||||||
color.as_raqote().a != 0
|
color.as_raqote().a != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
fn size_from_pattern(&self, rect: &Rect<f32>, pattern: &Pattern) -> Option<Size2D<f32>> {
|
fn size_from_pattern(
|
||||||
|
&self,
|
||||||
|
rect: &Rect<f32>,
|
||||||
|
pattern: &canvas_data::Pattern,
|
||||||
|
) -> Option<Size2D<f32>> {
|
||||||
match pattern {
|
match pattern {
|
||||||
Pattern::Raqote(raqote::Source::Image(image, ..), repetition) => {
|
canvas_data::Pattern::Raqote(Pattern::Surface(pattern)) => match pattern.repeat {
|
||||||
if let Some(repeat) = repetition {
|
Repetition::RepeatX => Some(Size2D::new(
|
||||||
match repeat {
|
rect.size.width as f32,
|
||||||
Repetition::RepeatX => {
|
pattern.image.height as f32,
|
||||||
Some(Size2D::new(rect.size.width as f32, image.height as f32))
|
)),
|
||||||
},
|
Repetition::RepeatY => Some(Size2D::new(
|
||||||
Repetition::RepeatY => {
|
pattern.image.width as f32,
|
||||||
Some(Size2D::new(image.width as f32, rect.size.height as f32))
|
rect.size.height as f32,
|
||||||
},
|
)),
|
||||||
Repetition::Repeat => Some(rect.size),
|
Repetition::Repeat => Some(rect.size),
|
||||||
Repetition::NoRepeat => {
|
Repetition::NoRepeat => Some(Size2D::new(
|
||||||
Some(Size2D::new(image.width as f32, image.height as f32))
|
pattern.image.width as f32,
|
||||||
},
|
pattern.image.height as f32,
|
||||||
}
|
)),
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
|
@ -60,8 +62,8 @@ impl Backend for RaqoteBackend {
|
||||||
state: &mut CanvasPaintState<'a>,
|
state: &mut CanvasPaintState<'a>,
|
||||||
_drawtarget: &dyn GenericDrawTarget,
|
_drawtarget: &dyn GenericDrawTarget,
|
||||||
) {
|
) {
|
||||||
if let Some(pattern) = style.to_raqote_source() {
|
if let Some(pattern) = style.to_raqote_pattern() {
|
||||||
state.fill_style = pattern;
|
state.fill_style = canvas_data::Pattern::Raqote(pattern);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,8 +73,8 @@ impl Backend for RaqoteBackend {
|
||||||
state: &mut CanvasPaintState<'a>,
|
state: &mut CanvasPaintState<'a>,
|
||||||
_drawtarget: &dyn GenericDrawTarget,
|
_drawtarget: &dyn GenericDrawTarget,
|
||||||
) {
|
) {
|
||||||
if let Some(pattern) = style.to_raqote_source() {
|
if let Some(pattern) = style.to_raqote_pattern() {
|
||||||
state.stroke_style = pattern;
|
state.stroke_style = canvas_data::Pattern::Raqote(pattern);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,54 +100,162 @@ impl Backend for RaqoteBackend {
|
||||||
|
|
||||||
impl<'a> CanvasPaintState<'a> {
|
impl<'a> CanvasPaintState<'a> {
|
||||||
pub fn new(_antialias: AntialiasMode) -> CanvasPaintState<'a> {
|
pub fn new(_antialias: AntialiasMode) -> CanvasPaintState<'a> {
|
||||||
let solid_src = raqote::SolidSource::from_unpremultiplied_argb(
|
let pattern = Pattern::Color(255, 0, 0, 0);
|
||||||
255,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
);
|
|
||||||
CanvasPaintState {
|
CanvasPaintState {
|
||||||
draw_options: DrawOptions::Raqote(raqote::DrawOptions::new()),
|
draw_options: DrawOptions::Raqote(raqote::DrawOptions::new()),
|
||||||
fill_style: Pattern::Raqote(raqote::Source::Solid(solid_src), None),
|
fill_style: canvas_data::Pattern::Raqote(pattern.clone()),
|
||||||
stroke_style: Pattern::Raqote(raqote::Source::Solid(solid_src), None),
|
stroke_style: canvas_data::Pattern::Raqote(pattern),
|
||||||
stroke_opts: StrokeOptions::Raqote(Default::default(), PhantomData),
|
stroke_opts: StrokeOptions::Raqote(Default::default(), PhantomData),
|
||||||
transform: Transform2D::identity(),
|
transform: Transform2D::identity(),
|
||||||
shadow_offset_x: 0.0,
|
shadow_offset_x: 0.0,
|
||||||
shadow_offset_y: 0.0,
|
shadow_offset_y: 0.0,
|
||||||
shadow_blur: 0.0,
|
shadow_blur: 0.0,
|
||||||
shadow_color: Color::Raqote(raqote::SolidSource::from_unpremultiplied_argb(
|
shadow_color: Color::Raqote(raqote::SolidSource::from_unpremultiplied_argb(0, 0, 0, 0)),
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
)),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Pattern<'_> {
|
#[derive(Clone)]
|
||||||
pub fn is_zero_size_gradient(&self) -> bool {
|
pub enum Pattern<'a> {
|
||||||
match self {
|
// argb
|
||||||
Pattern::Raqote(source, _) => {
|
Color(u8, u8, u8, u8),
|
||||||
use raqote::Source::*;
|
LinearGradient(LinearGradientPattern),
|
||||||
|
RadialGradient(RadialGradientPattern),
|
||||||
|
Surface(SurfacePattern<'a>),
|
||||||
|
}
|
||||||
|
|
||||||
match source {
|
#[derive(Clone)]
|
||||||
LinearGradient(g, ..) |
|
pub struct LinearGradientPattern {
|
||||||
RadialGradient(g, ..) |
|
gradient: raqote::Gradient,
|
||||||
TwoCircleRadialGradient(g, ..) => g.stops.is_empty(),
|
start: Point2D<f32>,
|
||||||
_ => false,
|
end: Point2D<f32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl LinearGradientPattern {
|
||||||
|
fn new(start: Point2D<f32>, end: Point2D<f32>, stops: Vec<raqote::GradientStop>) -> Self {
|
||||||
|
LinearGradientPattern {
|
||||||
|
gradient: raqote::Gradient { stops: stops },
|
||||||
|
start: start,
|
||||||
|
end: end,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct RadialGradientPattern {
|
||||||
|
gradient: raqote::Gradient,
|
||||||
|
center1: Point2D<f32>,
|
||||||
|
radius1: f32,
|
||||||
|
center2: Point2D<f32>,
|
||||||
|
radius2: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RadialGradientPattern {
|
||||||
|
fn new(
|
||||||
|
center1: Point2D<f32>,
|
||||||
|
radius1: f32,
|
||||||
|
center2: Point2D<f32>,
|
||||||
|
radius2: f32,
|
||||||
|
stops: Vec<raqote::GradientStop>,
|
||||||
|
) -> Self {
|
||||||
|
RadialGradientPattern {
|
||||||
|
gradient: raqote::Gradient { stops: stops },
|
||||||
|
center1: center1,
|
||||||
|
radius1: radius1,
|
||||||
|
center2: center2,
|
||||||
|
radius2: radius2,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct SurfacePattern<'a> {
|
||||||
|
image: raqote::Image<'a>,
|
||||||
|
filter: raqote::FilterMode,
|
||||||
|
extend: raqote::ExtendMode,
|
||||||
|
repeat: Repetition,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> SurfacePattern<'a> {
|
||||||
|
fn new(image: raqote::Image<'a>, filter: raqote::FilterMode, repeat: Repetition) -> Self {
|
||||||
|
let extend = match repeat {
|
||||||
|
Repetition::NoRepeat => raqote::ExtendMode::Pad,
|
||||||
|
Repetition::RepeatX | Repetition::RepeatY | Repetition::Repeat => {
|
||||||
|
raqote::ExtendMode::Repeat
|
||||||
|
},
|
||||||
|
};
|
||||||
|
SurfacePattern {
|
||||||
|
image: image,
|
||||||
|
filter: filter,
|
||||||
|
extend: extend,
|
||||||
|
repeat: repeat,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub enum Repetition {
|
||||||
|
Repeat,
|
||||||
|
RepeatX,
|
||||||
|
RepeatY,
|
||||||
|
NoRepeat,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Repetition {
|
||||||
|
fn from_xy(repeat_x: bool, repeat_y: bool) -> Self {
|
||||||
|
if repeat_x && repeat_y {
|
||||||
|
Repetition::Repeat
|
||||||
|
} else if repeat_x {
|
||||||
|
Repetition::RepeatX
|
||||||
|
} else if repeat_y {
|
||||||
|
Repetition::RepeatY
|
||||||
|
} else {
|
||||||
|
Repetition::NoRepeat
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl canvas_data::Pattern<'_> {
|
||||||
|
pub fn source(&self) -> raqote::Source {
|
||||||
|
match self {
|
||||||
|
canvas_data::Pattern::Raqote(pattern) => match pattern {
|
||||||
|
Pattern::Color(a, r, g, b) => raqote::Source::Solid(
|
||||||
|
raqote::SolidSource::from_unpremultiplied_argb(*a, *r, *g, *b),
|
||||||
|
),
|
||||||
|
Pattern::LinearGradient(pattern) => raqote::Source::new_linear_gradient(
|
||||||
|
pattern.gradient.clone(),
|
||||||
|
pattern.start,
|
||||||
|
pattern.end,
|
||||||
|
raqote::Spread::Pad,
|
||||||
|
),
|
||||||
|
Pattern::RadialGradient(pattern) => raqote::Source::new_two_circle_radial_gradient(
|
||||||
|
pattern.gradient.clone(),
|
||||||
|
pattern.center1,
|
||||||
|
pattern.radius1,
|
||||||
|
pattern.center2,
|
||||||
|
pattern.radius2,
|
||||||
|
raqote::Spread::Pad,
|
||||||
|
),
|
||||||
|
Pattern::Surface(pattern) => raqote::Source::Image(
|
||||||
|
pattern.image,
|
||||||
|
pattern.extend,
|
||||||
|
pattern.filter,
|
||||||
|
Transform2D::identity(),
|
||||||
|
),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn source(&self) -> &raqote::Source {
|
pub fn is_zero_size_gradient(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Pattern::Raqote(source, _) => source,
|
canvas_data::Pattern::Raqote(pattern) => match pattern {
|
||||||
}
|
Pattern::RadialGradient(pattern) => {
|
||||||
}
|
let centers_equal = pattern.center1 == pattern.center2;
|
||||||
pub fn repetition(&self) -> &Option<Repetition> {
|
let radii_equal = pattern.radius1 == pattern.radius2;
|
||||||
match self {
|
centers_equal && radii_equal
|
||||||
Pattern::Raqote(_, repetition) => repetition,
|
},
|
||||||
|
Pattern::LinearGradient(pattern) => pattern.start == pattern.end,
|
||||||
|
Pattern::Color(..) | Pattern::Surface(..) => false,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -226,6 +336,16 @@ impl Path {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn create_gradient_stops(gradient_stops: Vec<GradientStop>) -> GradientStops {
|
||||||
|
let mut stops = gradient_stops
|
||||||
|
.into_iter()
|
||||||
|
.map(|item| item.as_raqote().clone())
|
||||||
|
.collect::<Vec<raqote::GradientStop>>();
|
||||||
|
// https://www.w3.org/html/test/results/2dcontext/annotated-spec/canvas.html#testrefs.2d.gradient.interpolate.overlap
|
||||||
|
stops.sort_by(|a, b| a.position.partial_cmp(&b.position).unwrap());
|
||||||
|
GradientStops::Raqote(stops)
|
||||||
|
}
|
||||||
|
|
||||||
impl GenericDrawTarget for raqote::DrawTarget {
|
impl GenericDrawTarget for raqote::DrawTarget {
|
||||||
fn clear_rect(&mut self, rect: &Rect<f32>) {
|
fn clear_rect(&mut self, rect: &Rect<f32>) {
|
||||||
let mut pb = raqote::PathBuilder::new();
|
let mut pb = raqote::PathBuilder::new();
|
||||||
|
@ -237,16 +357,12 @@ impl GenericDrawTarget for raqote::DrawTarget {
|
||||||
);
|
);
|
||||||
let mut options = raqote::DrawOptions::new();
|
let mut options = raqote::DrawOptions::new();
|
||||||
options.blend_mode = raqote::BlendMode::Clear;
|
options.blend_mode = raqote::BlendMode::Clear;
|
||||||
raqote::DrawTarget::fill(
|
let pattern = Pattern::Color(0, 0, 0, 0);
|
||||||
|
GenericDrawTarget::fill(
|
||||||
self,
|
self,
|
||||||
&pb.finish(),
|
&Path::Raqote(pb.finish()),
|
||||||
&raqote::Source::Solid(raqote::SolidSource::from_unpremultiplied_argb(
|
canvas_data::Pattern::Raqote(pattern),
|
||||||
0,
|
&DrawOptions::Raqote(options),
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
)),
|
|
||||||
&options,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
#[allow(unsafe_code)]
|
#[allow(unsafe_code)]
|
||||||
|
@ -262,21 +378,14 @@ impl GenericDrawTarget for raqote::DrawTarget {
|
||||||
dt.get_data_mut().copy_from_slice(s);
|
dt.get_data_mut().copy_from_slice(s);
|
||||||
raqote::DrawTarget::copy_surface(self, &dt, source.to_box2d(), destination);
|
raqote::DrawTarget::copy_surface(self, &dt, source.to_box2d(), destination);
|
||||||
}
|
}
|
||||||
// TODO(pylbrecht)
|
|
||||||
// unused code?
|
|
||||||
fn create_gradient_stops(
|
fn create_gradient_stops(
|
||||||
&self,
|
&self,
|
||||||
gradient_stops: Vec<GradientStop>,
|
gradient_stops: Vec<GradientStop>,
|
||||||
_extend_mode: ExtendMode,
|
_extend_mode: ExtendMode,
|
||||||
) -> GradientStops {
|
) -> GradientStops {
|
||||||
let mut stops = gradient_stops
|
create_gradient_stops(gradient_stops)
|
||||||
.into_iter()
|
|
||||||
.map(|item| item.as_raqote().clone())
|
|
||||||
.collect::<Vec<raqote::GradientStop>>();
|
|
||||||
// https://www.w3.org/html/test/results/2dcontext/annotated-spec/canvas.html#testrefs.2d.gradient.interpolate.overlap
|
|
||||||
stops.sort_by(|a, b| a.position.partial_cmp(&b.position).unwrap());
|
|
||||||
GradientStops::Raqote(stops)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_path_builder(&self) -> Box<dyn GenericPathBuilder> {
|
fn create_path_builder(&self) -> Box<dyn GenericPathBuilder> {
|
||||||
Box::new(PathBuilder::new())
|
Box::new(PathBuilder::new())
|
||||||
}
|
}
|
||||||
|
@ -322,21 +431,15 @@ impl GenericDrawTarget for raqote::DrawTarget {
|
||||||
dest.size.width as f32,
|
dest.size.width as f32,
|
||||||
dest.size.height as f32,
|
dest.size.height as f32,
|
||||||
);
|
);
|
||||||
let source = raqote::Source::Image(
|
let pattern = Pattern::Surface(SurfacePattern::new(
|
||||||
image,
|
image,
|
||||||
raqote::ExtendMode::Pad,
|
|
||||||
filter.to_raqote(),
|
filter.to_raqote(),
|
||||||
raqote::Transform::create_translation(-dest.origin.x as f32, -dest.origin.y as f32)
|
Repetition::NoRepeat,
|
||||||
.post_scale(
|
));
|
||||||
image.width as f32 / dest.size.width as f32,
|
|
||||||
image.height as f32 / dest.size.height as f32,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
GenericDrawTarget::fill(
|
GenericDrawTarget::fill(
|
||||||
self,
|
self,
|
||||||
&Path::Raqote(pb.finish()),
|
&Path::Raqote(pb.finish()),
|
||||||
Pattern::Raqote(source, None),
|
canvas_data::Pattern::Raqote(pattern),
|
||||||
draw_options,
|
draw_options,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -351,11 +454,15 @@ impl GenericDrawTarget for raqote::DrawTarget {
|
||||||
) {
|
) {
|
||||||
warn!("no support for drawing shadows");
|
warn!("no support for drawing shadows");
|
||||||
}
|
}
|
||||||
fn fill(&mut self, path: &Path, pattern: Pattern, draw_options: &DrawOptions) {
|
fn fill(&mut self, path: &Path, pattern: canvas_data::Pattern, draw_options: &DrawOptions) {
|
||||||
match draw_options.as_raqote().blend_mode {
|
match draw_options.as_raqote().blend_mode {
|
||||||
raqote::BlendMode::Src => {
|
raqote::BlendMode::Src => {
|
||||||
self.clear(raqote::SolidSource::from_unpremultiplied_argb(0, 0, 0, 0));
|
self.clear(raqote::SolidSource::from_unpremultiplied_argb(0, 0, 0, 0));
|
||||||
self.fill(path.as_raqote(), pattern.source(), draw_options.as_raqote());
|
self.fill(
|
||||||
|
path.as_raqote(),
|
||||||
|
&pattern.source(),
|
||||||
|
draw_options.as_raqote(),
|
||||||
|
);
|
||||||
},
|
},
|
||||||
raqote::BlendMode::SrcAtop |
|
raqote::BlendMode::SrcAtop |
|
||||||
raqote::BlendMode::DstOut |
|
raqote::BlendMode::DstOut |
|
||||||
|
@ -363,7 +470,11 @@ impl GenericDrawTarget for raqote::DrawTarget {
|
||||||
raqote::BlendMode::Xor |
|
raqote::BlendMode::Xor |
|
||||||
raqote::BlendMode::DstOver |
|
raqote::BlendMode::DstOver |
|
||||||
raqote::BlendMode::SrcOver => {
|
raqote::BlendMode::SrcOver => {
|
||||||
self.fill(path.as_raqote(), pattern.source(), draw_options.as_raqote());
|
self.fill(
|
||||||
|
path.as_raqote(),
|
||||||
|
&pattern.source(),
|
||||||
|
draw_options.as_raqote(),
|
||||||
|
);
|
||||||
},
|
},
|
||||||
raqote::BlendMode::SrcIn |
|
raqote::BlendMode::SrcIn |
|
||||||
raqote::BlendMode::SrcOut |
|
raqote::BlendMode::SrcOut |
|
||||||
|
@ -372,7 +483,7 @@ impl GenericDrawTarget for raqote::DrawTarget {
|
||||||
let mut options = draw_options.as_raqote().clone();
|
let mut options = draw_options.as_raqote().clone();
|
||||||
self.push_layer_with_blend(1., options.blend_mode);
|
self.push_layer_with_blend(1., options.blend_mode);
|
||||||
options.blend_mode = raqote::BlendMode::SrcOver;
|
options.blend_mode = raqote::BlendMode::SrcOver;
|
||||||
self.fill(path.as_raqote(), pattern.source(), &options);
|
self.fill(path.as_raqote(), &pattern.source(), &options);
|
||||||
self.pop_layer();
|
self.pop_layer();
|
||||||
},
|
},
|
||||||
_ => warn!(
|
_ => warn!(
|
||||||
|
@ -384,7 +495,7 @@ impl GenericDrawTarget for raqote::DrawTarget {
|
||||||
fn fill_rect(
|
fn fill_rect(
|
||||||
&mut self,
|
&mut self,
|
||||||
rect: &Rect<f32>,
|
rect: &Rect<f32>,
|
||||||
pattern: Pattern,
|
pattern: canvas_data::Pattern,
|
||||||
draw_options: Option<&DrawOptions>,
|
draw_options: Option<&DrawOptions>,
|
||||||
) {
|
) {
|
||||||
let mut pb = raqote::PathBuilder::new();
|
let mut pb = raqote::PathBuilder::new();
|
||||||
|
@ -431,13 +542,13 @@ impl GenericDrawTarget for raqote::DrawTarget {
|
||||||
fn stroke(
|
fn stroke(
|
||||||
&mut self,
|
&mut self,
|
||||||
path: &Path,
|
path: &Path,
|
||||||
pattern: Pattern,
|
pattern: canvas_data::Pattern,
|
||||||
stroke_options: &StrokeOptions,
|
stroke_options: &StrokeOptions,
|
||||||
draw_options: &DrawOptions,
|
draw_options: &DrawOptions,
|
||||||
) {
|
) {
|
||||||
self.stroke(
|
self.stroke(
|
||||||
path.as_raqote(),
|
path.as_raqote(),
|
||||||
pattern.source(),
|
&pattern.source(),
|
||||||
stroke_options.as_raqote(),
|
stroke_options.as_raqote(),
|
||||||
draw_options.as_raqote(),
|
draw_options.as_raqote(),
|
||||||
);
|
);
|
||||||
|
@ -446,7 +557,7 @@ impl GenericDrawTarget for raqote::DrawTarget {
|
||||||
&mut self,
|
&mut self,
|
||||||
start: Point2D<f32>,
|
start: Point2D<f32>,
|
||||||
end: Point2D<f32>,
|
end: Point2D<f32>,
|
||||||
pattern: Pattern,
|
pattern: canvas_data::Pattern,
|
||||||
stroke_options: &StrokeOptions,
|
stroke_options: &StrokeOptions,
|
||||||
draw_options: &DrawOptions,
|
draw_options: &DrawOptions,
|
||||||
) {
|
) {
|
||||||
|
@ -462,7 +573,7 @@ impl GenericDrawTarget for raqote::DrawTarget {
|
||||||
|
|
||||||
self.stroke(
|
self.stroke(
|
||||||
&pb.finish(),
|
&pb.finish(),
|
||||||
pattern.source(),
|
&pattern.source(),
|
||||||
&stroke_options,
|
&stroke_options,
|
||||||
draw_options.as_raqote(),
|
draw_options.as_raqote(),
|
||||||
);
|
);
|
||||||
|
@ -470,7 +581,7 @@ impl GenericDrawTarget for raqote::DrawTarget {
|
||||||
fn stroke_rect(
|
fn stroke_rect(
|
||||||
&mut self,
|
&mut self,
|
||||||
rect: &Rect<f32>,
|
rect: &Rect<f32>,
|
||||||
pattern: Pattern,
|
pattern: canvas_data::Pattern,
|
||||||
stroke_options: &StrokeOptions,
|
stroke_options: &StrokeOptions,
|
||||||
draw_options: &DrawOptions,
|
draw_options: &DrawOptions,
|
||||||
) {
|
) {
|
||||||
|
@ -484,7 +595,7 @@ impl GenericDrawTarget for raqote::DrawTarget {
|
||||||
|
|
||||||
self.stroke(
|
self.stroke(
|
||||||
&pb.finish(),
|
&pb.finish(),
|
||||||
pattern.source(),
|
&pattern.source(),
|
||||||
stroke_options.as_raqote(),
|
stroke_options.as_raqote(),
|
||||||
draw_options.as_raqote(),
|
draw_options.as_raqote(),
|
||||||
);
|
);
|
||||||
|
@ -711,8 +822,8 @@ impl ToRaqoteStyle for LineCapStyle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ToRaqoteSource<'a> {
|
pub trait ToRaqotePattern<'a> {
|
||||||
fn to_raqote_source(self) -> Option<Pattern<'a>>;
|
fn to_raqote_pattern(self) -> Option<Pattern<'a>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ToRaqoteGradientStop {
|
pub trait ToRaqoteGradientStop {
|
||||||
|
@ -732,88 +843,64 @@ impl ToRaqoteGradientStop for CanvasGradientStop {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ToRaqoteSource<'a> for FillOrStrokeStyle {
|
impl<'a> ToRaqotePattern<'_> for FillOrStrokeStyle {
|
||||||
#[allow(unsafe_code)]
|
#[allow(unsafe_code)]
|
||||||
fn to_raqote_source(self) -> Option<Pattern<'a>> {
|
fn to_raqote_pattern(self) -> Option<Pattern<'static>> {
|
||||||
use canvas_traits::canvas::FillOrStrokeStyle::*;
|
use canvas_traits::canvas::FillOrStrokeStyle::*;
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
Color(rgba) => Some(Pattern::Raqote(raqote::Source::Solid(
|
Color(color) => Some(Pattern::Color(
|
||||||
raqote::SolidSource::from_unpremultiplied_argb(
|
color.alpha,
|
||||||
rgba.alpha, rgba.red, rgba.green, rgba.blue,
|
color.red,
|
||||||
),
|
color.green,
|
||||||
), None)),
|
color.blue,
|
||||||
|
)),
|
||||||
LinearGradient(style) => {
|
LinearGradient(style) => {
|
||||||
let mut stops: Vec<raqote::GradientStop> =
|
|
||||||
style.stops.into_iter().map(|s| s.to_raqote()).collect();
|
|
||||||
// https://www.w3.org/html/test/results/2dcontext/annotated-spec/canvas.html#testrefs.2d.gradient.interpolate.overlap
|
|
||||||
stops.sort_by(|a, b| a.position.partial_cmp(&b.position).unwrap());
|
|
||||||
let mut gradient = raqote::Gradient { stops };
|
|
||||||
let start = Point2D::new(style.x0 as f32, style.y0 as f32);
|
let start = Point2D::new(style.x0 as f32, style.y0 as f32);
|
||||||
let end = Point2D::new(style.x1 as f32, style.y1 as f32);
|
let end = Point2D::new(style.x1 as f32, style.y1 as f32);
|
||||||
if start == end {
|
let mut stops = style
|
||||||
// TODO
|
.stops
|
||||||
// hack to make Pattern::is_zero_size_gradient() return true
|
.iter()
|
||||||
gradient.stops.clear();
|
.map(|s| s.to_raqote())
|
||||||
}
|
.collect::<Vec<raqote::GradientStop>>();
|
||||||
Some(Pattern::Raqote(raqote::Source::new_linear_gradient(
|
stops.sort_by(|a, b| a.position.partial_cmp(&b.position).unwrap());
|
||||||
gradient,
|
Some(Pattern::LinearGradient(LinearGradientPattern::new(
|
||||||
start,
|
start, end, stops,
|
||||||
end,
|
)))
|
||||||
raqote::Spread::Pad,
|
|
||||||
), None))
|
|
||||||
},
|
},
|
||||||
RadialGradient(style) => {
|
RadialGradient(style) => {
|
||||||
let stops = style.stops.into_iter().map(|s| s.to_raqote()).collect();
|
|
||||||
let mut gradient = raqote::Gradient { stops };
|
|
||||||
let center1 = Point2D::new(style.x0 as f32, style.y0 as f32);
|
let center1 = Point2D::new(style.x0 as f32, style.y0 as f32);
|
||||||
let center2 = Point2D::new(style.x1 as f32, style.y1 as f32);
|
let center2 = Point2D::new(style.x1 as f32, style.y1 as f32);
|
||||||
let equal_centers = center1 == center2;
|
let mut stops = style
|
||||||
let equal_radius = style.r0 == style.r1;
|
.stops
|
||||||
if equal_centers && equal_radius {
|
.iter()
|
||||||
// TODO
|
.map(|s| s.to_raqote())
|
||||||
// hack to make Pattern::is_zero_size_gradient() return true
|
.collect::<Vec<raqote::GradientStop>>();
|
||||||
gradient.stops.clear();
|
stops.sort_by(|a, b| a.position.partial_cmp(&b.position).unwrap());
|
||||||
}
|
Some(Pattern::RadialGradient(RadialGradientPattern::new(
|
||||||
Some(Pattern::Raqote(raqote::Source::new_two_circle_radial_gradient(
|
|
||||||
gradient,
|
|
||||||
center1,
|
center1,
|
||||||
style.r0 as f32,
|
style.r0 as f32,
|
||||||
center2,
|
center2,
|
||||||
style.r1 as f32,
|
style.r1 as f32,
|
||||||
raqote::Spread::Pad,
|
stops,
|
||||||
), None))
|
)))
|
||||||
},
|
},
|
||||||
Surface(ref style) => {
|
Surface(ref style) => {
|
||||||
let repetition = if style.repeat_x && style.repeat_y {
|
let repeat = Repetition::from_xy(style.repeat_x, style.repeat_y);
|
||||||
Repetition::Repeat
|
|
||||||
} else if style.repeat_x {
|
|
||||||
Repetition::RepeatX
|
|
||||||
} else if style.repeat_y {
|
|
||||||
Repetition::RepeatY
|
|
||||||
} else {
|
|
||||||
Repetition::NoRepeat
|
|
||||||
};
|
|
||||||
|
|
||||||
let extend = if style.repeat_x || style.repeat_y {
|
|
||||||
raqote::ExtendMode::Repeat
|
|
||||||
} else {
|
|
||||||
raqote::ExtendMode::Pad
|
|
||||||
};
|
|
||||||
|
|
||||||
let data = &style.surface_data[..];
|
let data = &style.surface_data[..];
|
||||||
Some(Pattern::Raqote(raqote::Source::Image(
|
|
||||||
raqote::Image {
|
let image = raqote::Image {
|
||||||
data: unsafe {
|
width: style.surface_size.width as i32,
|
||||||
std::slice::from_raw_parts(data.as_ptr() as *const u32, data.len() / 4)
|
height: style.surface_size.height as i32,
|
||||||
},
|
data: unsafe {
|
||||||
width: style.surface_size.width as i32,
|
std::slice::from_raw_parts(data.as_ptr() as *const u32, data.len() / 4)
|
||||||
height: style.surface_size.height as i32,
|
|
||||||
},
|
},
|
||||||
extend,
|
};
|
||||||
raqote::FilterMode::Bilinear,
|
Some(Pattern::Surface(SurfacePattern::new(
|
||||||
raqote::Transform::identity(),
|
image,
|
||||||
), Some(repetition)))
|
raqote::FilterMode::Nearest,
|
||||||
|
repeat,
|
||||||
|
)))
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -831,12 +918,7 @@ impl ToRaqoteStyle for RGBA {
|
||||||
type Target = raqote::SolidSource;
|
type Target = raqote::SolidSource;
|
||||||
|
|
||||||
fn to_raqote_style(self) -> Self::Target {
|
fn to_raqote_style(self) -> Self::Target {
|
||||||
raqote::SolidSource::from_unpremultiplied_argb(
|
raqote::SolidSource::from_unpremultiplied_argb(self.alpha, self.red, self.green, self.blue)
|
||||||
self.alpha,
|
|
||||||
self.red,
|
|
||||||
self.green,
|
|
||||||
self.blue,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue