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();
|
||||
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_id = self.scene.push_paint(&paint);
|
||||
|
||||
|
|
|
@ -84,3 +84,14 @@ impl Default for BlendMode {
|
|||
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,
|
||||
TilingPathInfo::Draw {
|
||||
paint_metadata: &paint_metadata[paint_id.0 as usize],
|
||||
blend_mode: path_object.blend_mode(),
|
||||
built_clip_path,
|
||||
});
|
||||
|
||||
|
|
|
@ -80,6 +80,11 @@ where
|
|||
paint_texture: Option<D::Texture>,
|
||||
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_basic_program: FilterBasicProgram<D>,
|
||||
filter_basic_vertex_array: FilterBasicVertexArray<D>,
|
||||
|
@ -211,6 +216,11 @@ where
|
|||
device.create_texture(TextureFormat::R8, mask_framebuffer_size);
|
||||
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 debug_ui_presenter = DebugUIPresenter::new(&device, resources, window_size);
|
||||
|
||||
|
@ -238,6 +248,7 @@ where
|
|||
mask_framebuffer,
|
||||
paint_texture: None,
|
||||
layer_framebuffer_stack: vec![],
|
||||
clear_paint_texture,
|
||||
|
||||
filter_basic_program,
|
||||
filter_basic_vertex_array,
|
||||
|
@ -610,7 +621,15 @@ where
|
|||
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);
|
||||
uniforms.push((&self.alpha_tile_program.paint_texture_uniform,
|
||||
UniformData::TextureUnit(1)));
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
use crate::builder::{BuiltPath, ObjectBuilder, SceneBuilder, SolidTile};
|
||||
use crate::gpu_data::TileObjectPrimitive;
|
||||
use crate::paint::PaintMetadata;
|
||||
use pathfinder_content::effects::BlendMode;
|
||||
use pathfinder_content::fill::FillRule;
|
||||
use pathfinder_content::outline::{Contour, Outline, PointIndex};
|
||||
use pathfinder_content::segment::Segment;
|
||||
|
@ -42,7 +43,11 @@ pub(crate) struct Tiler<'a> {
|
|||
#[derive(Clone, Copy)]
|
||||
pub(crate) enum TilingPathInfo<'a> {
|
||||
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> {
|
||||
|
@ -122,10 +127,10 @@ impl<'a> Tiler<'a> {
|
|||
}
|
||||
|
||||
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::Draw { paint_metadata, built_clip_path } => {
|
||||
(paint_metadata, built_clip_path)
|
||||
TilingPathInfo::Draw { paint_metadata, blend_mode, built_clip_path } => {
|
||||
(paint_metadata, blend_mode, built_clip_path)
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -174,8 +179,9 @@ impl<'a> Tiler<'a> {
|
|||
(FillRule::EvenOdd, _) => {}
|
||||
}
|
||||
|
||||
// Next, if this is a solid tile, record that fact and stop here.
|
||||
if paint_metadata.is_opaque {
|
||||
// Next, if this is a solid tile that completely occludes the background, record
|
||||
// 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));
|
||||
continue;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue