Closed Bug 574330 Opened 14 years ago Closed 9 years ago

NS_ERROR_NOT_AVAILABLE with canvas.drawImage and Image.onload

Categories

(Core :: Graphics: ImageLib, defect)

x86
Windows CE
defect
Not set
normal

Tracking

()

RESOLVED INCOMPLETE
Tracking Status
blocking2.0 --- -

People

(Reporter: tobias.sauerwein, Unassigned, NeedInfo)

References

(Blocks 1 open bug)

Details

(Keywords: regressionwindow-wanted, testcase)

Attachments

(2 files, 1 obsolete file)

User-Agent:       Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3
Build Identifier: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3

Canvas.drawImage fails sometimes for some images with the following error message:

[Exception... "Component returned failure code: 0x80040111 (NS_ERROR_NOT_AVAILABLE) [nsIDOMCanvasRenderingContext2D.drawImage]" nsresult: "0x80040111 (NS_ERROR_NOT_AVAILABLE)" location: "JS frame :: file:///home/../firefox-image-onload.html :: anonymous :: line 20" data: no] { message="Component returned fail...ingContext2D.drawImage]",  more...}

This is the used code:

var requestImage = new Image();
requestImage.onload = function() {
  context.drawImage(this, 0, 0);
}
requestImage.src = '..';

Reproducible: Sometimes

Steps to Reproduce:
1. Activate Firebugs 
2. Open the attached file 'firefox-image-onload.html'
3. The script will load a bunch of images and draw them onto a canvas element. If an image can not be drawn, it will be displayed in a 'img' element, to demonstrate that there is nothing wrong about this image.
Actual Results:  
After a while, there is an image that can not be drawn, for example:

onload http://labs.metacarta.com/wms/vmap0?LAYERS=basic&SERVICE=WMS&VERSION=1.1.1&REQUEST=GetMap&STYLES=&EXCEPTIONS=application%2Fvnd.ogc.se_inimage&FORMAT=image%2Fjpeg&SRS=EPSG%3A4326&WIDTH=256&HEIGHT=256&BBOX=-180,-90,-170,-80
onload http://labs.metacarta.com/wms/vmap0?LAYERS=basic&SERVICE=WMS&VERSION=1.1.1&REQUEST=GetMap&STYLES=&EXCEPTIONS=application%2Fvnd.ogc.se_inimage&FORMAT=image%2Fjpeg&SRS=EPSG%3A4326&WIDTH=256&HEIGHT=256&BBOX=-170,-80,-160,-70
drawing failed http://labs.metacarta.com/wms/vmap0?LAYERS=basic&SERVICE=WMS&VERSION=1.1.1&REQUEST=GetMap&STYLES=&EXCEPTIONS=application%2Fvnd.ogc.se_inimage&FORMAT=image%2Fjpeg&SRS=EPSG%3A4326&WIDTH=256&HEIGHT=256&BBOX=-170,-80,-160,-70
[Exception... "Component returned failure code: 0x80040111 (NS_ERROR_NOT_AVAILABLE) [nsIDOMCanvasRenderingContext2D.drawImage]" nsresult: "0x80040111 (NS_ERROR_NOT_AVAILABLE)" location: "JS frame :: file:///home/../firefox-image-onload.html :: anonymous :: line 19" data: no] { message="Component returned fail...ingContext2D.drawImage]", more...}

Expected Results:  
All images should be drawn on the canvas element.
Attached file Test script to reproduce the error (deleted) —
I have also experienced this same exact bug in Firefox version 3.6.8.

Tried the "bad" and "good" coding practice shown in the link below, but the problem persists.

Link: http://www.thefutureoftheweb.com/blog/image-onload-isnt-being-called
https://developer.mozilla.org/en/Canvas_tutorial/Using_images

The page above claims that "if loading isn't finished when a drawImage statement gets executed, the script halts until the image is finished loading", but this doesn't seem to be the case.

The above article recommends following this method, which it claims will wait for the image to load before processing any further script:

var requestImage = new Image();
requestImage.src = '..';

However, this always creates the NS_ERROR_NOT_AVAILABLE error in my tests. The other method is this:

var requestImage = new Image();
requestImage.onload = function() {
  context.drawImage(this, 0, 0);
}
requestImage.src = '..';

Which works perfectly well over 90% of the time in my case, but does occasionally produce the NS_ERROR_NOT_AVAILABLE error.
We are getting this bug as well. It only seems to have started happening recently. I'm wondering if the fix for bug 517056 caused this bug. As the previous poster says, it works okay most of the time, but sometimes comes back with NS_ERROR_NOT_AVAILABLE. The image should load ok, but we are sometimes getting an exception thrown inside the img.onload when we call drawImage(). When the exception is thrown img.complete is false, which obviously should never happen (because it is inside onload).
Bug 517056 was only fixed on the trunk (so for Gecko 2.0 and Firefox 4.0).  It can't have changed behavior on the 3.6 branch.

Bobby, does 3.6 do some sort of lazy image decoding or something?  The code in comment 0 should really work, I would think.

The "Using images" page is just wrong.  I'll update it.
(In reply to comment #5)
> Bug 517056 was only fixed on the trunk (so for Gecko 2.0 and Firefox 4.0).  It
> can't have changed behavior on the 3.6 branch.
> 
> Bobby, does 3.6 do some sort of lazy image decoding or something?

It doesn't.

Not really sure what's going on here. Nothing significant that I've done to imagelib is in 3.6, so it must be some other issue.
Well, the NOT_AVAILABLE error means STATUS_LOAD_COMPLETE wasn't set.  But onload did fire, which means OnStopDecode was called (_and_ the event loop got spun afterward).  Can that happen?

David, can you perhaps point me to a page that shows the problem for you?
Try here: http://dev.groupboard.com/ajax/devtest2.html

Just click 'set background' and choose an image. Sometimes it works, sometimes you get the NS_ERROR_NOT_AVAILABLE exception which I display as an alert() along with the img.complete status, all of which is inside the img.onload
Hmm.  I can't seem to reproduce the problem so far...

Just to make sure we're on the same page, do you see the problem in safe mode?
Note that that page triggers a draw in the onerror handler too, as far as I can tell.  Are you sure that's not the codepath being taken here?
I get the exception immediately, even in safe mode. I'm running Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8 ( .NET CLR 3.5.30729).

Also, I checked the code and there doesn't appear to be a draw in the onerror. here is the onerror function:

                img.onerror = function()
                {
                    //alert("Error loading image "+img.src);
                    g.paused = false;
                }
Yes, and here's the onload function:

        img.onload = function()
        {
            g.paused = false;
        }

They do the same exact thing.
I think you're looking at a different codepath. Here is the one that is generating the error:

                img.onload = function()
                {
                    try
                    {
                        if (g.centre_in_window)
                        {
                            g.wb.drawImage(img, g.board_width/2-img.width/2, g.board_height/2-img.height/2);
                        }
                        else
                        {
                            g.wb.drawImage(img, 0, 0);
                        }
                    }
                    catch (ex)
                    {
                        alert("Error loading image "+img.src+" ("+ex+"),complete="+img.complete);
                    }
                    g.paused = false;
                }
                img.onerror = function()
                {
                    //alert("Error loading image "+img.src);
                    g.paused = false;
                }
                g.paused = true; // don't draw anything else until image loaded
                img.src = g.backgrounds_url + url;
 
It is the alert() inside the above catch() that I am seeing, and it is saying the complete=false.
Note: I've ran about 30-40 tests and as of yet I'm unable to reproduce the bug I mentioned in comments #2 and #3 when using Firefox version 4 beta 4 (4.0b4). I may have just been lucky so far but this seems promising.
Bug still occurred in 4.0b2, but I just downloaded 4.0b4 and it seems to be working ok for me. Did quite a few tests, quit and restarted browser, loaded some new images and some which would have been in cache, and it all seemed to work ok. So it looks like this bug might have been fixed between 4.0b2 and b4. Perhaps bug 517056 has actually fixed this bug rather than caused it.
Well, fx4b4 will never throw when you drawImage an unloaded image.  That's what bug 517056 was all about. It will just silently do nothing instead.

David, thanks for the pointer to the code involved.  Is the relevant callsite the one that passes null as the second argument to draw_background_pic, I assume?
Yes, in this case the second param will be null so it is creating a new Image.
OK.  Do you see the problem in safe mode too?
Yes, I see the problem in safe mode under 3.6.8.
I can confirm that this bug is happening often in my production website.
My page has an window.onerror handler which reports script errors back to the server, and I see the NS_ERROR_NOT_AVAILABLE exception often in the log for Firefox/3.5.8 to Firefox/3.6.10

This error happens because IMG.ONLOAD FIRES BEFORE THE IMAGE IS FULLY DOWNLOADED.

I can confirm that when the image onload handler is called, the "complete" property is "false", and drawImage throws and exception.

I can confirm that, if the code waits 3 seconds after onload, the complete flag becomes true and drawImage does not throw and exception, so there is no fundamental problem with the image, the problem is that onload fires prematurely. 

I can confirm that the image onabort and onerror handlers are not called, and the image width and height contain the correct values.

I don't have a test case as this seems to be a random timing thing. Here is a sampling of agent strings of browsers which have thrown this exception while accessing my website.

Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.2.9) Gecko/20100824 Firefox/3.6.9 ( .NET CLR 3.5.30729)
Mozilla/5.0 (Windows; U; Windows NT 5.1; es-ES; rv:1.9.2.10) Gecko/20100914 Firefox/3.6.10 (.NET CLR 3.5.30729)
Mozilla/5.0 (Windows; U; Windows NT 6.0; nl; rv:1.9.1.11) Gecko/20100701 Firefox/3.5.11 (.NET CLR 3.5.30729)
Mozilla/5.0 (Windows; U; Windows NT 6.1; es-ES; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3

I know it is difficult to fix bugs without a working example. If you add some debugging to mozilla if the form:
if (about_to_call_image_onload && complete!=true) raise_red_flag.
some red flags will be seen.

Otherwise take a website which gets a lot of traffc, and add some code of the form:
img = new Image();
img.onload=function(){if(!img.complete) log_error_to_server()};
img.src = "whatever";

You will see errors accumulate over time. 

On my site, the exception is thrown about 1 time in 240 page loads, across all browser types (but the script is only run on browsers which support <canvas>).
Joe, any idea how the situation described in comment 20 can arise?  Can an image that used to be complete stop being so while the async onload is waiting to fire, for example (assuming no one changes the src, etc)?
The oldest browser version I have seen this error thrown on is Gecko/20090924 Firefox/3.5. 
Consider the possibility that this bug may have been in the image library for some time, with benign consequences up to the day that canvas.drawImage became a consumer of images inside image.onload.
I have worked around the problem in my production website by adding a 10ms delay in the onload handler. In 99% of cases 10ms is sufficient, so the image must be 'almost' loaded when the onload fires. (img size is ~25k)

function image_onload_event()
{
 if(!img.complete){setTimeout('image_onload_event()',10); break;}
}
Status: UNCONFIRMED → NEW
blocking2.0: --- → ?
Ever confirmed: true
agb5, just to make sure... you see that issue in safe mode too, right?
Boris, I have not experienced the issue directly, I can see from my server log that visitors to my web site are experiencing the issue on a variety of firefox browser versions from 3.5 to 3.6.10 . My visitors are ordinary people using standard browsers. 
I don't see the error repeating in the logs for the same visitor IP address, so I don't think that a particular visitor browser setup is causing the issue.
This is a long-standing bug, but unfortunately we can release with it.
blocking2.0: ? → -
Component: Canvas: 2D → ImageLib
QA Contact: canvas.2d → imagelib
I see this with Firefox 3.6.10 on 32-bit Windows 7, loading a dynamic ContentFlow slider with images from a slow server. I read that drawImage should block until ready, but i can't even catch those NS errors. I'll try adding a setTimeout to my onload function as described in comment 23.
Cees T., is there any way you can give me access to the page that shows the problem for you?
I could catch the error. Refreshing external .js files can be a pain with caching bugs.

This minimal testcase shows the error without onload if the image isn't cached yet.
That last testcase doesn't use a load handler, so of course it will throw; you're calling drawImage before the image has loaded.  This bug is about cases when you drawImage from the onload handler for the image and get NS_ERROR_NOT_AVAILABLE.  

> I read that drawImage should block until ready

Fwiw, wherever you read that is wrong.  drawImage doesn't block on network activity.  Your comment 27 was suggesting that you were doing drawIamge from onload, though, which is why I asked to see the page in comment 28...
http://old.nabble.com/drawImage-throws-exception-NS_ERROR_NOT_AVAILABLE-td27224579.html

http://www.bugaboo.com/learn/bugaboo-cameleon?id=1820 lacks reflection because ContentFlow throws that error. I catch it so that the onclick at least works.
The developer.mozilla.org page in question hasn't said that since August.  At one point, it was in fact incorrect.

I have no idea what to do with the second link in comment 31..
We're seeing this problem on Windows with an image loaded from chrome. Same code pattern.

So it's not just about slow networks.
OS: Linux → Windows CE
Michael, if you have a testcase that reliably reproduces the problem (extension, whatever), I'd love to get my hands on it.
We're trying. One person sees it consistently on their Windows, I see it intermittently. We don't see it on other platforms (Linux/Mac)
As another datapoint, switching from our chrome URL to a data url for the PNG fixed the problem.
Sure; I understand there are all cases when this works.  I'm interested in the ones where it doesn't.  ;)

The OS dependence is ... odd.
I see this on Firefox 3.6.3 Windows (XP SP3, all updates, including that malfunctioning MS anti-virus, running as VM on kvm), with our toolbar.
The other option is that if someone can reproduce this reliably they could debug it... e.g. log all the notifications the relevant nsImageLoadingContent gets and the state of the imgIRequest at all those points.  That would be very helpful.
Same with 3.6.13pre on Windows. It works for me on Linux. 100% reproducible in both cases.
Comment on attachment 482202 [details]
Testcase for bug 574330 - NS_ERROR_NOT_AVAILABLE with canvas.drawImage

Marking this obsolete based on bz' comment 30.
Attachment #482202 - Attachment is obsolete: true
http://www.bugaboodev.com/test-cameleon-interviews
throws 16 (the number of content items) of these when reloading from network:

Error: uncaught exception: [Exception... "Component returned failure code:
0x80040111 (NS_ERROR_NOT_AVAILABLE) [nsIDOMCanvasRenderingContext2D.drawImage]"
 nsresult: "0x80040111 (NS_ERROR_NOT_AVAILABLE)"  location: "JS frame ::
http://www.bugaboodev.com/static-portlet/ContentFlow/contentflow.js ::
anonymous :: line 2"  data: no]

http://www.bugaboodev.com/static-portlet/ContentFlow/contentflow_src.js is the
readable version that i "fixed" with a try...catch in the foobar function of
this.content.onload = window.setTimeout(foobar, 100);
Fixed it with this.content.onload = foobar;

WFM. Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12
I'm confused.  Does the url from comment 42 still show a problem?  If not, can you point me to one that does?
Comment 42 shows the error but it's caused by a function call before the images are loaded. The author of ContentFlow forgot "function () { ... }" around it, but that doesn't make a difference compared to just "foobar" in Firefox 3.6.12 and IE8 according to my tests.
> but that doesn't make a difference compared to just "foobar" in Firefox 3.6.12
> and IE8

Well, if the setTimeout code in comment 42 is used, then what matters is whether the load finishes in less than 100ms, right?  It's quite possible for such timing to differ (and to depend on your network latency, local weather, and butterflies).
Blocks: 628394
(In reply to comment #46)
> Well, if the setTimeout code in comment 42 is used, then what matters is
> whether the load finishes in less than 100ms, right?

True; it was executing the function instead of assigning it to onload.

I don't have Windows CE to test attachment 453706 [details].
I can reliably reproduce this issue in FF3.6.17 in both Windows XP and Windows 7 using the attached HTML test page. This page loads many PNGs by random URLs, calling Canvas (2d) .drawImage() on load.

The issue seems to be common in Windows XP and rarer in Windows 7 but is reliably reproducible if I load 1000 images. However this may be a difference in machines rather than the OS.

You can also view the test page here:
http://geoapis.appspot.com/agdnZW9hcGlzchMLEgtFeGFtcGxlQ29kZRihmQIM
A thought that just occurred to me: does setting image.onload store a reference to that image in the onload handler? That is, could we be boned by GC here?

  function loadImage() {
    var image = new Image;
    image.onload = function() {
      context.drawImage(image, 0, 0);
    };
    image.src =
        'http://upload.wikimedia.org/wikipedia/en/9/9d/Commons-logo-31px.png?'
        + Math.random();
  }
> does setting image.onload store a reference to that image in the onload handler?

Yes, in the example given, since the handler closes over the image.

But even in cases when it does not we do some magic to keep image elements alive until the load handler fires.

Note that in this case the image is _not_ getting collected, since the load handler is in fact firing... it's just that the internal imagelib state doesn't think the image is complete at that point for some reason.
Further to my previous comment: I have just run that test page in all of {Windows XP, Windows 7} x {FF3.6.17, FF4}. It fails every time in FF3.6.17 across both Windows OS, and never fails in FF4 across both Windows OS. So as far as I can tell, the issue affects FF3.6.17 and not FF4.
(In reply to comment #21)
> Joe, any idea how the situation described in comment 20 can arise?  Can an
> image that used to be complete stop being so while the async onload is
> waiting to fire, for example (assuming no one changes the src, etc)?

One thing that I wonder about in 1.9.2 is imgRequest::OnStopRequest. That's called (I'm fairly certain) by Necko to say that we're done with network data, but it can call back in to the decoder, which can cause arbitrary processing afterwards, including other on*() being called.

This is all very different in 2.0; I'm more certain that 2.0 is correct.
(In reply to comment #51)
> Further to my previous comment: I have just run that test page in all of
> {Windows XP, Windows 7} x {FF3.6.17, FF4}. It fails every time in FF3.6.17
> across both Windows OS, and never fails in FF4 across both Windows OS. So as
> far as I can tell, the issue affects FF3.6.17 and not FF4.

Fx4 will never throw an error on an incomplete image in drawWindow, so unfortunately that might not be instructive.

Can you modify your testcase to check if image.complete is true, and if not, log an error? That should catch the problem in both Fx3.6 and Fx4.
If you need a work-around, try the following:

image.onload = function() {
  if (!image.complete) {
    image.src = image.src;
    return;
  }
  // Insert your code here
};

With this modification, my stress-test passes every time:
http://geoapis.appspot.com/agdnZW9hcGlzchMLEgtFeGFtcGxlQ29kZRjSiQIM
I get this consistently (100% reproducible) using FF 8.0 on this page:
http://phrogz.net/SVG/svg_to_png.xhtml
Gavin: That's the first mention of SVG on this page.  Note that SVG images have extra restrictions placed on them, so your issue is likely unrelated to the original bug here.  I'm guessing that bug 672013's fix (not landed yet) is required in order that phrogz site to work.
(In reply to Daniel Holbert [:dholbert] from comment #56)
> I'm guessing that bug 672013's fix (not landed yet) is required in order that phrogz site to work.

Daniel: Perhaps, but note that the symptom is not with the canvas being (unnecessarily) tainted after drawing the SVG, but rather the drawImage() call never succeeds (yielding the error message described in this bug).
Stepping through the testcase in comment 55, the image is in fact completely loaded, which is why the operation is not just a no-op.  But the SVG image has no explicit size specified, so we don't know what size to draw it at and throw.  The spec on that has been clarified recently, and I'm pretty sure that we have an existing bug on it.

But the whole "no size" issue is definitely SVG-specific; that problem never arises with bitmap images.
(In reply to Boris Zbarsky (:bz) from comment #58)
> But the SVG image
> has no explicit size specified, so we don't know what size to draw it at and
> throw.  The spec on that has been clarified recently, and I'm pretty sure
> that we have an existing bug on it.

It sounds like you're describing bug 700533, which I trust is the exact issue here. While the SVG element in the SVG file has no explicit dimensions (and thus the SVG image has no intrinsic dimensions), the `<img>` tag that the SVG is loaded into does have explicit dimensions set (lines 50-51):

    svgImg.width  = can.width  = o2.getAttribute('width')*1;
    svgImg.height = can.height = o2.getAttribute('height')*1;

Do explicit dimensions on an <img> housing a dimension-less SVG count as the "image" having intrinsic dimensions or not?
(In reply to Gavin Kistner from comment #59)
> It sounds like you're describing bug 700533

Yeah, looks like that's exactly the issue with the phrogz.net testcase.

> Do explicit dimensions on an <img> housing a dimension-less SVG count as the
> "image" having intrinsic dimensions or not?

That clearly doesn't count in Gecko right now; I'm not sure if it's supposed to.  In any case, let's take this discussion (comment 55 through this one) over to bug 700533, since it's a separate issue from the original bug reported here.
Attachment #536511 - Attachment mime type: text/plain → text/html
Is anybody able to reproduce this in a current build?
Closing this as incomplete due to inactivity and the lack of a reproducible test case. Feel free to reopen the bug if there's an updated testcase that still reproduces the issue.
Status: NEW → RESOLVED
Closed: 9 years ago
Resolution: --- → INCOMPLETE
We fixed something that sounds like this, so it's entirely possible this got fixed. (of course if not, please re-open)

I created a lib to draw on HTML 5 Canvas and it works perfectly on browsers based on chromium, but in firefox I started to get this error. I happens when it tries to draw an image on the canvas. I think firefox is trying to draw the image when it is in a broken state. I pass an Image object to the context 2d to draw. In chromium browsers it does not draw if it has nothing to draw.

This is the error:

Uncaught 
Exception
​
columnNumber: 0
​
data: null
​
filename: ""
​
lineNumber: 0
​
message: ""
​
name: "NS_ERROR_NOT_AVAILABLE"
​
result: 2147746065
​
stack: ""
​
<prototype>: ExceptionPrototype { toString: toString(), name: Getter, message: Getter, … }
icon.js:40
    draw file:///C:/Users/allan_000/workspace/js_schema_builder/dist/index.js:673
    draw file:///C:/Users/allan_000/workspace/js_schema_builder/dist/index.js:1439
    draw file:///C:/Users/allan_000/workspace/js_schema_builder/dist/index.js:997
    draw file:///C:/Users/allan_000/workspace/js_schema_builder/dist/index.js:117
    addTable file:///C:/Users/allan_000/workspace/js_schema_builder/dist/index.js:748
    <anonymous> file:///C:/Users/allan_000/workspace/js_schema_builder/demo/index.html:200

This is the line 673 of my code

ctx.drawImage(
            this._image,
            this._transform._position.x,
            this._transform._position.y,
            this._transform._dimension.width,
            this._transform._dimension.height
        );

Please file a new bug with a testcase. Thanks.

Flags: needinfo?(allanoricilcos)
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: