parent
ba7fe4be39
commit
cd37791d72
|
@ -112,13 +112,23 @@ pub struct CanvasRenderingContext2D {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CanvasRenderingContext2D {
|
impl CanvasRenderingContext2D {
|
||||||
// Finalization
|
// Canvas accessors
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn canvas(&self) -> &Canvas {
|
||||||
|
&self.canvas
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn into_canvas(self) -> Canvas {
|
pub fn into_canvas(self) -> Canvas {
|
||||||
self.canvas
|
self.canvas
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn font_context(&self) -> CanvasFontContext {
|
||||||
|
self.font_context.clone()
|
||||||
|
}
|
||||||
|
|
||||||
// Drawing rectangles
|
// Drawing rectangles
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -413,6 +423,30 @@ impl CanvasRenderingContext2D {
|
||||||
self.current_state.global_composite_operation = new_composite_operation;
|
self.current_state.global_composite_operation = new_composite_operation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Drawing images
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn draw_image<I, L>(&mut self, image: I, dest_location: L)
|
||||||
|
where I: CanvasImageSource, L: CanvasImageDestLocation {
|
||||||
|
let pattern = image.to_pattern(self, Transform2F::default());
|
||||||
|
let src_rect = RectF::new(vec2f(0.0, 0.0), pattern.size().to_f32());
|
||||||
|
self.draw_subimage(pattern, src_rect, dest_location)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn draw_subimage<I, L>(&mut self, image: I, src_location: RectF, dest_location: L)
|
||||||
|
where I: CanvasImageSource, L: CanvasImageDestLocation {
|
||||||
|
let dest_size = dest_location.size().unwrap_or(src_location.size());
|
||||||
|
let scale = dest_size / src_location.size();
|
||||||
|
let offset = dest_location.origin() - src_location.origin();
|
||||||
|
let transform = Transform2F::from_scale(scale).translate(offset);
|
||||||
|
|
||||||
|
let pattern = image.to_pattern(self, transform);
|
||||||
|
let old_fill_paint = self.current_state.fill_paint.clone();
|
||||||
|
self.set_fill_style(pattern);
|
||||||
|
self.fill_rect(RectF::new(dest_location.origin(), dest_size));
|
||||||
|
self.current_state.fill_paint = old_fill_paint;
|
||||||
|
}
|
||||||
|
|
||||||
// Image smoothing
|
// Image smoothing
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -451,15 +485,19 @@ impl CanvasRenderingContext2D {
|
||||||
|
|
||||||
// Extensions
|
// Extensions
|
||||||
|
|
||||||
pub fn create_pattern_from_canvas(&mut self, canvas: Canvas) -> Pattern {
|
pub fn create_pattern_from_canvas(&mut self, canvas: Canvas, transform: Transform2F)
|
||||||
|
-> Pattern {
|
||||||
let subscene = canvas.into_scene();
|
let subscene = canvas.into_scene();
|
||||||
let subscene_size = subscene.view_box().size().ceil().to_i32();
|
let subscene_size = subscene.view_box().size().ceil().to_i32();
|
||||||
let render_target = RenderTarget::new(subscene_size, String::new());
|
let render_target = RenderTarget::new(subscene_size, String::new());
|
||||||
let render_target_id = self.canvas.scene.push_render_target(render_target);
|
let render_target_id = self.canvas.scene.push_render_target(render_target);
|
||||||
self.canvas.scene.append_scene(subscene);
|
self.canvas.scene.append_scene(subscene);
|
||||||
self.canvas.scene.pop_render_target();
|
self.canvas.scene.pop_render_target();
|
||||||
let pattern_source = PatternSource::RenderTarget(render_target_id);
|
let pattern_source = PatternSource::RenderTarget {
|
||||||
Pattern::new(pattern_source, Transform2F::default(), PatternFlags::empty())
|
id: render_target_id,
|
||||||
|
size: subscene_size,
|
||||||
|
};
|
||||||
|
Pattern::new(pattern_source, transform, PatternFlags::empty())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -782,6 +820,54 @@ pub enum ImageSmoothingQuality {
|
||||||
High,
|
High,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait CanvasImageSource {
|
||||||
|
fn to_pattern(self, dest_context: &mut CanvasRenderingContext2D, transform: Transform2F)
|
||||||
|
-> Pattern;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait CanvasImageDestLocation {
|
||||||
|
fn origin(&self) -> Vector2F;
|
||||||
|
fn size(&self) -> Option<Vector2F>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CanvasImageSource for Pattern {
|
||||||
|
#[inline]
|
||||||
|
fn to_pattern(mut self, _: &mut CanvasRenderingContext2D, transform: Transform2F) -> Pattern {
|
||||||
|
self.transform(transform);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CanvasImageSource for Canvas {
|
||||||
|
#[inline]
|
||||||
|
fn to_pattern(self, dest_context: &mut CanvasRenderingContext2D, transform: Transform2F)
|
||||||
|
-> Pattern {
|
||||||
|
dest_context.create_pattern_from_canvas(self, transform)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CanvasImageDestLocation for RectF {
|
||||||
|
#[inline]
|
||||||
|
fn origin(&self) -> Vector2F {
|
||||||
|
RectF::origin(*self)
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn size(&self) -> Option<Vector2F> {
|
||||||
|
Some(RectF::size(*self))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CanvasImageDestLocation for Vector2F {
|
||||||
|
#[inline]
|
||||||
|
fn origin(&self) -> Vector2F {
|
||||||
|
*self
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn size(&self) -> Option<Vector2F> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Debug for Path2D {
|
impl Debug for Path2D {
|
||||||
fn fmt(&self, formatter: &mut Formatter) -> Result<(), FmtError> {
|
fn fmt(&self, formatter: &mut Formatter) -> Result<(), FmtError> {
|
||||||
self.clone().into_outline().fmt(formatter)
|
self.clone().into_outline().fmt(formatter)
|
||||||
|
|
|
@ -34,7 +34,10 @@ pub struct Pattern {
|
||||||
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
|
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
|
||||||
pub enum PatternSource {
|
pub enum PatternSource {
|
||||||
Image(Image),
|
Image(Image),
|
||||||
RenderTarget(RenderTargetId),
|
RenderTarget {
|
||||||
|
id: RenderTargetId,
|
||||||
|
size: Vector2I,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// RGBA, non-premultiplied.
|
/// RGBA, non-premultiplied.
|
||||||
|
@ -61,6 +64,19 @@ impl Pattern {
|
||||||
pub fn new(source: PatternSource, transform: Transform2F, flags: PatternFlags) -> Pattern {
|
pub fn new(source: PatternSource, transform: Transform2F, flags: PatternFlags) -> Pattern {
|
||||||
Pattern { source, transform, flags }
|
Pattern { source, transform, flags }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn transform(&mut self, transform: Transform2F) {
|
||||||
|
self.transform *= transform
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn size(&self) -> Vector2I {
|
||||||
|
match self.source {
|
||||||
|
PatternSource::Image(ref image) => image.size(),
|
||||||
|
PatternSource::RenderTarget { size, .. } => size,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Image {
|
impl Image {
|
||||||
|
@ -104,7 +120,7 @@ impl PatternSource {
|
||||||
pub fn is_opaque(&self) -> bool {
|
pub fn is_opaque(&self) -> bool {
|
||||||
match *self {
|
match *self {
|
||||||
PatternSource::Image(ref image) => image.is_opaque(),
|
PatternSource::Image(ref image) => image.is_opaque(),
|
||||||
PatternSource::RenderTarget(_) => {
|
PatternSource::RenderTarget { .. } => {
|
||||||
// TODO(pcwalton): Maybe do something smarter here?
|
// TODO(pcwalton): Maybe do something smarter here?
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
|
@ -236,7 +236,7 @@ impl Palette {
|
||||||
}
|
}
|
||||||
Paint::Pattern(ref pattern) => {
|
Paint::Pattern(ref pattern) => {
|
||||||
match pattern.source {
|
match pattern.source {
|
||||||
PatternSource::RenderTarget(render_target_id) => {
|
PatternSource::RenderTarget { id: render_target_id, .. } => {
|
||||||
texture_location =
|
texture_location =
|
||||||
render_target_metadata[render_target_id.0 as usize].location;
|
render_target_metadata[render_target_id.0 as usize].location;
|
||||||
}
|
}
|
||||||
|
@ -311,7 +311,7 @@ impl Palette {
|
||||||
transform.inverse() * render_transform
|
transform.inverse() * render_transform
|
||||||
}
|
}
|
||||||
Paint::Pattern(Pattern {
|
Paint::Pattern(Pattern {
|
||||||
source: PatternSource::RenderTarget(_),
|
source: PatternSource::RenderTarget { .. },
|
||||||
transform,
|
transform,
|
||||||
..
|
..
|
||||||
}) => {
|
}) => {
|
||||||
|
|
|
@ -18,6 +18,7 @@ use crate::paint::{Paint, PaintId, PaintInfo, Palette};
|
||||||
use pathfinder_content::effects::{BlendMode, Effects};
|
use pathfinder_content::effects::{BlendMode, Effects};
|
||||||
use pathfinder_content::fill::FillRule;
|
use pathfinder_content::fill::FillRule;
|
||||||
use pathfinder_content::outline::Outline;
|
use pathfinder_content::outline::Outline;
|
||||||
|
use pathfinder_content::pattern::{Pattern, PatternSource};
|
||||||
use pathfinder_content::render_target::RenderTargetId;
|
use pathfinder_content::render_target::RenderTargetId;
|
||||||
use pathfinder_geometry::rect::RectF;
|
use pathfinder_geometry::rect::RectF;
|
||||||
use pathfinder_geometry::transform2d::Transform2F;
|
use pathfinder_geometry::transform2d::Transform2F;
|
||||||
|
@ -48,19 +49,23 @@ impl Scene {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push_path(&mut self, path: DrawPath) {
|
pub fn push_path(&mut self, path: DrawPath) {
|
||||||
self.bounds = self.bounds.union_rect(path.outline.bounds());
|
let path_index = self.paths.len() as u32;
|
||||||
self.paths.push(path);
|
self.paths.push(path);
|
||||||
|
self.push_path_with_index(path_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn push_path_with_index(&mut self, path_index: u32) {
|
||||||
|
self.bounds = self.bounds.union_rect(self.paths[path_index as usize].outline.bounds());
|
||||||
|
|
||||||
let new_path_count = self.paths.len() as u32;
|
|
||||||
if let Some(DisplayItem::DrawPaths {
|
if let Some(DisplayItem::DrawPaths {
|
||||||
start_index: _,
|
start_index: _,
|
||||||
ref mut end_index
|
ref mut end_index
|
||||||
}) = self.display_list.last_mut() {
|
}) = self.display_list.last_mut() {
|
||||||
*end_index = new_path_count;
|
*end_index = path_index + 1;
|
||||||
} else {
|
} else {
|
||||||
self.display_list.push(DisplayItem::DrawPaths {
|
self.display_list.push(DisplayItem::DrawPaths {
|
||||||
start_index: new_path_count - 1,
|
start_index: path_index,
|
||||||
end_index: new_path_count,
|
end_index: path_index + 1,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -100,9 +105,25 @@ impl Scene {
|
||||||
|
|
||||||
// Merge paints.
|
// Merge paints.
|
||||||
let mut paint_mapping = HashMap::new();
|
let mut paint_mapping = HashMap::new();
|
||||||
for (old_paint_index, paint) in scene.palette.paints.iter().enumerate() {
|
for (old_paint_index, old_paint) in scene.palette.paints.iter().enumerate() {
|
||||||
let old_paint_id = PaintId(old_paint_index as u16);
|
let old_paint_id = PaintId(old_paint_index as u16);
|
||||||
let new_paint_id = self.palette.push_paint(&paint);
|
let new_paint_id = match old_paint {
|
||||||
|
Paint::Pattern(Pattern {
|
||||||
|
source: PatternSource::RenderTarget { id: old_render_target_id, size },
|
||||||
|
transform,
|
||||||
|
flags
|
||||||
|
}) => {
|
||||||
|
self.palette.push_paint(&Paint::Pattern(Pattern {
|
||||||
|
source: PatternSource::RenderTarget {
|
||||||
|
id: render_target_mapping[old_render_target_id],
|
||||||
|
size: *size,
|
||||||
|
},
|
||||||
|
transform: *transform,
|
||||||
|
flags: *flags,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
paint => self.palette.push_paint(paint),
|
||||||
|
};
|
||||||
paint_mapping.insert(old_paint_id, new_paint_id);
|
paint_mapping.insert(old_paint_id, new_paint_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,7 +137,7 @@ impl Scene {
|
||||||
// Merge draw paths.
|
// Merge draw paths.
|
||||||
let mut draw_path_mapping = Vec::with_capacity(scene.paths.len());
|
let mut draw_path_mapping = Vec::with_capacity(scene.paths.len());
|
||||||
for draw_path in scene.paths {
|
for draw_path in scene.paths {
|
||||||
draw_path_mapping.push(self.paths.len());
|
draw_path_mapping.push(self.paths.len() as u32);
|
||||||
self.paths.push(DrawPath {
|
self.paths.push(DrawPath {
|
||||||
outline: draw_path.outline,
|
outline: draw_path.outline,
|
||||||
paint: paint_mapping[&draw_path.paint],
|
paint: paint_mapping[&draw_path.paint],
|
||||||
|
@ -129,6 +150,34 @@ impl Scene {
|
||||||
name: draw_path.name,
|
name: draw_path.name,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Merge display items.
|
||||||
|
for display_item in scene.display_list {
|
||||||
|
match display_item {
|
||||||
|
DisplayItem::DrawRenderTarget {
|
||||||
|
render_target: old_render_target_id,
|
||||||
|
effects,
|
||||||
|
} => {
|
||||||
|
let new_render_target_id = render_target_mapping[&old_render_target_id];
|
||||||
|
self.draw_render_target(new_render_target_id, effects)
|
||||||
|
}
|
||||||
|
DisplayItem::PushRenderTarget(old_render_target_id) => {
|
||||||
|
let new_render_target_id = render_target_mapping[&old_render_target_id];
|
||||||
|
self.display_list.push(DisplayItem::PushRenderTarget(new_render_target_id));
|
||||||
|
}
|
||||||
|
DisplayItem::PopRenderTarget => {
|
||||||
|
self.display_list.push(DisplayItem::PopRenderTarget);
|
||||||
|
}
|
||||||
|
DisplayItem::DrawPaths {
|
||||||
|
start_index: old_start_path_index,
|
||||||
|
end_index: old_end_path_index,
|
||||||
|
} => {
|
||||||
|
for old_path_index in old_start_path_index..old_end_path_index {
|
||||||
|
self.push_path_with_index(draw_path_mapping[old_path_index as usize])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
Loading…
Reference in New Issue