You are missing a beginPath()
on the second clip:
// 2nd clip
ctx.save();
ctx.beginPath()
ctx.rect(140,20,100,100);
ctx.stroke();
ctx.clip();
What happens is that your new rect is merged with the first one since stroking/filling does not clear the path - so both are stroked/filled again. To clear the path you must explicitly clear it using beginPath()
. As the path also is the basis for clip()
..