Using CORS to load WebGL textures from cross-domain images

In Firefox, as well as in Chrome, it is now possible to load cross-domain images into WebGL textures, if they have been approved by CORS.

Most prominently, this feature allows for impressive 3D mapping applications such as Google MapsGL and Nokia Maps 3D.

What happened

Earlier this year, the Editor’s Draft WebGL specification got updated in response to a security concern. The additions were:

  1. A mandatory clause disallowing usage of cross-domain elements as WebGL textures in the general case.
  2. A non-normative clause specifically allowing cross-domain elements that have CORS approval. For that occasion, the HTML specification on the <img> element got updated to add a new crossorigin attribute.

The first got implemented in Firefox 5, the second is now in Firefox 8.

How to use this feature

There are two CORS modes: “anonymous” and “use-credentials”. We’ll focus on “anonymous” as it’s the common case. A great example of images served with anonymous CORS is Google Maps imagery, such as:

In order to load it with CORS as a WebGL texture, we set the crossOrigin attribute on it:

var earthImage = new Image();
earthImage.crossOrigin = "anonymous";

Now we load it as usual:

    earthImage.onload = function() {
      // whatever you usually to do load WebGL textures
    earthImage.src = "";

That’s it! Aside from setting the crossOrigin attribute, we didn’t have to do anything. Here is the full self-contained example.

The HTTP headers

If we study the HTTP headers for this image (using, for example, Firefox’s Web Console), we find that the Request Headers contain

Origin: null

which is the effect of having set this crossOrigin attribute on the img element. And the Response Headers contain

Access-Control-Allow-Origin: null

which is the effect of the server supporting CORS for this file.

Doing this in HTML

Of course, one could also set this attribute in HTML, in which case it’s case-insensitive:

<img src="" crossorigin="anonymous">

And since “anonymous” is both the missing-value-default and the invalid-value-default for the crossorigin attribute, we can pass any invalid value for it, or even just omit its value:

<img src="" crossorigin>

Coming soon: CORS approval for Canvas 2D drawImage

What if you first draw a CORS-approved cross-domain image onto a 2D
canvas, and then use that canvas as the source of a WebGL texture? The
good news is that this will work in Firefox 9, which is hitting the Beta
channel soon. This fix means that demos like this will work really
nicely in Firefox 9.


Comments are now closed.

  1. Henri Astre wrote on November 8th, 2011 at 14:34:

    In a very particular context, I’ve found a workaround that permit to bypass the sop restriction:

    What do you think of this?

  2. Benoit Jacob wrote on November 8th, 2011 at 19:43:

    @Henri: I think it’s smart! Hopefully though, we’ll manage to evangelize content providers to support CORS so that that won’t be needed in the future.

  3. Ben Adams wrote on November 10th, 2011 at 07:51:

    This is fantastic news! Good job!

  4. Bill wrote on December 15th, 2011 at 18:20:

    Is there any way to disable the CORS check for testing purposes? If your actual app and data normally are served from but you want to try debugging your app locally with a server running off localhost, it’s handy to be able to turn off the security check temporarily. Chrome does that with a –disable-web-security flag on startup.

    1. Benoit Jacob wrote on December 15th, 2011 at 21:01:

      I’m not aware of such a feature in Firefox. For local URIs there is security.fileuri.strict_origin_policy=false but I don’t know about remote ones. Would be worth filing a bug, i think (if you do, CC me please, :bjacob)

  5. Henri Astre wrote on December 17th, 2011 at 15:55:

    @Bill: for local debugging I’m using a php proxy page using curl extension. I’ve also updated and released the source code of a workaround to bypass sop restriction (only working for chrome/firefox(?) extension). My new workaround is way much faster than the previous one which was doing jpeg decoding in js:

Comments are closed for this article.