parent
ba7fe4be39
commit
cd37791d72
|
@ -112,13 +112,23 @@ pub struct CanvasRenderingContext2D {
|
|||
}
|
||||
|
||||
impl CanvasRenderingContext2D {
|
||||
// Finalization
|
||||
// Canvas accessors
|
||||
|
||||
#[inline]
|
||||
pub fn canvas(&self) -> &Canvas {
|
||||
&self.canvas
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn into_canvas(self) -> Canvas {
|
||||
self.canvas
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn font_context(&self) -> CanvasFontContext {
|
||||
self.font_context.clone()
|
||||
}
|
||||
|
||||
// Drawing rectangles
|
||||
|
||||
#[inline]
|
||||
|
@ -413,6 +423,30 @@ impl CanvasRenderingContext2D {
|
|||
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
|
||||
|
||||
#[inline]
|
||||
|
@ -451,15 +485,19 @@ impl CanvasRenderingContext2D {
|
|||
|
||||
// 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_size = subscene.view_box().size().ceil().to_i32();
|
||||
let render_target = RenderTarget::new(subscene_size, String::new());
|
||||
let render_target_id = self.canvas.scene.push_render_target(render_target);
|
||||
self.canvas.scene.append_scene(subscene);
|
||||
self.canvas.scene.pop_render_target();
|
||||
let pattern_source = PatternSource::RenderTarget(render_target_id);
|
||||
Pattern::new(pattern_source, Transform2F::default(), PatternFlags::empty())
|
||||
let pattern_source = PatternSource::RenderTarget {
|
||||
id: render_target_id,
|
||||
size: subscene_size,
|
||||
};
|
||||
Pattern::new(pattern_source, transform, PatternFlags::empty())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -782,6 +820,54 @@ pub enum ImageSmoothingQuality {
|
|||
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 {
|
||||
fn fmt(&self, formatter: &mut Formatter) -> Result<(), FmtError> {
|
||||
self.clone().into_outline().fmt(formatter)
|
||||
|
|
|
@ -34,7 +34,10 @@ pub struct Pattern {
|
|||
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
|
||||
pub enum PatternSource {
|
||||
Image(Image),
|
||||
RenderTarget(RenderTargetId),
|
||||
RenderTarget {
|
||||
id: RenderTargetId,
|
||||
size: Vector2I,
|
||||
}
|
||||
}
|
||||
|
||||
/// RGBA, non-premultiplied.
|
||||
|
@ -61,6 +64,19 @@ impl Pattern {
|
|||
pub fn new(source: PatternSource, transform: Transform2F, flags: PatternFlags) -> Pattern {
|
||||
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 {
|
||||
|
@ -104,7 +120,7 @@ impl PatternSource {
|
|||
pub fn is_opaque(&self) -> bool {
|
||||
match *self {
|
||||
PatternSource::Image(ref image) => image.is_opaque(),
|
||||
PatternSource::RenderTarget(_) => {
|
||||
PatternSource::RenderTarget { .. } => {
|
||||
// TODO(pcwalton): Maybe do something smarter here?
|
||||
false
|
||||
}
|
||||
|
|
|
@ -236,7 +236,7 @@ impl Palette {
|
|||
}
|
||||
Paint::Pattern(ref pattern) => {
|
||||
match pattern.source {
|
||||
PatternSource::RenderTarget(render_target_id) => {
|
||||
PatternSource::RenderTarget { id: render_target_id, .. } => {
|
||||
texture_location =
|
||||
render_target_metadata[render_target_id.0 as usize].location;
|
||||
}
|
||||
|
@ -311,7 +311,7 @@ impl Palette {
|
|||
transform.inverse() * render_transform
|
||||
}
|
||||
Paint::Pattern(Pattern {
|
||||
source: PatternSource::RenderTarget(_),
|
||||
source: PatternSource::RenderTarget { .. },
|
||||
transform,
|
||||
..
|
||||
}) => {
|
||||
|
|
|
@ -18,6 +18,7 @@ use crate::paint::{Paint, PaintId, PaintInfo, Palette};
|
|||
use pathfinder_content::effects::{BlendMode, Effects};
|
||||
use pathfinder_content::fill::FillRule;
|
||||
use pathfinder_content::outline::Outline;
|
||||
use pathfinder_content::pattern::{Pattern, PatternSource};
|
||||
use pathfinder_content::render_target::RenderTargetId;
|
||||
use pathfinder_geometry::rect::RectF;
|
||||
use pathfinder_geometry::transform2d::Transform2F;
|
||||
|
@ -48,19 +49,23 @@ impl Scene {
|
|||
}
|
||||
|
||||
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.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 {
|
||||
start_index: _,
|
||||
ref mut end_index
|
||||
}) = self.display_list.last_mut() {
|
||||
*end_index = new_path_count;
|
||||
*end_index = path_index + 1;
|
||||
} else {
|
||||
self.display_list.push(DisplayItem::DrawPaths {
|
||||
start_index: new_path_count - 1,
|
||||
end_index: new_path_count,
|
||||
start_index: path_index,
|
||||
end_index: path_index + 1,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -100,9 +105,25 @@ impl Scene {
|
|||
|
||||
// Merge paints.
|
||||
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 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);
|
||||
}
|
||||
|
||||
|
@ -116,7 +137,7 @@ impl Scene {
|
|||
// Merge draw paths.
|
||||
let mut draw_path_mapping = Vec::with_capacity(scene.paths.len());
|
||||
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 {
|
||||
outline: draw_path.outline,
|
||||
paint: paint_mapping[&draw_path.paint],
|
||||
|
@ -129,6 +150,34 @@ impl Scene {
|
|||
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]
|
||||
|
|
Loading…
Reference in New Issue