Skip to content

Commit 05d10b1

Browse files
authored
fix: shadow is not applied with transform correctly (#1124)
1 parent e0b76b9 commit 05d10b1

File tree

3 files changed

+44
-3
lines changed

3 files changed

+44
-3
lines changed

__test__/regression.spec.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -528,3 +528,32 @@ test('pass invalid args to setLineDash should not throw', (t) => {
528528
])
529529
})
530530
})
531+
532+
// https://github.com/Brooooooklyn/canvas/issues/1121
533+
test('shadow-offset-with-transform', async (t) => {
534+
// Test for issue #1121 - shadow offset should be in device coordinates
535+
const canvas = createCanvas(300, 300)
536+
const ctx = canvas.getContext('2d')
537+
538+
// Fill with white background
539+
ctx.fillStyle = 'white'
540+
ctx.fillRect(0, 0, 300, 300)
541+
542+
// Apply transform - scale down by 0.5 and translate
543+
ctx.transform(0.5, 0, 0, 0.5, 100, 100)
544+
545+
// Set shadow properties
546+
ctx.shadowColor = 'rgba(0, 0, 0, 1)'
547+
ctx.shadowBlur = 0
548+
ctx.shadowOffsetX = 5
549+
ctx.shadowOffsetY = 5
550+
551+
// Draw green rectangle
552+
ctx.fillStyle = 'green'
553+
ctx.rect(0, 0, 100, 100)
554+
ctx.fill()
555+
556+
// The shadow should be offset by exactly 5px in both X and Y directions
557+
// in device/screen coordinates, regardless of the transform applied
558+
await snapshotImage(t, { canvas, ctx }, 'png', 0.3)
559+
})
1.12 KB
Loading

src/ctx.rs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -969,9 +969,21 @@ impl Context {
969969
shadow_offset_x: f32,
970970
shadow_offset_y: f32,
971971
) -> result::Result<(), SkError> {
972-
let mut shadow_transform = canvas.get_transform_matrix().clone();
973-
shadow_transform.pre_translate(shadow_offset_x, shadow_offset_y);
974-
canvas.set_transform(&shadow_transform);
972+
// Following CanvasKit's approach: apply shadow offset in device coordinates
973+
// by inverting the current transform, applying the offset, then re-applying the transform
974+
let current_transform = canvas.get_transform_matrix().clone();
975+
976+
// Invert the current transform to get back to device coordinates
977+
if let Some(inverted) = current_transform.invert() {
978+
canvas.concat(&inverted);
979+
// Apply shadow offset in device coordinates
980+
canvas.concat(&Matrix::translated(shadow_offset_x, shadow_offset_y));
981+
// Re-apply the original transform
982+
canvas.concat(&current_transform);
983+
} else {
984+
// If the transform is not invertible, fall back to simple translation
985+
canvas.concat(&Matrix::translated(shadow_offset_x, shadow_offset_y));
986+
}
975987
Ok(())
976988
}
977989

0 commit comments

Comments
 (0)