Skip to content

Instantly share code, notes, and snippets.

@flapenguin
Created April 19, 2017 21:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save flapenguin/5503b96e235c2a8fc1197ff634eba7bc to your computer and use it in GitHub Desktop.
Save flapenguin/5503b96e235c2a8fc1197ff634eba7bc to your computer and use it in GitHub Desktop.
Firefox foreignObject background-image canvas rendering bug
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<meta http-equiv="Cache-Control" content="no-cache">
<title>Firefox foreignObject background-image canvas rendering bug</title>
<style>
td { border: 1px darkblue solid; }
</style>
</head>
<body>
<button id="reproduce">reproduce</button>
<table>
<tr>
<td>img</td>
<td>canvas</td>
</tr>
<tr>
<td><img id="src"></td>
<td><canvas id="dst"></canvas></td>
</tr>
</table>
<script>
document.body.onload = async () => {
try {
await main();
} catch (e) {
console.error(e);
}
};
async function main() {
const N = +(location.search.replace(/^\?/, '')||'0');
document.querySelector('#reproduce').onclick = () => {
window.location = window.location.href.replace(/(\?\d*)?$/, `?${N+1}`);
};
const image = document.querySelector('#image'),
{width, height} = image.dataset;
let imageUrl = image.innerText.trim();
// Add three dummy zero bytes to the end of png N times to confuse cache.
imageUrl = imageUrl.replace(/=*$/, 'AAAA'.repeat(N) + '$&');
const svg = `
<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}">
<foreignObject width="100%" height="100%">
<div xmlns="http://www.w3.org/1999/xhtml" style="position: relative;">
<div style="background: url(${imageUrl}); width: ${width}px; height: ${height}px;"></div>
</div>
</foreignObject>
</svg>
`;
const svgUrl = URL.createObjectURL(new Blob([svg], { type: 'image/svg+xml' }));
const src = document.querySelector('#src');
src.width = width;
src.height = height;
await new Promise((resolve, reject) => {
src.onload = resolve;
src.onerror = reject;
src.src = svgUrl;
});
const ctx = document.querySelector('#dst').getContext('2d');
ctx.canvas.width = width;
ctx.canvas.height = height;
URL.revokeObjectURL(svgUrl);
ctx.drawImage(src, 0, 0);
};
</script>
<script id="image" type="text/plain" data-width="32" data-height="32">
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgAQAAAAEsBnfPAAAABGdBTUEAAYagMeiWXwAAAJBJREFUeJwtjTEOwjAMRd/GgsQVGHoApC4Zergeg7En4AxWOQATY6WA2FgsZckQNXxLeLC/v99PcBaMGeesuXCj8tHe2Wlc5b9ZY9/ZKq9Mn9kn6kSeZIffW5w255m5G98IK01L1AFP5AFLAat6F67mlNKNMootY4N6cEUeFkhwLZqf9KEdL3pRqiHloYx//QCU41EdZhgi8gAAAABJRU5ErkJggg==
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment