Fix rendering semi-opaque paths with "Outside" stroke alignment (#4110)

This commit is contained in:
Keavon Chambers 2026-05-06 01:26:43 -07:00 committed by GitHub
parent 269a217cf9
commit 39a7c45ccd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 6 additions and 18 deletions

View File

@ -923,7 +923,6 @@ impl Render for Table<Vector> {
let blend_mode_attr: BlendMode = self.attribute_cloned_or_default(ATTR_BLEND_MODE, index); let blend_mode_attr: BlendMode = self.attribute_cloned_or_default(ATTR_BLEND_MODE, index);
let opacity_attr: f64 = self.attribute_cloned_or(ATTR_OPACITY, index, 1.); let opacity_attr: f64 = self.attribute_cloned_or(ATTR_OPACITY, index, 1.);
let opacity_fill_attr: f64 = self.attribute_cloned_or(ATTR_OPACITY_FILL, index, 1.); let opacity_fill_attr: f64 = self.attribute_cloned_or(ATTR_OPACITY_FILL, index, 1.);
let clipping_mask_attr: bool = self.attribute_cloned_or_default(ATTR_CLIPPING_MASK, index);
// Only consider strokes with non-zero weight, since default strokes with zero weight would prevent assigning the correct stroke transform // Only consider strokes with non-zero weight, since default strokes with zero weight would prevent assigning the correct stroke transform
let has_real_stroke = vector.style.stroke().filter(|stroke| stroke.weight() > 0.); let has_real_stroke = vector.style.stroke().filter(|stroke| stroke.weight() > 0.);
@ -986,14 +985,9 @@ impl Render for Table<Vector> {
cloned_vector.style.clear_stroke(); cloned_vector.style.clear_stroke();
cloned_vector.style.set_fill(Fill::solid(Color::BLACK)); cloned_vector.style.set_fill(Fill::solid(Color::BLACK));
let vector_item = Table::new_from_row( // The mask must draw at full alpha so the SVG `<mask>`/`<clipPath>` fully zeroes the path interior.
TableRow::new_from_element(cloned_vector) // The wrapping SVG group (above) handles the user-set opacity.
.with_attribute(ATTR_TRANSFORM, multiplied_transform) let vector_item = Table::new_from_row(TableRow::new_from_element(cloned_vector).with_attribute(ATTR_TRANSFORM, multiplied_transform));
.with_attribute(ATTR_BLEND_MODE, blend_mode_attr)
.with_attribute(ATTR_OPACITY, opacity_attr)
.with_attribute(ATTR_OPACITY_FILL, opacity_fill_attr)
.with_attribute(ATTR_CLIPPING_MASK, clipping_mask_attr),
);
(id, mask_type, vector_item) (id, mask_type, vector_item)
}); });
@ -1125,7 +1119,6 @@ impl Render for Table<Vector> {
let blend_mode_attr: BlendMode = self.attribute_cloned_or_default(ATTR_BLEND_MODE, index); let blend_mode_attr: BlendMode = self.attribute_cloned_or_default(ATTR_BLEND_MODE, index);
let opacity_attr: f64 = self.attribute_cloned_or(ATTR_OPACITY, index, 1.); let opacity_attr: f64 = self.attribute_cloned_or(ATTR_OPACITY, index, 1.);
let opacity_fill_attr: f64 = self.attribute_cloned_or(ATTR_OPACITY_FILL, index, 1.); let opacity_fill_attr: f64 = self.attribute_cloned_or(ATTR_OPACITY_FILL, index, 1.);
let clip_attr: bool = self.attribute_cloned_or_default(ATTR_CLIPPING_MASK, index);
let multiplied_transform = parent_transform * item_transform; let multiplied_transform = parent_transform * item_transform;
let has_real_stroke = element.style.stroke().filter(|stroke| stroke.weight() > 0.); let has_real_stroke = element.style.stroke().filter(|stroke| stroke.weight() > 0.);
let set_stroke_transform = has_real_stroke.map(|stroke| stroke.transform).filter(|transform| transform.matrix2.determinant() != 0.); let set_stroke_transform = has_real_stroke.map(|stroke| stroke.transform).filter(|transform| transform.matrix2.determinant() != 0.);
@ -1317,14 +1310,9 @@ impl Render for Table<Vector> {
cloned_element.style.clear_stroke(); cloned_element.style.clear_stroke();
cloned_element.style.set_fill(Fill::solid(Color::BLACK)); cloned_element.style.set_fill(Fill::solid(Color::BLACK));
let vector_table = Table::new_from_row( // The mask must draw at full alpha so `SrcOut` fully zeroes the path interior.
TableRow::new_from_element(cloned_element) // The outer opacity/blend layer (above) handles the user-set opacity.
.with_attribute(ATTR_TRANSFORM, item_transform) let vector_table = Table::new_from_row(TableRow::new_from_element(cloned_element).with_attribute(ATTR_TRANSFORM, item_transform));
.with_attribute(ATTR_BLEND_MODE, blend_mode_attr)
.with_attribute(ATTR_OPACITY, opacity_attr)
.with_attribute(ATTR_OPACITY_FILL, opacity_fill_attr)
.with_attribute(ATTR_CLIPPING_MASK, clip_attr),
);
let bounds = element.bounding_box_with_transform(multiplied_transform).unwrap_or(layer_bounds); let bounds = element.bounding_box_with_transform(multiplied_transform).unwrap_or(layer_bounds);
// This branch is gated on `can_draw_aligned_stroke`, which already requires every subpath is closed // This branch is gated on `can_draw_aligned_stroke`, which already requires every subpath is closed