script: Implement enough 2D canvas support to render basic SVGs such as the tiger.

This commit is contained in:
Patrick Walton 2015-02-22 12:35:52 -05:00 committed by Josh Matthews
parent 287f390c4a
commit 55a0ee6ec7
28 changed files with 419 additions and 181 deletions

View file

@ -2,9 +2,10 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use azure::azure_hl::{DrawTarget, SurfaceFormat, BackendType, StrokeOptions, DrawOptions};
use azure::azure_hl::{ColorPattern, PatternRef, JoinStyle, CapStyle, DrawSurfaceOptions, Filter};
use azure::AzFloat;
use azure::azure::AzFloat;
use azure::azure_hl::{DrawTarget, SurfaceFormat, BackendType, StrokeOptions, DrawOptions, Pattern};
use azure::azure_hl::{ColorPattern, PathBuilder, JoinStyle, CapStyle, DrawSurfaceOptions, Filter};
use geom::matrix2d::Matrix2D;
use geom::point::Point2D;
use geom::rect::Rect;
use geom::size::Size2D;
@ -12,6 +13,7 @@ use gfx::color;
use util::task::spawn_named;
use util::vec::byte_swap;
use cssparser::RGBA;
use std::borrow::ToOwned;
use std::ops::Add;
use std::sync::mpsc::{channel, Sender};
@ -21,6 +23,14 @@ pub enum CanvasMsg {
FillRect(Rect<f32>),
ClearRect(Rect<f32>),
StrokeRect(Rect<f32>),
BeginPath,
ClosePath,
Fill,
MoveTo(Point2D<f32>),
BezierCurveTo(Point2D<f32>, Point2D<f32>, Point2D<f32>),
SetFillStyle(FillOrStrokeStyle),
SetStrokeStyle(FillOrStrokeStyle),
SetTransform(Matrix2D<f32>),
Recreate(Size2D<i32>),
SendPixelContents(Sender<Vec<u8>>),
GetImageData(Rect<i32>, Size2D<i32>, Sender<Vec<u8>>),
@ -30,18 +40,26 @@ pub enum CanvasMsg {
pub struct CanvasPaintTask<'a> {
drawtarget: DrawTarget,
fill_color: ColorPattern,
stroke_color: ColorPattern,
fill_style: Pattern,
stroke_style: Pattern,
stroke_opts: StrokeOptions<'a>,
/// TODO(pcwalton): Support multiple paths.
path_builder: PathBuilder,
/// The current 2D transform matrix.
transform: Matrix2D<f32>,
}
impl<'a> CanvasPaintTask<'a> {
fn new(size: Size2D<i32>) -> CanvasPaintTask<'a> {
let draw_target = CanvasPaintTask::create(size);
let path_builder = draw_target.create_path_builder();
CanvasPaintTask {
drawtarget: CanvasPaintTask::create(size),
fill_color: ColorPattern::new(color::black()),
stroke_color: ColorPattern::new(color::black()),
drawtarget: draw_target,
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, 1.0, &[]),
path_builder: path_builder,
transform: Matrix2D::identity(),
}
}
@ -55,6 +73,16 @@ impl<'a> CanvasPaintTask<'a> {
CanvasMsg::FillRect(ref rect) => painter.fill_rect(rect),
CanvasMsg::StrokeRect(ref rect) => painter.stroke_rect(rect),
CanvasMsg::ClearRect(ref rect) => painter.clear_rect(rect),
CanvasMsg::BeginPath => painter.begin_path(),
CanvasMsg::ClosePath => painter.close_path(),
CanvasMsg::Fill => painter.fill(),
CanvasMsg::MoveTo(ref point) => painter.move_to(point),
CanvasMsg::BezierCurveTo(ref cp1, ref cp2, ref pt) => {
painter.bezier_curve_to(cp1, cp2, pt)
}
CanvasMsg::SetFillStyle(style) => painter.set_fill_style(style),
CanvasMsg::SetStrokeStyle(style) => painter.set_stroke_style(style),
CanvasMsg::SetTransform(ref matrix) => painter.set_transform(matrix),
CanvasMsg::Recreate(size) => painter.recreate(size),
CanvasMsg::SendPixelContents(chan) => painter.send_pixel_contents(chan),
CanvasMsg::GetImageData(dest_rect, canvas_size, chan) => painter.get_image_data(dest_rect, canvas_size, chan),
@ -69,7 +97,7 @@ impl<'a> CanvasPaintTask<'a> {
fn fill_rect(&self, rect: &Rect<f32>) {
let drawopts = DrawOptions::new(1.0, 0);
self.drawtarget.fill_rect(rect, PatternRef::Color(&self.fill_color), Some(&drawopts));
self.drawtarget.fill_rect(rect, self.fill_style.to_pattern_ref(), Some(&drawopts));
}
fn clear_rect(&self, rect: &Rect<f32>) {
@ -78,7 +106,58 @@ impl<'a> CanvasPaintTask<'a> {
fn stroke_rect(&self, rect: &Rect<f32>) {
let drawopts = DrawOptions::new(1.0, 0);
self.drawtarget.stroke_rect(rect, &self.stroke_color, &self.stroke_opts, &drawopts);
match self.stroke_style {
Pattern::Color(ref color) => {
self.drawtarget.stroke_rect(rect, color, &self.stroke_opts, &drawopts)
}
_ => {
// TODO(pcwalton)
}
};
}
fn begin_path(&mut self) {
self.path_builder = self.drawtarget.create_path_builder()
}
fn close_path(&self) {
self.path_builder.close()
}
fn fill(&self) {
let draw_options = DrawOptions::new(1.0, 0);
match self.fill_style {
Pattern::Color(ref color) => {
self.drawtarget.fill(&self.path_builder.finish(), color, &draw_options);
}
_ => {
// TODO(pcwalton)
}
};
}
fn move_to(&self, point: &Point2D<AzFloat>) {
self.path_builder.move_to(*point)
}
fn bezier_curve_to(&self,
cp1: &Point2D<AzFloat>,
cp2: &Point2D<AzFloat>,
endpoint: &Point2D<AzFloat>) {
self.path_builder.bezier_curve_to(cp1, cp2, endpoint)
}
fn set_fill_style(&mut self, style: FillOrStrokeStyle) {
self.fill_style = style.to_azure_pattern()
}
fn set_stroke_style(&mut self, style: FillOrStrokeStyle) {
self.stroke_style = style.to_azure_pattern()
}
fn set_transform(&mut self, transform: &Matrix2D<f32>) {
self.transform = *transform;
self.drawtarget.set_transform(transform)
}
fn create(size: Size2D<i32>) -> DrawTarget {
@ -192,3 +271,22 @@ impl<'a> CanvasPaintTask<'a> {
}
}
}
#[derive(Clone)]
pub enum FillOrStrokeStyle {
Color(RGBA),
}
impl FillOrStrokeStyle {
fn to_azure_pattern(&self) -> Pattern {
match *self {
FillOrStrokeStyle::Color(ref color) => {
Pattern::Color(ColorPattern::new(color::new(color.red,
color.green,
color.blue,
color.alpha)))
}
}
}
}