Составные операции работают на альфа-канале и, следовательно, плохо сочетаются с тенями.
К сожалению, я думаю, что вы мало что можете сделать, чтобы обойти это для своей тени на прозрачном фоне, более тогодля круга.
Одна маленькая вещь, которую я вижу, это то, что вам на самом деле не нужна часть xor, и вы можете заменить ее на путь, состоящий из прямоугольника и дуги, которую вы бы заполнили как 'даже странно'.Это создаст дыру напрямую, уменьшив немного артефактов сглаживания.
drawOP();
drawEvenOdd();
function drawEvenOdd() {
let canvas = document.getElementById('evenodd');
canvas.width = 150;
canvas.height = 200;
let ctx = canvas.getContext('2d')
ctx.textAlign = 'center';
ctx.shadowColor = 'black';
ctx.shadowBlur = 10 * 2;
ctx.shadowOffsetY = 5;
ctx.beginPath();
ctx.rect(0, 0, canvas.width, canvas.height);
ctx.arc(100, 100, 50, 0, 2 * Math.PI);
// will draw an hole
ctx.fill('evenodd');
// remove shadow
ctx.shadowColor = 'transparent';
ctx.shadowBlur = ctx.shadowOffsetY = 0;
ctx.globalCompositeOperation = 'destination-out';
ctx.fill('evenodd');
ctx.globalCompositeOperation = 'source-over';
ctx.fillText('evenodd', 100, 180)
}
function drawOP() {
let canvas = document.getElementById('OP')
canvas.width = 150;
canvas.height = 200;
let ctx = canvas.getContext('2d')
ctx.textAlign = 'center';
ctx.fillStyle = 'black'
ctx.fillRect(0, 0, canvas.width, canvas.height)
ctx.globalCompositeOperation = 'xor'
ctx.arc(100, 100, 50, 0, 2 * Math.PI)
ctx.fill()
ctx.filter = 'drop-shadow(0 5px 10px black)'
ctx.drawImage(canvas, 0, 0)
ctx.filter = 'none';
ctx.fillText('OP', 100, 180)
}
<canvas id="OP"></canvas>
<canvas id="evenodd"></canvas>