Implement `clear_rect()` in the canvas front-end by introducing the concept of
per-path blend modes. These should be useful for some canvas composite operations as well.
This commit is contained in:
parent
0c3dad974f
commit
6acd2d91f7
|
@ -12,6 +12,7 @@
|
||||||
|
|
||||||
use pathfinder_color::ColorU;
|
use pathfinder_color::ColorU;
|
||||||
use pathfinder_content::dash::OutlineDash;
|
use pathfinder_content::dash::OutlineDash;
|
||||||
|
use pathfinder_content::effects::BlendMode;
|
||||||
use pathfinder_content::fill::FillRule;
|
use pathfinder_content::fill::FillRule;
|
||||||
use pathfinder_content::gradient::Gradient;
|
use pathfinder_content::gradient::Gradient;
|
||||||
use pathfinder_content::outline::{ArcDirection, Contour, Outline};
|
use pathfinder_content::outline::{ArcDirection, Contour, Outline};
|
||||||
|
@ -91,6 +92,25 @@ impl CanvasRenderingContext2D {
|
||||||
self.stroke_path(path);
|
self.stroke_path(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn clear_rect(&mut self, rect: RectF) {
|
||||||
|
let mut path = Path2D::new();
|
||||||
|
path.rect(rect);
|
||||||
|
|
||||||
|
let mut outline = path.into_outline();
|
||||||
|
outline.transform(&self.current_state.transform);
|
||||||
|
|
||||||
|
let paint = Paint::black();
|
||||||
|
let paint = self.current_state.resolve_paint(&paint);
|
||||||
|
let paint_id = self.scene.push_paint(&paint);
|
||||||
|
|
||||||
|
self.scene.push_path(DrawPath::new(outline,
|
||||||
|
paint_id,
|
||||||
|
None,
|
||||||
|
FillRule::Winding,
|
||||||
|
BlendMode::Clear,
|
||||||
|
String::new()))
|
||||||
|
}
|
||||||
|
|
||||||
// Line styles
|
// Line styles
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -223,10 +243,16 @@ impl CanvasRenderingContext2D {
|
||||||
paint_id,
|
paint_id,
|
||||||
clip_path,
|
clip_path,
|
||||||
fill_rule,
|
fill_rule,
|
||||||
|
BlendMode::SourceOver,
|
||||||
String::new()))
|
String::new()))
|
||||||
}
|
}
|
||||||
|
|
||||||
self.scene.push_path(DrawPath::new(outline, paint_id, clip_path, fill_rule, String::new()))
|
self.scene.push_path(DrawPath::new(outline,
|
||||||
|
paint_id,
|
||||||
|
clip_path,
|
||||||
|
fill_rule,
|
||||||
|
BlendMode::SourceOver,
|
||||||
|
String::new()))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Transformations
|
// Transformations
|
||||||
|
|
|
@ -61,6 +61,13 @@ pub enum CompositeOp {
|
||||||
SourceOver,
|
SourceOver,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Blend modes that can be applied to individual paths without creating layers for them.
|
||||||
|
#[derive(Clone, Copy, PartialEq, Debug)]
|
||||||
|
pub enum BlendMode {
|
||||||
|
SourceOver,
|
||||||
|
Clear,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Debug)]
|
#[derive(Clone, Copy, PartialEq, Debug)]
|
||||||
pub struct DefringingKernel(pub [f32; 4]);
|
pub struct DefringingKernel(pub [f32; 4]);
|
||||||
|
|
||||||
|
@ -70,3 +77,10 @@ impl Default for CompositeOp {
|
||||||
CompositeOp::SourceOver
|
CompositeOp::SourceOver
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for BlendMode {
|
||||||
|
#[inline]
|
||||||
|
fn default() -> BlendMode {
|
||||||
|
BlendMode::SourceOver
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@ use crate::scene::{DisplayItem, Scene};
|
||||||
use crate::tile_map::DenseTileMap;
|
use crate::tile_map::DenseTileMap;
|
||||||
use crate::tiles::{self, TILE_HEIGHT, TILE_WIDTH, Tiler, TilingPathInfo};
|
use crate::tiles::{self, TILE_HEIGHT, TILE_WIDTH, Tiler, TilingPathInfo};
|
||||||
use crate::z_buffer::ZBuffer;
|
use crate::z_buffer::ZBuffer;
|
||||||
use pathfinder_content::effects::Effects;
|
use pathfinder_content::effects::{BlendMode, Effects};
|
||||||
use pathfinder_content::fill::FillRule;
|
use pathfinder_content::fill::FillRule;
|
||||||
use pathfinder_geometry::line_segment::{LineSegment2F, LineSegmentU4, LineSegmentU8};
|
use pathfinder_geometry::line_segment::{LineSegment2F, LineSegmentU4, LineSegmentU8};
|
||||||
use pathfinder_geometry::vector::{Vector2F, Vector2I};
|
use pathfinder_geometry::vector::{Vector2F, Vector2I};
|
||||||
|
@ -48,6 +48,12 @@ pub(crate) struct ObjectBuilder {
|
||||||
pub bounds: RectF,
|
pub bounds: RectF,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct BuiltDrawPath {
|
||||||
|
path: BuiltPath,
|
||||||
|
blend_mode: BlendMode,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) struct BuiltPath {
|
pub(crate) struct BuiltPath {
|
||||||
pub mask_tiles: Vec<MaskTile>,
|
pub mask_tiles: Vec<MaskTile>,
|
||||||
|
@ -147,7 +153,7 @@ impl<'a> SceneBuilder<'a> {
|
||||||
scene: &Scene,
|
scene: &Scene,
|
||||||
paint_metadata: &[PaintMetadata],
|
paint_metadata: &[PaintMetadata],
|
||||||
built_clip_paths: &[BuiltPath],
|
built_clip_paths: &[BuiltPath],
|
||||||
) -> BuiltPath {
|
) -> BuiltDrawPath {
|
||||||
let path_object = &scene.paths[path_index];
|
let path_object = &scene.paths[path_index];
|
||||||
let outline = scene.apply_render_options(path_object.outline(), built_options);
|
let outline = scene.apply_render_options(path_object.outline(), built_options);
|
||||||
let paint_id = path_object.paint();
|
let paint_id = path_object.paint();
|
||||||
|
@ -168,13 +174,17 @@ impl<'a> SceneBuilder<'a> {
|
||||||
tiler.generate_tiles();
|
tiler.generate_tiles();
|
||||||
|
|
||||||
self.listener.send(RenderCommand::AddFills(tiler.object_builder.fills));
|
self.listener.send(RenderCommand::AddFills(tiler.object_builder.fills));
|
||||||
tiler.object_builder.built_path
|
|
||||||
|
BuiltDrawPath {
|
||||||
|
path: tiler.object_builder.built_path,
|
||||||
|
blend_mode: path_object.blend_mode(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cull_tiles(&self,
|
fn cull_tiles(&self,
|
||||||
paint_metadata: &[PaintMetadata],
|
paint_metadata: &[PaintMetadata],
|
||||||
built_clip_paths: Vec<BuiltPath>,
|
built_clip_paths: Vec<BuiltPath>,
|
||||||
built_draw_paths: Vec<BuiltPath>)
|
built_draw_paths: Vec<BuiltDrawPath>)
|
||||||
-> CulledTiles {
|
-> CulledTiles {
|
||||||
let mut culled_tiles = CulledTiles {
|
let mut culled_tiles = CulledTiles {
|
||||||
mask_winding_tiles: vec![],
|
mask_winding_tiles: vec![],
|
||||||
|
@ -226,24 +236,37 @@ impl<'a> SceneBuilder<'a> {
|
||||||
|
|
||||||
for draw_path_index in start_draw_path_index..end_draw_path_index {
|
for draw_path_index in start_draw_path_index..end_draw_path_index {
|
||||||
let built_draw_path = &built_draw_paths[draw_path_index as usize];
|
let built_draw_path = &built_draw_paths[draw_path_index as usize];
|
||||||
culled_tiles.push_mask_tiles(built_draw_path);
|
culled_tiles.push_mask_tiles(&built_draw_path.path);
|
||||||
|
|
||||||
// Create a `DrawAlphaTiles` display item if necessary.
|
// Create a new `DrawAlphaTiles` display item if we don't have one or if we have to
|
||||||
|
// break a batch due to blend mode differences.
|
||||||
|
//
|
||||||
|
// TODO(pcwalton): If we really wanted to, we could use tile maps to avoid batch
|
||||||
|
// breaks in some cases…
|
||||||
match culled_tiles.display_list.last() {
|
match culled_tiles.display_list.last() {
|
||||||
Some(&CulledDisplayItem::DrawAlphaTiles(_)) => {}
|
Some(&CulledDisplayItem::DrawAlphaTiles {
|
||||||
_ => culled_tiles.display_list.push(CulledDisplayItem::DrawAlphaTiles(vec![])),
|
tiles: _,
|
||||||
|
blend_mode
|
||||||
|
}) if blend_mode == built_draw_path.blend_mode => {}
|
||||||
|
_ => {
|
||||||
|
culled_tiles.display_list.push(CulledDisplayItem::DrawAlphaTiles {
|
||||||
|
tiles: vec![],
|
||||||
|
blend_mode: built_draw_path.blend_mode,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch the destination alpha tiles buffer.
|
// Fetch the destination alpha tiles buffer.
|
||||||
let culled_alpha_tiles = match *culled_tiles.display_list.last_mut().unwrap() {
|
let culled_alpha_tiles = match *culled_tiles.display_list.last_mut().unwrap() {
|
||||||
CulledDisplayItem::DrawAlphaTiles(ref mut culled_alpha_tiles) => {
|
CulledDisplayItem::DrawAlphaTiles {
|
||||||
culled_alpha_tiles
|
tiles: ref mut culled_alpha_tiles,
|
||||||
}
|
..
|
||||||
|
} => culled_alpha_tiles,
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let layer_z_buffer = layer_z_buffers_stack.last().unwrap();
|
let layer_z_buffer = layer_z_buffers_stack.last().unwrap();
|
||||||
for alpha_tile in &built_draw_path.alpha_tiles {
|
for alpha_tile in &built_draw_path.path.alpha_tiles {
|
||||||
let alpha_tile_coords = alpha_tile.upper_left.tile_position();
|
let alpha_tile_coords = alpha_tile.upper_left.tile_position();
|
||||||
if layer_z_buffer.test(alpha_tile_coords,
|
if layer_z_buffer.test(alpha_tile_coords,
|
||||||
alpha_tile.upper_left.object_index as u32) {
|
alpha_tile.upper_left.object_index as u32) {
|
||||||
|
@ -256,7 +279,7 @@ impl<'a> SceneBuilder<'a> {
|
||||||
culled_tiles
|
culled_tiles
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_solid_tiles(&self, built_draw_paths: &[BuiltPath]) -> Vec<ZBuffer> {
|
fn build_solid_tiles(&self, built_draw_paths: &[BuiltDrawPath]) -> Vec<ZBuffer> {
|
||||||
let effective_view_box = self.scene.effective_view_box(self.built_options);
|
let effective_view_box = self.scene.effective_view_box(self.built_options);
|
||||||
let mut z_buffers = vec![ZBuffer::new(effective_view_box)];
|
let mut z_buffers = vec![ZBuffer::new(effective_view_box)];
|
||||||
let mut z_buffer_index_stack = vec![0];
|
let mut z_buffer_index_stack = vec![0];
|
||||||
|
@ -276,7 +299,7 @@ impl<'a> SceneBuilder<'a> {
|
||||||
let z_buffer = &mut z_buffers[*z_buffer_index_stack.last().unwrap()];
|
let z_buffer = &mut z_buffers[*z_buffer_index_stack.last().unwrap()];
|
||||||
for (path_index, built_draw_path) in
|
for (path_index, built_draw_path) in
|
||||||
built_draw_paths[start_index..end_index].iter().enumerate() {
|
built_draw_paths[start_index..end_index].iter().enumerate() {
|
||||||
z_buffer.update(&built_draw_path.solid_tiles, path_index as u32);
|
z_buffer.update(&built_draw_path.path.solid_tiles, path_index as u32);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -305,8 +328,8 @@ impl<'a> SceneBuilder<'a> {
|
||||||
CulledDisplayItem::DrawSolidTiles(tiles) => {
|
CulledDisplayItem::DrawSolidTiles(tiles) => {
|
||||||
self.listener.send(RenderCommand::DrawSolidTiles(tiles))
|
self.listener.send(RenderCommand::DrawSolidTiles(tiles))
|
||||||
}
|
}
|
||||||
CulledDisplayItem::DrawAlphaTiles(tiles) => {
|
CulledDisplayItem::DrawAlphaTiles { tiles, blend_mode } => {
|
||||||
self.listener.send(RenderCommand::DrawAlphaTiles(tiles))
|
self.listener.send(RenderCommand::DrawAlphaTiles { tiles, blend_mode })
|
||||||
}
|
}
|
||||||
CulledDisplayItem::PushLayer { effects } => {
|
CulledDisplayItem::PushLayer { effects } => {
|
||||||
self.listener.send(RenderCommand::PushLayer { effects })
|
self.listener.send(RenderCommand::PushLayer { effects })
|
||||||
|
@ -319,7 +342,7 @@ impl<'a> SceneBuilder<'a> {
|
||||||
fn finish_building(&mut self,
|
fn finish_building(&mut self,
|
||||||
paint_metadata: &[PaintMetadata],
|
paint_metadata: &[PaintMetadata],
|
||||||
built_clip_paths: Vec<BuiltPath>,
|
built_clip_paths: Vec<BuiltPath>,
|
||||||
built_draw_paths: Vec<BuiltPath>) {
|
built_draw_paths: Vec<BuiltDrawPath>) {
|
||||||
self.listener.send(RenderCommand::FlushFills);
|
self.listener.send(RenderCommand::FlushFills);
|
||||||
let culled_tiles = self.cull_tiles(paint_metadata, built_clip_paths, built_draw_paths);
|
let culled_tiles = self.cull_tiles(paint_metadata, built_clip_paths, built_draw_paths);
|
||||||
self.pack_tiles(culled_tiles);
|
self.pack_tiles(culled_tiles);
|
||||||
|
@ -358,7 +381,7 @@ struct CulledTiles {
|
||||||
|
|
||||||
enum CulledDisplayItem {
|
enum CulledDisplayItem {
|
||||||
DrawSolidTiles(Vec<SolidTileVertex>),
|
DrawSolidTiles(Vec<SolidTileVertex>),
|
||||||
DrawAlphaTiles(Vec<AlphaTile>),
|
DrawAlphaTiles { tiles: Vec<AlphaTile>, blend_mode: BlendMode },
|
||||||
PushLayer { effects: Effects },
|
PushLayer { effects: Effects },
|
||||||
PopLayer,
|
PopLayer,
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@ use crate::gpu_data::{AlphaTile, FillBatchPrimitive, MaskTile, PaintData};
|
||||||
use crate::gpu_data::{RenderCommand, SolidTileVertex};
|
use crate::gpu_data::{RenderCommand, SolidTileVertex};
|
||||||
use crate::tiles::{TILE_HEIGHT, TILE_WIDTH};
|
use crate::tiles::{TILE_HEIGHT, TILE_WIDTH};
|
||||||
use pathfinder_color::{self as color, ColorF};
|
use pathfinder_color::{self as color, ColorF};
|
||||||
use pathfinder_content::effects::{CompositeOp, DefringingKernel, Effects, Filter};
|
use pathfinder_content::effects::{BlendMode, CompositeOp, DefringingKernel, Effects, Filter};
|
||||||
use pathfinder_content::fill::FillRule;
|
use pathfinder_content::fill::FillRule;
|
||||||
use pathfinder_geometry::vector::{Vector2I, Vector4F};
|
use pathfinder_geometry::vector::{Vector2I, Vector4F};
|
||||||
use pathfinder_geometry::rect::RectI;
|
use pathfinder_geometry::rect::RectI;
|
||||||
|
@ -298,11 +298,11 @@ where
|
||||||
self.upload_solid_tiles(solid_tile_vertices);
|
self.upload_solid_tiles(solid_tile_vertices);
|
||||||
self.draw_solid_tiles(count as u32);
|
self.draw_solid_tiles(count as u32);
|
||||||
}
|
}
|
||||||
RenderCommand::DrawAlphaTiles(ref alpha_tiles) => {
|
RenderCommand::DrawAlphaTiles { tiles: ref alpha_tiles, blend_mode } => {
|
||||||
let count = alpha_tiles.len();
|
let count = alpha_tiles.len();
|
||||||
self.stats.alpha_tile_count += count;
|
self.stats.alpha_tile_count += count;
|
||||||
self.upload_alpha_tiles(alpha_tiles);
|
self.upload_alpha_tiles(alpha_tiles);
|
||||||
self.draw_alpha_tiles(count as u32);
|
self.draw_alpha_tiles(count as u32, blend_mode);
|
||||||
}
|
}
|
||||||
RenderCommand::Finish { .. } => {}
|
RenderCommand::Finish { .. } => {}
|
||||||
}
|
}
|
||||||
|
@ -595,7 +595,7 @@ where
|
||||||
self.framebuffer_flags.insert(FramebufferFlags::MUST_PRESERVE_MASK_FRAMEBUFFER_CONTENTS);
|
self.framebuffer_flags.insert(FramebufferFlags::MUST_PRESERVE_MASK_FRAMEBUFFER_CONTENTS);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_alpha_tiles(&mut self, tile_count: u32) {
|
fn draw_alpha_tiles(&mut self, tile_count: u32, blend_mode: BlendMode) {
|
||||||
let clear_color = self.clear_color_for_draw_operation();
|
let clear_color = self.clear_color_for_draw_operation();
|
||||||
|
|
||||||
let mut textures = vec![self.device.framebuffer_texture(&self.mask_framebuffer)];
|
let mut textures = vec![self.device.framebuffer_texture(&self.mask_framebuffer)];
|
||||||
|
@ -629,7 +629,7 @@ where
|
||||||
uniforms: &uniforms,
|
uniforms: &uniforms,
|
||||||
viewport: self.draw_viewport(),
|
viewport: self.draw_viewport(),
|
||||||
options: RenderOptions {
|
options: RenderOptions {
|
||||||
blend: Some(alpha_blend_state()),
|
blend: Some(blend_mode.to_blend_state()),
|
||||||
stencil: self.stencil_state(),
|
stencil: self.stencil_state(),
|
||||||
clear_ops: ClearOps { color: clear_color, ..ClearOps::default() },
|
clear_ops: ClearOps { color: clear_color, ..ClearOps::default() },
|
||||||
..RenderOptions::default()
|
..RenderOptions::default()
|
||||||
|
@ -743,7 +743,7 @@ where
|
||||||
],
|
],
|
||||||
viewport: self.draw_viewport(),
|
viewport: self.draw_viewport(),
|
||||||
options: RenderOptions {
|
options: RenderOptions {
|
||||||
blend: Some(alpha_blend_state()),
|
blend: Some(BlendMode::SourceOver.to_blend_state()),
|
||||||
depth: Some(DepthState { func: DepthFunc::Less, write: false, }),
|
depth: Some(DepthState { func: DepthFunc::Less, write: false, }),
|
||||||
clear_ops: ClearOps { color: clear_color, ..ClearOps::default() },
|
clear_ops: ClearOps { color: clear_color, ..ClearOps::default() },
|
||||||
..RenderOptions::default()
|
..RenderOptions::default()
|
||||||
|
@ -829,7 +829,7 @@ where
|
||||||
];
|
];
|
||||||
|
|
||||||
let blend_state = match composite_op {
|
let blend_state = match composite_op {
|
||||||
CompositeOp::SourceOver => alpha_blend_state(),
|
CompositeOp::SourceOver => BlendMode::SourceOver.to_blend_state(),
|
||||||
};
|
};
|
||||||
|
|
||||||
self.device.draw_elements(6, &RenderState {
|
self.device.draw_elements(6, &RenderState {
|
||||||
|
@ -1107,12 +1107,31 @@ struct LayerFramebufferInfo<D> where D: Device {
|
||||||
must_preserve_contents: bool,
|
must_preserve_contents: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn alpha_blend_state() -> BlendState {
|
trait BlendModeExt {
|
||||||
BlendState {
|
fn to_blend_state(self) -> BlendState;
|
||||||
src_rgb_factor: BlendFactor::SrcAlpha,
|
}
|
||||||
dest_rgb_factor: BlendFactor::OneMinusSrcAlpha,
|
|
||||||
src_alpha_factor: BlendFactor::One,
|
impl BlendModeExt for BlendMode {
|
||||||
dest_alpha_factor: BlendFactor::One,
|
fn to_blend_state(self) -> BlendState {
|
||||||
..BlendState::default()
|
match self {
|
||||||
|
BlendMode::SourceOver => {
|
||||||
|
BlendState {
|
||||||
|
src_rgb_factor: BlendFactor::SrcAlpha,
|
||||||
|
dest_rgb_factor: BlendFactor::OneMinusSrcAlpha,
|
||||||
|
src_alpha_factor: BlendFactor::One,
|
||||||
|
dest_alpha_factor: BlendFactor::One,
|
||||||
|
..BlendState::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BlendMode::Clear => {
|
||||||
|
BlendState {
|
||||||
|
src_rgb_factor: BlendFactor::Zero,
|
||||||
|
dest_rgb_factor: BlendFactor::OneMinusSrcAlpha,
|
||||||
|
src_alpha_factor: BlendFactor::Zero,
|
||||||
|
dest_alpha_factor: BlendFactor::OneMinusSrcAlpha,
|
||||||
|
..BlendState::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
|
|
||||||
use crate::options::BoundingQuad;
|
use crate::options::BoundingQuad;
|
||||||
use pathfinder_color::ColorU;
|
use pathfinder_color::ColorU;
|
||||||
use pathfinder_content::effects::Effects;
|
use pathfinder_content::effects::{BlendMode, Effects};
|
||||||
use pathfinder_content::fill::FillRule;
|
use pathfinder_content::fill::FillRule;
|
||||||
use pathfinder_geometry::line_segment::{LineSegmentU4, LineSegmentU8};
|
use pathfinder_geometry::line_segment::{LineSegmentU4, LineSegmentU8};
|
||||||
use pathfinder_geometry::vector::Vector2I;
|
use pathfinder_geometry::vector::Vector2I;
|
||||||
|
@ -27,7 +27,7 @@ pub enum RenderCommand {
|
||||||
RenderMaskTiles { tiles: Vec<MaskTile>, fill_rule: FillRule },
|
RenderMaskTiles { tiles: Vec<MaskTile>, fill_rule: FillRule },
|
||||||
PushLayer { effects: Effects },
|
PushLayer { effects: Effects },
|
||||||
PopLayer,
|
PopLayer,
|
||||||
DrawAlphaTiles(Vec<AlphaTile>),
|
DrawAlphaTiles { tiles: Vec<AlphaTile>, blend_mode: BlendMode },
|
||||||
DrawSolidTiles(Vec<SolidTileVertex>),
|
DrawSolidTiles(Vec<SolidTileVertex>),
|
||||||
Finish { build_time: Duration },
|
Finish { build_time: Duration },
|
||||||
}
|
}
|
||||||
|
@ -130,8 +130,8 @@ impl Debug for RenderCommand {
|
||||||
}
|
}
|
||||||
RenderCommand::PushLayer { .. } => write!(formatter, "PushLayer"),
|
RenderCommand::PushLayer { .. } => write!(formatter, "PushLayer"),
|
||||||
RenderCommand::PopLayer => write!(formatter, "PopLayer"),
|
RenderCommand::PopLayer => write!(formatter, "PopLayer"),
|
||||||
RenderCommand::DrawAlphaTiles(ref tiles) => {
|
RenderCommand::DrawAlphaTiles { ref tiles, blend_mode } => {
|
||||||
write!(formatter, "DrawAlphaTiles(x{})", tiles.len())
|
write!(formatter, "DrawAlphaTiles(x{}, {:?})", tiles.len(), blend_mode)
|
||||||
}
|
}
|
||||||
RenderCommand::DrawSolidTiles(ref tiles) => {
|
RenderCommand::DrawSolidTiles(ref tiles) => {
|
||||||
write!(formatter, "DrawSolidTiles(x{})", tiles.len())
|
write!(formatter, "DrawSolidTiles(x{})", tiles.len())
|
||||||
|
|
|
@ -15,7 +15,7 @@ use crate::concurrent::executor::Executor;
|
||||||
use crate::options::{BuildOptions, PreparedBuildOptions};
|
use crate::options::{BuildOptions, PreparedBuildOptions};
|
||||||
use crate::options::{PreparedRenderTransform, RenderCommandListener};
|
use crate::options::{PreparedRenderTransform, RenderCommandListener};
|
||||||
use crate::paint::{Paint, PaintId, PaintInfo, Palette};
|
use crate::paint::{Paint, PaintId, PaintInfo, Palette};
|
||||||
use pathfinder_content::effects::Effects;
|
use pathfinder_content::effects::{BlendMode, Effects};
|
||||||
use pathfinder_content::fill::FillRule;
|
use pathfinder_content::fill::FillRule;
|
||||||
use pathfinder_geometry::vector::Vector2F;
|
use pathfinder_geometry::vector::Vector2F;
|
||||||
use pathfinder_geometry::rect::RectF;
|
use pathfinder_geometry::rect::RectF;
|
||||||
|
@ -218,6 +218,7 @@ pub struct DrawPath {
|
||||||
paint: PaintId,
|
paint: PaintId,
|
||||||
clip_path: Option<ClipPathId>,
|
clip_path: Option<ClipPathId>,
|
||||||
fill_rule: FillRule,
|
fill_rule: FillRule,
|
||||||
|
blend_mode: BlendMode,
|
||||||
name: String,
|
name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -244,9 +245,10 @@ impl DrawPath {
|
||||||
paint: PaintId,
|
paint: PaintId,
|
||||||
clip_path: Option<ClipPathId>,
|
clip_path: Option<ClipPathId>,
|
||||||
fill_rule: FillRule,
|
fill_rule: FillRule,
|
||||||
|
blend_mode: BlendMode,
|
||||||
name: String)
|
name: String)
|
||||||
-> DrawPath {
|
-> DrawPath {
|
||||||
DrawPath { outline, paint, clip_path, fill_rule, name }
|
DrawPath { outline, paint, clip_path, fill_rule, blend_mode, name }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -268,6 +270,11 @@ impl DrawPath {
|
||||||
pub(crate) fn fill_rule(&self) -> FillRule {
|
pub(crate) fn fill_rule(&self) -> FillRule {
|
||||||
self.fill_rule
|
self.fill_rule
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn blend_mode(&self) -> BlendMode {
|
||||||
|
self.blend_mode
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ClipPath {
|
impl ClipPath {
|
||||||
|
|
|
@ -15,6 +15,7 @@ extern crate bitflags;
|
||||||
|
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
use pathfinder_color::ColorU;
|
use pathfinder_color::ColorU;
|
||||||
|
use pathfinder_content::effects::BlendMode;
|
||||||
use pathfinder_content::fill::FillRule;
|
use pathfinder_content::fill::FillRule;
|
||||||
use pathfinder_content::outline::Outline;
|
use pathfinder_content::outline::Outline;
|
||||||
use pathfinder_content::segment::{Segment, SegmentFlags};
|
use pathfinder_content::segment::{Segment, SegmentFlags};
|
||||||
|
@ -235,7 +236,12 @@ impl BuiltSVG {
|
||||||
opacity,
|
opacity,
|
||||||
&mut self.result_flags));
|
&mut self.result_flags));
|
||||||
let fill_rule = FillRule::from_usvg_fill_rule(fill_rule);
|
let fill_rule = FillRule::from_usvg_fill_rule(fill_rule);
|
||||||
self.scene.push_path(DrawPath::new(outline, style, state.clip_path, fill_rule, name));
|
self.scene.push_path(DrawPath::new(outline,
|
||||||
|
style,
|
||||||
|
state.clip_path,
|
||||||
|
fill_rule,
|
||||||
|
BlendMode::SourceOver,
|
||||||
|
name));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
|
|
||||||
use std::ops::Add;
|
use std::ops::Add;
|
||||||
use pathfinder_color::{ColorF, ColorU};
|
use pathfinder_color::{ColorF, ColorU};
|
||||||
|
use pathfinder_content::effects::BlendMode;
|
||||||
use pathfinder_content::fill::FillRule;
|
use pathfinder_content::fill::FillRule;
|
||||||
use pathfinder_content::outline::{Outline, Contour};
|
use pathfinder_content::outline::{Outline, Contour};
|
||||||
use pathfinder_content::stroke::{OutlineStrokeToFill, StrokeStyle};
|
use pathfinder_content::stroke::{OutlineStrokeToFill, StrokeStyle};
|
||||||
|
@ -200,6 +201,7 @@ pub fn draw_paths_into_scene(library: &SymbolLibrary, scene: &mut Scene) {
|
||||||
paint_id,
|
paint_id,
|
||||||
None,
|
None,
|
||||||
FillRule::EvenOdd,
|
FillRule::EvenOdd,
|
||||||
|
BlendMode::SourceOver,
|
||||||
String::new()
|
String::new()
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@ use font_kit::error::GlyphLoadingError;
|
||||||
use font_kit::hinting::HintingOptions;
|
use font_kit::hinting::HintingOptions;
|
||||||
use font_kit::loader::Loader;
|
use font_kit::loader::Loader;
|
||||||
use lyon_path::builder::{FlatPathBuilder, PathBuilder, Build};
|
use lyon_path::builder::{FlatPathBuilder, PathBuilder, Build};
|
||||||
|
use pathfinder_content::effects::BlendMode;
|
||||||
use pathfinder_content::fill::FillRule;
|
use pathfinder_content::fill::FillRule;
|
||||||
use pathfinder_content::outline::{Contour, Outline};
|
use pathfinder_content::outline::{Contour, Outline};
|
||||||
use pathfinder_content::stroke::{OutlineStrokeToFill, StrokeStyle};
|
use pathfinder_content::stroke::{OutlineStrokeToFill, StrokeStyle};
|
||||||
|
@ -77,7 +78,13 @@ impl SceneExt for Scene {
|
||||||
outline = stroke_to_fill.into_outline();
|
outline = stroke_to_fill.into_outline();
|
||||||
}
|
}
|
||||||
|
|
||||||
self.push_path(DrawPath::new(outline, paint_id, None, FillRule::Winding, String::new()));
|
self.push_path(DrawPath::new(outline,
|
||||||
|
paint_id,
|
||||||
|
None,
|
||||||
|
FillRule::Winding,
|
||||||
|
BlendMode::SourceOver,
|
||||||
|
String::new()));
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue