Firefox 76 not rendering texture loaded from SVG (Chrome & Safari work fine)

Hi,

I seem to be having a problem with Firefox 76 using a texture from an SVG that is already loaded in the browser (I’m on macOS Catalina, haven’t tried Windows / Linux).

In Chrome (v84) and Safari (v13.1), the code works perfectly, and I see both the SVG and a three.js scene containing a cube with the SVG texture on it.

In Firefox, I see just the SVG, and an empty three.js scene (although it’s probably a scene with a cube that has no texture).

Here’s the code of the SVG file, firefoxSvgTest.svg:

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 400">
  <defs>
    <radialGradient id="A" cx="2350.96" cy="-538.75" r="121.43" gradientTransform="matrix(-2.1, -1.56, 1.99, -1.58, 6244.43, 2993.03)" gradientUnits="userSpaceOnUse">
      <stop offset="0" stop-color="#ff0000"/>
      <stop offset=".2" stop-color="#00ff00"/>
      <stop offset=".4" stop-color="#0000ff"/>
      <stop offset=".6" stop-color="#ffff00"/>
      <stop offset=".8" stop-color="#00ffff"/>
    </radialGradient>
  </defs>
  <path d="M0 0h400v400H0z" fill="url(#A)"/>
  <path d="M100 100.7h200v200h-200v-200z" fill="#fff"/>
</svg>

And here’s my test harness:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Firefox texture bug</title>

    <script type="text/javascript" src="three.116.master.js"></script>

    <script>
      window.addEventListener('load', () => {

        const scene = new THREE.Scene();
        const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );

        const renderer = new THREE.WebGLRenderer();
        renderer.setSize( 400, 400 );
        document.body.appendChild( renderer.domElement );

        const ambientLight = new THREE.AmbientLight( 0xffffff );
        scene.add( ambientLight );

        const cubeTexture = new THREE.Texture(
          document.getElementById('svgTexture'),
          THREE.UVMapping,
          THREE.RepeatWrapping,
          THREE.RepeatWrapping
        );
        cubeTexture.needsUpdate = true;
        const cubeMaterial = new THREE.MeshPhongMaterial( { map: cubeTexture, side: THREE.DoubleSide } );
        const cubeGeometry = new THREE.BoxBufferGeometry( 2, 2, 2 );
        const cubeMesh = new THREE.Mesh( cubeGeometry, cubeMaterial );
        cubeMesh.rotation.x = 0.5;
        cubeMesh.rotation.y = 0.5;
        scene.add( cubeMesh );

        camera.position.z = 5;
        renderer.render( scene, camera );

      }, false);
    </script>
  </head>

 <body>
   <img id="svgTexture" src="firefoxSvgTest.svg" style="width:400px; height:400px;">
  </body>
</html>

I’m running this through a web server with the HTML file, SVG file, and three.js files all in the same folder - so there are no file:// or CORS issues at play here.

The only thing showing in the Firefox console is the same as in Chrome and Safari: a warning that the texture has been resized from 400x400 down to 256x256, so I’ve got no errors to give me a hint as to why this isn’t working.

This doesn’t seem to be an issue with the radial gradient, as I can replace the SVG code with that containing just a single path filled with a solid colour, and the outcome is the same.

Can anyone see where I’m going wrong, or is this a bug with Firefox?

Incidentally, I’m only using this method as I couldn’t figure out how to get a radial gradient in three.js (the square shape drawn on top of the gradient is irrelevant, I just wanted to prove it wasn’t the lack of a solidly-filled path causing the problem)… so if anyone knows of a way to get a radial gradient texture, I can stop using the SVG altogether. However, it would be nice to get to the bottom of this issue!

Here’s how the code looks in Chrome and Firefox when run:

Chrome

Firefox

Thanks,

Dan

Looks like it’s the same issue as bug 700533 in Firefox.

In a nutshell, Firefox refuses to draw SVG images to a <canvas> unless the SVG root element has both a width and a height attribute, even if the dimensions are specified in the viewBox attribute.

Once I add a width and height attribute, three.js renders it in the same way as Chrome and Safari.

2 Likes