mirror of
https://github.com/servo/servo.git
synced 2025-08-05 05:30:08 +01:00
Auto merge of #5731 - mmatyas:canvas_saverestore, r=jdm
This patch enables the use of `save()` and `restore()` for the canvas context, which is used by *a lot* of sites and scripts. Depends on servo/rust-azure#153. <!-- Reviewable:start --> [<img src="https://reviewable.io/review_button.png" height=40 alt="Review on Reviewable"/>](https://reviewable.io/reviews/servo/servo/5731) <!-- Reviewable:end -->
This commit is contained in:
commit
9c7c289aca
21 changed files with 157 additions and 165 deletions
|
@ -16,11 +16,14 @@ use util::vec::byte_swap;
|
||||||
|
|
||||||
use cssparser::RGBA;
|
use cssparser::RGBA;
|
||||||
use std::borrow::ToOwned;
|
use std::borrow::ToOwned;
|
||||||
|
use std::mem;
|
||||||
use std::num::{Float, ToPrimitive};
|
use std::num::{Float, ToPrimitive};
|
||||||
use std::sync::mpsc::{channel, Sender};
|
use std::sync::mpsc::{channel, Sender};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub enum CanvasMsg {
|
pub enum CanvasMsg {
|
||||||
|
SaveContext,
|
||||||
|
RestoreContext,
|
||||||
FillRect(Rect<f32>),
|
FillRect(Rect<f32>),
|
||||||
ClearRect(Rect<f32>),
|
ClearRect(Rect<f32>),
|
||||||
StrokeRect(Rect<f32>),
|
StrokeRect(Rect<f32>),
|
||||||
|
@ -109,7 +112,7 @@ impl<'a> CanvasPaintTask<'a> {
|
||||||
image_size, image_size.width * 4, SurfaceFormat::B8G8R8A8);
|
image_size, image_size.width * 4, SurfaceFormat::B8G8R8A8);
|
||||||
|
|
||||||
let draw_surface_options = DrawSurfaceOptions::new(filter, true);
|
let draw_surface_options = DrawSurfaceOptions::new(filter, true);
|
||||||
let draw_options = DrawOptions::new(self.draw_options.alpha, 0);
|
let draw_options = DrawOptions::new(self.state.draw_options.alpha, 0);
|
||||||
|
|
||||||
self.drawtarget.draw_surface(source_surface,
|
self.drawtarget.draw_surface(source_surface,
|
||||||
dest_rect.to_azfloat(),
|
dest_rect.to_azfloat(),
|
||||||
|
@ -186,28 +189,43 @@ impl<'a> CanvasPaintTask<'a> {
|
||||||
|
|
||||||
pub struct CanvasPaintTask<'a> {
|
pub struct CanvasPaintTask<'a> {
|
||||||
drawtarget: DrawTarget,
|
drawtarget: DrawTarget,
|
||||||
|
/// TODO(pcwalton): Support multiple paths.
|
||||||
|
path_builder: PathBuilder,
|
||||||
|
state: CanvasPaintState<'a>,
|
||||||
|
saved_states: Vec<CanvasPaintState<'a>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct CanvasPaintState<'a> {
|
||||||
draw_options: DrawOptions,
|
draw_options: DrawOptions,
|
||||||
fill_style: Pattern,
|
fill_style: Pattern,
|
||||||
stroke_style: Pattern,
|
stroke_style: Pattern,
|
||||||
stroke_opts: StrokeOptions<'a>,
|
stroke_opts: StrokeOptions<'a>,
|
||||||
/// TODO(pcwalton): Support multiple paths.
|
|
||||||
path_builder: PathBuilder,
|
|
||||||
/// The current 2D transform matrix.
|
/// The current 2D transform matrix.
|
||||||
transform: Matrix2D<f32>,
|
transform: Matrix2D<f32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a> CanvasPaintState<'a> {
|
||||||
|
fn new() -> CanvasPaintState<'a> {
|
||||||
|
CanvasPaintState {
|
||||||
|
draw_options: DrawOptions::new(1.0, 0),
|
||||||
|
fill_style: Pattern::Color(ColorPattern::new(color::black())),
|
||||||
|
stroke_style: Pattern::Color(ColorPattern::new(color::black())),
|
||||||
|
stroke_opts: StrokeOptions::new(1.0, JoinStyle::MiterOrBevel, CapStyle::Butt, 10.0, &[]),
|
||||||
|
transform: Matrix2D::identity(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a> CanvasPaintTask<'a> {
|
impl<'a> CanvasPaintTask<'a> {
|
||||||
fn new(size: Size2D<i32>) -> CanvasPaintTask<'a> {
|
fn new(size: Size2D<i32>) -> CanvasPaintTask<'a> {
|
||||||
let draw_target = CanvasPaintTask::create(size);
|
let draw_target = CanvasPaintTask::create(size);
|
||||||
let path_builder = draw_target.create_path_builder();
|
let path_builder = draw_target.create_path_builder();
|
||||||
CanvasPaintTask {
|
CanvasPaintTask {
|
||||||
drawtarget: draw_target,
|
drawtarget: draw_target,
|
||||||
draw_options: DrawOptions::new(1.0, 0),
|
|
||||||
fill_style: Pattern::Color(ColorPattern::new(color::black())),
|
|
||||||
stroke_style: Pattern::Color(ColorPattern::new(color::black())),
|
|
||||||
stroke_opts: StrokeOptions::new(1.0, JoinStyle::MiterOrBevel, CapStyle::Butt, 10.0, &[]),
|
|
||||||
path_builder: path_builder,
|
path_builder: path_builder,
|
||||||
transform: Matrix2D::identity(),
|
state: CanvasPaintState::new(),
|
||||||
|
saved_states: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -218,6 +236,8 @@ impl<'a> CanvasPaintTask<'a> {
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
match port.recv().unwrap() {
|
match port.recv().unwrap() {
|
||||||
|
CanvasMsg::SaveContext => painter.save_context_state(),
|
||||||
|
CanvasMsg::RestoreContext => painter.restore_context_state(),
|
||||||
CanvasMsg::FillRect(ref rect) => painter.fill_rect(rect),
|
CanvasMsg::FillRect(ref rect) => painter.fill_rect(rect),
|
||||||
CanvasMsg::StrokeRect(ref rect) => painter.stroke_rect(rect),
|
CanvasMsg::StrokeRect(ref rect) => painter.stroke_rect(rect),
|
||||||
CanvasMsg::ClearRect(ref rect) => painter.clear_rect(rect),
|
CanvasMsg::ClearRect(ref rect) => painter.clear_rect(rect),
|
||||||
|
@ -265,8 +285,20 @@ impl<'a> CanvasPaintTask<'a> {
|
||||||
chan
|
chan
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn save_context_state(&mut self) {
|
||||||
|
self.saved_states.push(self.state.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn restore_context_state(&mut self) {
|
||||||
|
if let Some(state) = self.saved_states.pop() {
|
||||||
|
mem::replace(&mut self.state, state);
|
||||||
|
self.drawtarget.set_transform(&self.state.transform);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn fill_rect(&self, rect: &Rect<f32>) {
|
fn fill_rect(&self, rect: &Rect<f32>) {
|
||||||
self.drawtarget.fill_rect(rect, self.fill_style.to_pattern_ref(), Some(&self.draw_options));
|
self.drawtarget.fill_rect(rect, self.state.fill_style.to_pattern_ref(),
|
||||||
|
Some(&self.state.draw_options));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clear_rect(&self, rect: &Rect<f32>) {
|
fn clear_rect(&self, rect: &Rect<f32>) {
|
||||||
|
@ -274,9 +306,9 @@ impl<'a> CanvasPaintTask<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn stroke_rect(&self, rect: &Rect<f32>) {
|
fn stroke_rect(&self, rect: &Rect<f32>) {
|
||||||
match self.stroke_style {
|
match self.state.stroke_style {
|
||||||
Pattern::Color(ref color) => {
|
Pattern::Color(ref color) => {
|
||||||
self.drawtarget.stroke_rect(rect, color, &self.stroke_opts, &self.draw_options)
|
self.drawtarget.stroke_rect(rect, color, &self.state.stroke_opts, &self.state.draw_options)
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
// TODO(pcwalton)
|
// TODO(pcwalton)
|
||||||
|
@ -293,9 +325,9 @@ impl<'a> CanvasPaintTask<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fill(&self) {
|
fn fill(&self) {
|
||||||
match self.fill_style {
|
match self.state.fill_style {
|
||||||
Pattern::Color(ref color) => {
|
Pattern::Color(ref color) => {
|
||||||
self.drawtarget.fill(&self.path_builder.finish(), color, &self.draw_options);
|
self.drawtarget.fill(&self.path_builder.finish(), color, &self.state.draw_options);
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
// TODO(pcwalton)
|
// TODO(pcwalton)
|
||||||
|
@ -304,10 +336,10 @@ impl<'a> CanvasPaintTask<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn stroke(&self) {
|
fn stroke(&self) {
|
||||||
match self.stroke_style {
|
match self.state.stroke_style {
|
||||||
Pattern::Color(ref color) => {
|
Pattern::Color(ref color) => {
|
||||||
self.drawtarget.stroke(&self.path_builder.finish(),
|
self.drawtarget.stroke(&self.path_builder.finish(),
|
||||||
color, &self.stroke_opts, &self.draw_options);
|
color, &self.state.stroke_opts, &self.state.draw_options);
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
// TODO
|
// TODO
|
||||||
|
@ -420,36 +452,36 @@ impl<'a> CanvasPaintTask<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_fill_style(&mut self, style: FillOrStrokeStyle) {
|
fn set_fill_style(&mut self, style: FillOrStrokeStyle) {
|
||||||
self.fill_style = style.to_azure_pattern(&self.drawtarget)
|
self.state.fill_style = style.to_azure_pattern(&self.drawtarget)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_stroke_style(&mut self, style: FillOrStrokeStyle) {
|
fn set_stroke_style(&mut self, style: FillOrStrokeStyle) {
|
||||||
self.stroke_style = style.to_azure_pattern(&self.drawtarget)
|
self.state.stroke_style = style.to_azure_pattern(&self.drawtarget)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_line_width(&mut self, width: f32) {
|
fn set_line_width(&mut self, width: f32) {
|
||||||
self.stroke_opts.line_width = width;
|
self.state.stroke_opts.line_width = width;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_line_cap(&mut self, cap: LineCapStyle) {
|
fn set_line_cap(&mut self, cap: LineCapStyle) {
|
||||||
self.stroke_opts.line_cap = cap.to_azure_style();
|
self.state.stroke_opts.line_cap = cap.to_azure_style();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_line_join(&mut self, join: LineJoinStyle) {
|
fn set_line_join(&mut self, join: LineJoinStyle) {
|
||||||
self.stroke_opts.line_join = join.to_azure_style();
|
self.state.stroke_opts.line_join = join.to_azure_style();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_miter_limit(&mut self, limit: f32) {
|
fn set_miter_limit(&mut self, limit: f32) {
|
||||||
self.stroke_opts.miter_limit = limit;
|
self.state.stroke_opts.miter_limit = limit;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_transform(&mut self, transform: &Matrix2D<f32>) {
|
fn set_transform(&mut self, transform: &Matrix2D<f32>) {
|
||||||
self.transform = *transform;
|
self.state.transform = *transform;
|
||||||
self.drawtarget.set_transform(transform)
|
self.drawtarget.set_transform(transform)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_global_alpha(&mut self, alpha: f32) {
|
fn set_global_alpha(&mut self, alpha: f32) {
|
||||||
self.draw_options.alpha = alpha;
|
self.state.draw_options.alpha = alpha;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create(size: Size2D<i32>) -> DrawTarget {
|
fn create(size: Size2D<i32>) -> DrawTarget {
|
||||||
|
|
|
@ -36,7 +36,7 @@ use net_traits::image_cache_task::{ImageResponseMsg, Msg};
|
||||||
use png::PixelsByColorType;
|
use png::PixelsByColorType;
|
||||||
|
|
||||||
use std::borrow::ToOwned;
|
use std::borrow::ToOwned;
|
||||||
use std::cell::Cell;
|
use std::cell::RefCell;
|
||||||
use std::num::{Float, ToPrimitive};
|
use std::num::{Float, ToPrimitive};
|
||||||
use std::sync::{Arc};
|
use std::sync::{Arc};
|
||||||
use std::sync::mpsc::{channel, Sender};
|
use std::sync::mpsc::{channel, Sender};
|
||||||
|
@ -52,40 +52,56 @@ pub struct CanvasRenderingContext2D {
|
||||||
global: GlobalField,
|
global: GlobalField,
|
||||||
renderer: Sender<CanvasMsg>,
|
renderer: Sender<CanvasMsg>,
|
||||||
canvas: JS<HTMLCanvasElement>,
|
canvas: JS<HTMLCanvasElement>,
|
||||||
global_alpha: Cell<f64>,
|
state: RefCell<CanvasContextState>,
|
||||||
image_smoothing_enabled: Cell<bool>,
|
saved_states: RefCell<Vec<CanvasContextState>>,
|
||||||
stroke_color: Cell<RGBA>,
|
|
||||||
line_width: Cell<f64>,
|
|
||||||
line_cap: Cell<LineCapStyle>,
|
|
||||||
line_join: Cell<LineJoinStyle>,
|
|
||||||
miter_limit: Cell<f64>,
|
|
||||||
fill_color: Cell<RGBA>,
|
|
||||||
transform: Cell<Matrix2D<f32>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CanvasRenderingContext2D {
|
#[derive(Clone)]
|
||||||
fn new_inherited(global: GlobalRef, canvas: JSRef<HTMLCanvasElement>, size: Size2D<i32>)
|
#[jstraceable]
|
||||||
-> CanvasRenderingContext2D {
|
struct CanvasContextState {
|
||||||
|
global_alpha: f64,
|
||||||
|
image_smoothing_enabled: bool,
|
||||||
|
stroke_color: RGBA,
|
||||||
|
line_width: f64,
|
||||||
|
line_cap: LineCapStyle,
|
||||||
|
line_join: LineJoinStyle,
|
||||||
|
miter_limit: f64,
|
||||||
|
fill_color: RGBA,
|
||||||
|
transform: Matrix2D<f32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CanvasContextState {
|
||||||
|
fn new() -> CanvasContextState {
|
||||||
let black = RGBA {
|
let black = RGBA {
|
||||||
red: 0.0,
|
red: 0.0,
|
||||||
green: 0.0,
|
green: 0.0,
|
||||||
blue: 0.0,
|
blue: 0.0,
|
||||||
alpha: 1.0,
|
alpha: 1.0,
|
||||||
};
|
};
|
||||||
|
CanvasContextState {
|
||||||
|
global_alpha: 1.0,
|
||||||
|
image_smoothing_enabled: true,
|
||||||
|
stroke_color: black,
|
||||||
|
line_width: 1.0,
|
||||||
|
line_cap: LineCapStyle::Butt,
|
||||||
|
line_join: LineJoinStyle::Miter,
|
||||||
|
miter_limit: 10.0,
|
||||||
|
fill_color: black,
|
||||||
|
transform: Matrix2D::identity(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CanvasRenderingContext2D {
|
||||||
|
fn new_inherited(global: GlobalRef, canvas: JSRef<HTMLCanvasElement>, size: Size2D<i32>)
|
||||||
|
-> CanvasRenderingContext2D {
|
||||||
CanvasRenderingContext2D {
|
CanvasRenderingContext2D {
|
||||||
reflector_: Reflector::new(),
|
reflector_: Reflector::new(),
|
||||||
global: GlobalField::from_rooted(&global),
|
global: GlobalField::from_rooted(&global),
|
||||||
renderer: CanvasPaintTask::start(size),
|
renderer: CanvasPaintTask::start(size),
|
||||||
canvas: JS::from_rooted(canvas),
|
canvas: JS::from_rooted(canvas),
|
||||||
global_alpha: Cell::new(1.0),
|
state: RefCell::new(CanvasContextState::new()),
|
||||||
image_smoothing_enabled: Cell::new(true),
|
saved_states: RefCell::new(Vec::new()),
|
||||||
stroke_color: Cell::new(black),
|
|
||||||
line_width: Cell::new(1.0),
|
|
||||||
line_cap: Cell::new(LineCapStyle::Butt),
|
|
||||||
line_join: Cell::new(LineJoinStyle::Miter),
|
|
||||||
miter_limit: Cell::new(10.0),
|
|
||||||
fill_color: Cell::new(black),
|
|
||||||
transform: Cell::new(Matrix2D::identity()),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,7 +116,7 @@ impl CanvasRenderingContext2D {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_transform(&self) {
|
fn update_transform(&self) {
|
||||||
self.renderer.send(CanvasMsg::SetTransform(self.transform.get())).unwrap()
|
self.renderer.send(CanvasMsg::SetTransform(self.state.borrow().transform)).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
// It is used by DrawImage to calculate the size of the source and destination rectangles based
|
// It is used by DrawImage to calculate the size of the source and destination rectangles based
|
||||||
|
@ -184,7 +200,7 @@ impl CanvasRenderingContext2D {
|
||||||
return Err(IndexSize)
|
return Err(IndexSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
let smoothing_enabled = self.image_smoothing_enabled.get();
|
let smoothing_enabled = self.state.borrow().image_smoothing_enabled;
|
||||||
|
|
||||||
// If the source and target canvas are the same
|
// If the source and target canvas are the same
|
||||||
let msg = if self.canvas.root().r() == canvas {
|
let msg = if self.canvas.root().r() == canvas {
|
||||||
|
@ -216,7 +232,7 @@ impl CanvasRenderingContext2D {
|
||||||
return Err(IndexSize)
|
return Err(IndexSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
let smoothing_enabled = self.image_smoothing_enabled.get();
|
let smoothing_enabled = self.state.borrow().image_smoothing_enabled;
|
||||||
self.renderer.send(CanvasMsg::DrawImage(
|
self.renderer.send(CanvasMsg::DrawImage(
|
||||||
image_data, image_size, dest_rect,
|
image_data, image_size, dest_rect,
|
||||||
source_rect, smoothing_enabled)).unwrap();
|
source_rect, smoothing_enabled)).unwrap();
|
||||||
|
@ -318,13 +334,29 @@ impl<'a> CanvasRenderingContext2DMethods for JSRef<'a, CanvasRenderingContext2D>
|
||||||
Temporary::new(self.canvas)
|
Temporary::new(self.canvas)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://html.spec.whatwg.org/multipage/#dom-context-2d-save
|
||||||
|
fn Save(self) {
|
||||||
|
self.saved_states.borrow_mut().push(self.state.borrow().clone());
|
||||||
|
self.renderer.send(CanvasMsg::SaveContext).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://html.spec.whatwg.org/multipage/#dom-context-2d-restore
|
||||||
|
fn Restore(self) {
|
||||||
|
let mut saved_states = self.saved_states.borrow_mut();
|
||||||
|
if let Some(state) = saved_states.pop() {
|
||||||
|
self.state.borrow_mut().clone_from(&state);
|
||||||
|
self.renderer.send(CanvasMsg::RestoreContext).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-scale
|
// https://html.spec.whatwg.org/multipage/#dom-context-2d-scale
|
||||||
fn Scale(self, x: f64, y: f64) {
|
fn Scale(self, x: f64, y: f64) {
|
||||||
if !(x.is_finite() && y.is_finite()) {
|
if !(x.is_finite() && y.is_finite()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.transform.set(self.transform.get().scale(x as f32, y as f32));
|
let transform = self.state.borrow().transform;
|
||||||
|
self.state.borrow_mut().transform = transform.scale(x as f32, y as f32);
|
||||||
self.update_transform()
|
self.update_transform()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -334,7 +366,8 @@ impl<'a> CanvasRenderingContext2DMethods for JSRef<'a, CanvasRenderingContext2D>
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.transform.set(self.transform.get().translate(x as f32, y as f32));
|
let transform = self.state.borrow().transform;
|
||||||
|
self.state.borrow_mut().transform = transform.translate(x as f32, y as f32);
|
||||||
self.update_transform()
|
self.update_transform()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -345,12 +378,13 @@ impl<'a> CanvasRenderingContext2DMethods for JSRef<'a, CanvasRenderingContext2D>
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.transform.set(self.transform.get().mul(&Matrix2D::new(a as f32,
|
let transform = self.state.borrow().transform;
|
||||||
b as f32,
|
self.state.borrow_mut().transform = transform.mul(&Matrix2D::new(a as f32,
|
||||||
c as f32,
|
b as f32,
|
||||||
d as f32,
|
c as f32,
|
||||||
e as f32,
|
d as f32,
|
||||||
f as f32)));
|
e as f32,
|
||||||
|
f as f32));
|
||||||
self.update_transform()
|
self.update_transform()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -361,18 +395,19 @@ impl<'a> CanvasRenderingContext2DMethods for JSRef<'a, CanvasRenderingContext2D>
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.transform.set(Matrix2D::new(a as f32,
|
self.state.borrow_mut().transform = Matrix2D::new(a as f32,
|
||||||
b as f32,
|
b as f32,
|
||||||
c as f32,
|
c as f32,
|
||||||
d as f32,
|
d as f32,
|
||||||
e as f32,
|
e as f32,
|
||||||
f as f32));
|
f as f32);
|
||||||
self.update_transform()
|
self.update_transform()
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-globalalpha
|
// https://html.spec.whatwg.org/multipage/#dom-context-2d-globalalpha
|
||||||
fn GlobalAlpha(self) -> f64 {
|
fn GlobalAlpha(self) -> f64 {
|
||||||
self.global_alpha.get()
|
let state = self.state.borrow();
|
||||||
|
state.global_alpha
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-globalalpha
|
// https://html.spec.whatwg.org/multipage/#dom-context-2d-globalalpha
|
||||||
|
@ -381,7 +416,7 @@ impl<'a> CanvasRenderingContext2DMethods for JSRef<'a, CanvasRenderingContext2D>
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.global_alpha.set(alpha);
|
self.state.borrow_mut().global_alpha = alpha;
|
||||||
self.renderer.send(CanvasMsg::SetGlobalAlpha(alpha as f32)).unwrap()
|
self.renderer.send(CanvasMsg::SetGlobalAlpha(alpha as f32)).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -661,12 +696,13 @@ impl<'a> CanvasRenderingContext2DMethods for JSRef<'a, CanvasRenderingContext2D>
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/#dom-context-2d-imagesmoothingenabled
|
// https://html.spec.whatwg.org/#dom-context-2d-imagesmoothingenabled
|
||||||
fn ImageSmoothingEnabled(self) -> bool {
|
fn ImageSmoothingEnabled(self) -> bool {
|
||||||
self.image_smoothing_enabled.get()
|
let state = self.state.borrow();
|
||||||
|
state.image_smoothing_enabled
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/#dom-context-2d-imagesmoothingenabled
|
// https://html.spec.whatwg.org/#dom-context-2d-imagesmoothingenabled
|
||||||
fn SetImageSmoothingEnabled(self, value: bool) -> () {
|
fn SetImageSmoothingEnabled(self, value: bool) -> () {
|
||||||
self.image_smoothing_enabled.set(value);
|
self.state.borrow_mut().image_smoothing_enabled = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-strokestyle
|
// https://html.spec.whatwg.org/multipage/#dom-context-2d-strokestyle
|
||||||
|
@ -675,7 +711,7 @@ impl<'a> CanvasRenderingContext2DMethods for JSRef<'a, CanvasRenderingContext2D>
|
||||||
//
|
//
|
||||||
// https://html.spec.whatwg.org/multipage/#serialisation-of-a-colour
|
// https://html.spec.whatwg.org/multipage/#serialisation-of-a-colour
|
||||||
let mut result = String::new();
|
let mut result = String::new();
|
||||||
self.stroke_color.get().to_css(&mut result).unwrap();
|
self.state.borrow().stroke_color.to_css(&mut result).unwrap();
|
||||||
StringOrCanvasGradientOrCanvasPattern::eString(result)
|
StringOrCanvasGradientOrCanvasPattern::eString(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -685,7 +721,7 @@ impl<'a> CanvasRenderingContext2DMethods for JSRef<'a, CanvasRenderingContext2D>
|
||||||
StringOrCanvasGradientOrCanvasPattern::eString(string) => {
|
StringOrCanvasGradientOrCanvasPattern::eString(string) => {
|
||||||
match parse_color(&string) {
|
match parse_color(&string) {
|
||||||
Ok(rgba) => {
|
Ok(rgba) => {
|
||||||
self.stroke_color.set(rgba);
|
self.state.borrow_mut().stroke_color = rgba;
|
||||||
self.renderer
|
self.renderer
|
||||||
.send(CanvasMsg::SetStrokeStyle(FillOrStrokeStyle::Color(rgba)))
|
.send(CanvasMsg::SetStrokeStyle(FillOrStrokeStyle::Color(rgba)))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -705,7 +741,7 @@ impl<'a> CanvasRenderingContext2DMethods for JSRef<'a, CanvasRenderingContext2D>
|
||||||
//
|
//
|
||||||
// https://html.spec.whatwg.org/multipage/#serialisation-of-a-colour
|
// https://html.spec.whatwg.org/multipage/#serialisation-of-a-colour
|
||||||
let mut result = String::new();
|
let mut result = String::new();
|
||||||
self.stroke_color.get().to_css(&mut result).unwrap();
|
self.state.borrow().stroke_color.to_css(&mut result).unwrap();
|
||||||
StringOrCanvasGradientOrCanvasPattern::eString(result)
|
StringOrCanvasGradientOrCanvasPattern::eString(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -715,7 +751,7 @@ impl<'a> CanvasRenderingContext2DMethods for JSRef<'a, CanvasRenderingContext2D>
|
||||||
StringOrCanvasGradientOrCanvasPattern::eString(string) => {
|
StringOrCanvasGradientOrCanvasPattern::eString(string) => {
|
||||||
match parse_color(&string) {
|
match parse_color(&string) {
|
||||||
Ok(rgba) => {
|
Ok(rgba) => {
|
||||||
self.fill_color.set(rgba);
|
self.state.borrow_mut().fill_color = rgba;
|
||||||
self.renderer
|
self.renderer
|
||||||
.send(CanvasMsg::SetFillStyle(FillOrStrokeStyle::Color(rgba)))
|
.send(CanvasMsg::SetFillStyle(FillOrStrokeStyle::Color(rgba)))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
@ -846,7 +882,8 @@ impl<'a> CanvasRenderingContext2DMethods for JSRef<'a, CanvasRenderingContext2D>
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-linewidth
|
// https://html.spec.whatwg.org/multipage/#dom-context-2d-linewidth
|
||||||
fn LineWidth(self) -> f64 {
|
fn LineWidth(self) -> f64 {
|
||||||
self.line_width.get()
|
let state = self.state.borrow();
|
||||||
|
state.line_width
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-linewidth
|
// https://html.spec.whatwg.org/multipage/#dom-context-2d-linewidth
|
||||||
|
@ -855,13 +892,14 @@ impl<'a> CanvasRenderingContext2DMethods for JSRef<'a, CanvasRenderingContext2D>
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.line_width.set(width);
|
self.state.borrow_mut().line_width = width;
|
||||||
self.renderer.send(CanvasMsg::SetLineWidth(width as f32)).unwrap()
|
self.renderer.send(CanvasMsg::SetLineWidth(width as f32)).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-linecap
|
// https://html.spec.whatwg.org/multipage/#dom-context-2d-linecap
|
||||||
fn LineCap(self) -> DOMString {
|
fn LineCap(self) -> DOMString {
|
||||||
match self.line_cap.get() {
|
let state = self.state.borrow();
|
||||||
|
match state.line_cap {
|
||||||
LineCapStyle::Butt => "butt".to_owned(),
|
LineCapStyle::Butt => "butt".to_owned(),
|
||||||
LineCapStyle::Round => "round".to_owned(),
|
LineCapStyle::Round => "round".to_owned(),
|
||||||
LineCapStyle::Square => "square".to_owned(),
|
LineCapStyle::Square => "square".to_owned(),
|
||||||
|
@ -871,14 +909,15 @@ impl<'a> CanvasRenderingContext2DMethods for JSRef<'a, CanvasRenderingContext2D>
|
||||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-linecap
|
// https://html.spec.whatwg.org/multipage/#dom-context-2d-linecap
|
||||||
fn SetLineCap(self, cap_str: DOMString) {
|
fn SetLineCap(self, cap_str: DOMString) {
|
||||||
if let Some(cap) = LineCapStyle::from_str(&cap_str) {
|
if let Some(cap) = LineCapStyle::from_str(&cap_str) {
|
||||||
self.line_cap.set(cap);
|
self.state.borrow_mut().line_cap = cap;
|
||||||
self.renderer.send(CanvasMsg::SetLineCap(cap)).unwrap()
|
self.renderer.send(CanvasMsg::SetLineCap(cap)).unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-linejoin
|
// https://html.spec.whatwg.org/multipage/#dom-context-2d-linejoin
|
||||||
fn LineJoin(self) -> DOMString {
|
fn LineJoin(self) -> DOMString {
|
||||||
match self.line_join.get() {
|
let state = self.state.borrow();
|
||||||
|
match state.line_join {
|
||||||
LineJoinStyle::Round => "round".to_owned(),
|
LineJoinStyle::Round => "round".to_owned(),
|
||||||
LineJoinStyle::Bevel => "bevel".to_owned(),
|
LineJoinStyle::Bevel => "bevel".to_owned(),
|
||||||
LineJoinStyle::Miter => "miter".to_owned(),
|
LineJoinStyle::Miter => "miter".to_owned(),
|
||||||
|
@ -888,14 +927,15 @@ impl<'a> CanvasRenderingContext2DMethods for JSRef<'a, CanvasRenderingContext2D>
|
||||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-linejoin
|
// https://html.spec.whatwg.org/multipage/#dom-context-2d-linejoin
|
||||||
fn SetLineJoin(self, join_str: DOMString) {
|
fn SetLineJoin(self, join_str: DOMString) {
|
||||||
if let Some(join) = LineJoinStyle::from_str(&join_str) {
|
if let Some(join) = LineJoinStyle::from_str(&join_str) {
|
||||||
self.line_join.set(join);
|
self.state.borrow_mut().line_join = join;
|
||||||
self.renderer.send(CanvasMsg::SetLineJoin(join)).unwrap()
|
self.renderer.send(CanvasMsg::SetLineJoin(join)).unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-miterlimit
|
// https://html.spec.whatwg.org/multipage/#dom-context-2d-miterlimit
|
||||||
fn MiterLimit(self) -> f64 {
|
fn MiterLimit(self) -> f64 {
|
||||||
self.miter_limit.get()
|
let state = self.state.borrow();
|
||||||
|
state.miter_limit
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-miterlimit
|
// https://html.spec.whatwg.org/multipage/#dom-context-2d-miterlimit
|
||||||
|
@ -904,7 +944,7 @@ impl<'a> CanvasRenderingContext2DMethods for JSRef<'a, CanvasRenderingContext2D>
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.miter_limit.set(limit);
|
self.state.borrow_mut().miter_limit = limit;
|
||||||
self.renderer.send(CanvasMsg::SetMiterLimit(limit as f32)).unwrap()
|
self.renderer.send(CanvasMsg::SetMiterLimit(limit as f32)).unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,8 +26,8 @@ interface CanvasRenderingContext2D {
|
||||||
//void commit(); // push the image to the output bitmap
|
//void commit(); // push the image to the output bitmap
|
||||||
|
|
||||||
// state
|
// state
|
||||||
//void save(); // push state on state stack
|
void save(); // push state on state stack
|
||||||
//void restore(); // pop state stack and restore state
|
void restore(); // pop state stack and restore state
|
||||||
|
|
||||||
// transformations (default transform is the identity matrix)
|
// transformations (default transform is the identity matrix)
|
||||||
// attribute SVGMatrix currentTransform;
|
// attribute SVGMatrix currentTransform;
|
||||||
|
|
2
components/servo/Cargo.lock
generated
2
components/servo/Cargo.lock
generated
|
@ -35,7 +35,7 @@ source = "git+https://github.com/tomaka/android-rs-glue#5a68056599fb498b0cf3715f
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "azure"
|
name = "azure"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/servo/rust-azure#358fc5da081cf7d0618fae2d9d5582951beb791f"
|
source = "git+https://github.com/servo/rust-azure#3e5daf667a62f702dc16285e923464458bef785f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"core_foundation 0.1.0 (git+https://github.com/servo/rust-core-foundation)",
|
"core_foundation 0.1.0 (git+https://github.com/servo/rust-core-foundation)",
|
||||||
"core_graphics 0.1.0 (git+https://github.com/servo/rust-core-graphics)",
|
"core_graphics 0.1.0 (git+https://github.com/servo/rust-core-graphics)",
|
||||||
|
|
3
ports/cef/Cargo.lock
generated
3
ports/cef/Cargo.lock
generated
|
@ -37,7 +37,7 @@ source = "git+https://github.com/tomaka/android-rs-glue#5a68056599fb498b0cf3715f
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "azure"
|
name = "azure"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/servo/rust-azure#358fc5da081cf7d0618fae2d9d5582951beb791f"
|
source = "git+https://github.com/servo/rust-azure#3e5daf667a62f702dc16285e923464458bef785f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"core_foundation 0.1.0 (git+https://github.com/servo/rust-core-foundation)",
|
"core_foundation 0.1.0 (git+https://github.com/servo/rust-core-foundation)",
|
||||||
"core_graphics 0.1.0 (git+https://github.com/servo/rust-core-graphics)",
|
"core_graphics 0.1.0 (git+https://github.com/servo/rust-core-graphics)",
|
||||||
|
@ -855,6 +855,7 @@ dependencies = [
|
||||||
"bitflags 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bitflags 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"compositing 0.0.1",
|
"compositing 0.0.1",
|
||||||
"devtools 0.0.1",
|
"devtools 0.0.1",
|
||||||
|
"devtools_traits 0.0.1",
|
||||||
"gfx 0.0.1",
|
"gfx 0.0.1",
|
||||||
"glutin_app 0.0.1",
|
"glutin_app 0.0.1",
|
||||||
"layout 0.0.1",
|
"layout 0.0.1",
|
||||||
|
|
3
ports/gonk/Cargo.lock
generated
3
ports/gonk/Cargo.lock
generated
|
@ -26,7 +26,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "azure"
|
name = "azure"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/servo/rust-azure#358fc5da081cf7d0618fae2d9d5582951beb791f"
|
source = "git+https://github.com/servo/rust-azure#3e5daf667a62f702dc16285e923464458bef785f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"core_foundation 0.1.0 (git+https://github.com/servo/rust-core-foundation)",
|
"core_foundation 0.1.0 (git+https://github.com/servo/rust-core-foundation)",
|
||||||
"core_graphics 0.1.0 (git+https://github.com/servo/rust-core-graphics)",
|
"core_graphics 0.1.0 (git+https://github.com/servo/rust-core-graphics)",
|
||||||
|
@ -780,6 +780,7 @@ dependencies = [
|
||||||
"bitflags 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bitflags 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"compositing 0.0.1",
|
"compositing 0.0.1",
|
||||||
"devtools 0.0.1",
|
"devtools 0.0.1",
|
||||||
|
"devtools_traits 0.0.1",
|
||||||
"gfx 0.0.1",
|
"gfx 0.0.1",
|
||||||
"layout 0.0.1",
|
"layout 0.0.1",
|
||||||
"msg 0.0.1",
|
"msg 0.0.1",
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
[2d.line.width.transformed.html]
|
|
||||||
type: testharness
|
|
||||||
[Line stroke widths are affected by scale transformations]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
[2d.state.saverestore.bitmap.html]
|
|
||||||
type: testharness
|
|
||||||
[save()/restore() does not affect the current bitmap]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
[2d.state.saverestore.fillStyle.html]
|
|
||||||
type: testharness
|
|
||||||
[save()/restore() works for fillStyle]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
[2d.state.saverestore.globalAlpha.html]
|
|
||||||
type: testharness
|
|
||||||
[save()/restore() works for globalAlpha]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
[2d.state.saverestore.lineCap.html]
|
|
||||||
type: testharness
|
|
||||||
[save()/restore() works for lineCap]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
[2d.state.saverestore.lineJoin.html]
|
|
||||||
type: testharness
|
|
||||||
[save()/restore() works for lineJoin]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
[2d.state.saverestore.lineWidth.html]
|
|
||||||
type: testharness
|
|
||||||
[save()/restore() works for lineWidth]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
[2d.state.saverestore.miterLimit.html]
|
|
||||||
type: testharness
|
|
||||||
[save()/restore() works for miterLimit]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
[2d.state.saverestore.stack.html]
|
|
||||||
type: testharness
|
|
||||||
[save()/restore() can be nested as a stack]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
[2d.state.saverestore.stackdepth.html]
|
|
||||||
type: testharness
|
|
||||||
[save()/restore() stack depth is not unreasonably limited]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
[2d.state.saverestore.strokeStyle.html]
|
|
||||||
type: testharness
|
|
||||||
[save()/restore() works for strokeStyle]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
[2d.state.saverestore.transformation.html]
|
|
||||||
type: testharness
|
|
||||||
[save()/restore() affects the current transformation matrix]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
[2d.state.saverestore.underflow.html]
|
|
||||||
type: testharness
|
|
||||||
[restore() with an empty stack has no effect]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
[2d.transformation.scale.negative.html]
|
|
||||||
type: testharness
|
|
||||||
[scale() with negative scale factors works]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -6870,12 +6870,6 @@
|
||||||
[CanvasRenderingContext2D interface: operation commit()]
|
[CanvasRenderingContext2D interface: operation commit()]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[CanvasRenderingContext2D interface: operation save()]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CanvasRenderingContext2D interface: operation restore()]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CanvasRenderingContext2D interface: attribute currentTransform]
|
[CanvasRenderingContext2D interface: attribute currentTransform]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
@ -7017,12 +7011,6 @@
|
||||||
[CanvasRenderingContext2D interface: document.createElement("canvas").getContext("2d") must inherit property "commit" with the proper type (3)]
|
[CanvasRenderingContext2D interface: document.createElement("canvas").getContext("2d") must inherit property "commit" with the proper type (3)]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[CanvasRenderingContext2D interface: document.createElement("canvas").getContext("2d") must inherit property "save" with the proper type (4)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CanvasRenderingContext2D interface: document.createElement("canvas").getContext("2d") must inherit property "restore" with the proper type (5)]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[CanvasRenderingContext2D interface: document.createElement("canvas").getContext("2d") must inherit property "currentTransform" with the proper type (6)]
|
[CanvasRenderingContext2D interface: document.createElement("canvas").getContext("2d") must inherit property "currentTransform" with the proper type (6)]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue