Fix handling of solid tiles with the Clear blend mode
This commit is contained in:
parent
6acd2d91f7
commit
ab55b9509b
|
@ -99,7 +99,7 @@ impl CanvasRenderingContext2D {
|
||||||
let mut outline = path.into_outline();
|
let mut outline = path.into_outline();
|
||||||
outline.transform(&self.current_state.transform);
|
outline.transform(&self.current_state.transform);
|
||||||
|
|
||||||
let paint = Paint::black();
|
let paint = Paint::transparent_black();
|
||||||
let paint = self.current_state.resolve_paint(&paint);
|
let paint = self.current_state.resolve_paint(&paint);
|
||||||
let paint_id = self.scene.push_paint(&paint);
|
let paint_id = self.scene.push_paint(&paint);
|
||||||
|
|
||||||
|
|
|
@ -84,3 +84,14 @@ impl Default for BlendMode {
|
||||||
BlendMode::SourceOver
|
BlendMode::SourceOver
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl BlendMode {
|
||||||
|
/// Whether the backdrop is irrelevant when applying this blend mode (i.e. destination blend
|
||||||
|
/// factor is zero).
|
||||||
|
#[inline]
|
||||||
|
pub fn occludes_backdrop(self) -> bool {
|
||||||
|
match self {
|
||||||
|
BlendMode::SourceOver | BlendMode::Clear => true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -168,6 +168,7 @@ impl<'a> SceneBuilder<'a> {
|
||||||
path_index as u16,
|
path_index as u16,
|
||||||
TilingPathInfo::Draw {
|
TilingPathInfo::Draw {
|
||||||
paint_metadata: &paint_metadata[paint_id.0 as usize],
|
paint_metadata: &paint_metadata[paint_id.0 as usize],
|
||||||
|
blend_mode: path_object.blend_mode(),
|
||||||
built_clip_path,
|
built_clip_path,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -80,6 +80,11 @@ where
|
||||||
paint_texture: Option<D::Texture>,
|
paint_texture: Option<D::Texture>,
|
||||||
layer_framebuffer_stack: Vec<LayerFramebufferInfo<D>>,
|
layer_framebuffer_stack: Vec<LayerFramebufferInfo<D>>,
|
||||||
|
|
||||||
|
// This is a dummy texture consisting solely of a single `rgba(0, 0, 0, 255)` texel. It serves
|
||||||
|
// as the paint texture when drawing alpha tiles with the Clear blend mode. If this weren't
|
||||||
|
// used, then the transparent black paint would zero out the alpha mask.
|
||||||
|
clear_paint_texture: D::Texture,
|
||||||
|
|
||||||
// Filter shaders
|
// Filter shaders
|
||||||
filter_basic_program: FilterBasicProgram<D>,
|
filter_basic_program: FilterBasicProgram<D>,
|
||||||
filter_basic_vertex_array: FilterBasicVertexArray<D>,
|
filter_basic_vertex_array: FilterBasicVertexArray<D>,
|
||||||
|
@ -211,6 +216,11 @@ where
|
||||||
device.create_texture(TextureFormat::R8, mask_framebuffer_size);
|
device.create_texture(TextureFormat::R8, mask_framebuffer_size);
|
||||||
let mask_framebuffer = device.create_framebuffer(mask_framebuffer_texture);
|
let mask_framebuffer = device.create_framebuffer(mask_framebuffer_texture);
|
||||||
|
|
||||||
|
let clear_paint_texture =
|
||||||
|
device.create_texture_from_data(TextureFormat::RGBA8,
|
||||||
|
Vector2I::splat(1),
|
||||||
|
TextureDataRef::U8(&[0, 0, 0, 255]));
|
||||||
|
|
||||||
let window_size = dest_framebuffer.window_size(&device);
|
let window_size = dest_framebuffer.window_size(&device);
|
||||||
let debug_ui_presenter = DebugUIPresenter::new(&device, resources, window_size);
|
let debug_ui_presenter = DebugUIPresenter::new(&device, resources, window_size);
|
||||||
|
|
||||||
|
@ -238,6 +248,7 @@ where
|
||||||
mask_framebuffer,
|
mask_framebuffer,
|
||||||
paint_texture: None,
|
paint_texture: None,
|
||||||
layer_framebuffer_stack: vec![],
|
layer_framebuffer_stack: vec![],
|
||||||
|
clear_paint_texture,
|
||||||
|
|
||||||
filter_basic_program,
|
filter_basic_program,
|
||||||
filter_basic_vertex_array,
|
filter_basic_vertex_array,
|
||||||
|
@ -610,7 +621,15 @@ where
|
||||||
MASK_FRAMEBUFFER_HEIGHT as f32))),
|
MASK_FRAMEBUFFER_HEIGHT as f32))),
|
||||||
];
|
];
|
||||||
|
|
||||||
let paint_texture = self.paint_texture.as_ref().unwrap();
|
let paint_texture = match blend_mode {
|
||||||
|
BlendMode::Clear => {
|
||||||
|
// Use a special dummy paint texture containing `rgba(0, 0, 0, 255)` so that the
|
||||||
|
// transparent black paint color doesn't zero out the mask.
|
||||||
|
&self.clear_paint_texture
|
||||||
|
}
|
||||||
|
_ => self.paint_texture.as_ref().unwrap(),
|
||||||
|
};
|
||||||
|
|
||||||
textures.push(paint_texture);
|
textures.push(paint_texture);
|
||||||
uniforms.push((&self.alpha_tile_program.paint_texture_uniform,
|
uniforms.push((&self.alpha_tile_program.paint_texture_uniform,
|
||||||
UniformData::TextureUnit(1)));
|
UniformData::TextureUnit(1)));
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
use crate::builder::{BuiltPath, ObjectBuilder, SceneBuilder, SolidTile};
|
use crate::builder::{BuiltPath, ObjectBuilder, SceneBuilder, SolidTile};
|
||||||
use crate::gpu_data::TileObjectPrimitive;
|
use crate::gpu_data::TileObjectPrimitive;
|
||||||
use crate::paint::PaintMetadata;
|
use crate::paint::PaintMetadata;
|
||||||
|
use pathfinder_content::effects::BlendMode;
|
||||||
use pathfinder_content::fill::FillRule;
|
use pathfinder_content::fill::FillRule;
|
||||||
use pathfinder_content::outline::{Contour, Outline, PointIndex};
|
use pathfinder_content::outline::{Contour, Outline, PointIndex};
|
||||||
use pathfinder_content::segment::Segment;
|
use pathfinder_content::segment::Segment;
|
||||||
|
@ -42,7 +43,11 @@ pub(crate) struct Tiler<'a> {
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub(crate) enum TilingPathInfo<'a> {
|
pub(crate) enum TilingPathInfo<'a> {
|
||||||
Clip,
|
Clip,
|
||||||
Draw { paint_metadata: &'a PaintMetadata, built_clip_path: Option<&'a BuiltPath> },
|
Draw {
|
||||||
|
paint_metadata: &'a PaintMetadata,
|
||||||
|
blend_mode: BlendMode,
|
||||||
|
built_clip_path: Option<&'a BuiltPath>,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Tiler<'a> {
|
impl<'a> Tiler<'a> {
|
||||||
|
@ -122,10 +127,10 @@ impl<'a> Tiler<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pack_and_cull_draw_path(&mut self) {
|
fn pack_and_cull_draw_path(&mut self) {
|
||||||
let (paint_metadata, built_clip_path) = match self.path_info {
|
let (paint_metadata, blend_mode, built_clip_path) = match self.path_info {
|
||||||
TilingPathInfo::Clip => unreachable!(),
|
TilingPathInfo::Clip => unreachable!(),
|
||||||
TilingPathInfo::Draw { paint_metadata, built_clip_path } => {
|
TilingPathInfo::Draw { paint_metadata, blend_mode, built_clip_path } => {
|
||||||
(paint_metadata, built_clip_path)
|
(paint_metadata, blend_mode, built_clip_path)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -174,8 +179,9 @@ impl<'a> Tiler<'a> {
|
||||||
(FillRule::EvenOdd, _) => {}
|
(FillRule::EvenOdd, _) => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Next, if this is a solid tile, record that fact and stop here.
|
// Next, if this is a solid tile that completely occludes the background, record
|
||||||
if paint_metadata.is_opaque {
|
// that fact and stop here.
|
||||||
|
if paint_metadata.is_opaque && blend_mode.occludes_backdrop() {
|
||||||
self.object_builder.built_path.solid_tiles.push(SolidTile::new(tile_coords));
|
self.object_builder.built_path.solid_tiles.push(SolidTile::new(tile_coords));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue