When rendering a SVG to canvas background-images in a foreignObject HTML are not rendered




6 years ago
2 years ago


(Reporter: christoph.burgmer, Unassigned)


14 Branch
Mac OS X

Firefox Tracking Flags

(Not tracked)



(3 attachments)



6 years ago
Created attachment 658975 [details]

User Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_4) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/21.0.1180.89 Safari/537.1

Steps to reproduce:

I am rendering an HTML document inside an SVG as foreignObject to a canvas. The HTML document includes a CSS background-image declaration (using dataURI for web security reasons).

Actual results:

The background image is never rendered unless the image is loaded as a background image in the surrounding page (the one that holds the canvas) independently.

See the attached test case (or https://gist.github.com/3660040).

Expected results:

The background image should always be rendered to the canvas.
Attachment #658975 - Attachment mime type: text/plain → text/html
You wait for the svg to load but not the background image. I suspect you'll need to preload the background image (since you can't catch an onload event on it directly) so that you know it's rendered before you convert to canvas.

I don't think what you're doing can be expected to work as-is and this is likely invalid as a bug.

Comment 2

6 years ago
It took me some time to process your answer but I think I understand. :)

However, what loading has to be done then in addition as the image is already available as dataURI? And is there really no way to catch that?
You could try prepopulating the image. i.e. load the image data uri into an Image then continue processing when it's loaded.

function OnImageLoaded (img) {
    ... your code runs here once the image is loaded into an Image element.
function PreloadImage (src) {
  var img = new Image ();
  img.onload = function () {OnImageLoaded (this)};
  img.src = src;

PreloadImage (data uri);
Loading of all URIs is asynchronous in gecko. That's compliant with the various specifications involved even for data URIs.

Comment 5

6 years ago
Yes, I will try that.

Another thought, even using setTimeout() to defer the rendering with drawImage doesn't help. The hope here is that after some time all the elements are now loaded.

I guess that's because the content of the SVG is only loaded once it is going to be shown somewhere? Although, doing the
img.src = THE_SVG
should trigger that, or should it?
Images are loaded whether they are being shown or not.

It could be that there's some other bug happening too, but to see that you'd need to fix the issue I pointed out first.

Comment 7

6 years ago
Created attachment 659329 [details]
Extended testcase with background image preloading, broken

Here's my try to preload background-images through an image. I might be missing something, but in the current state it doesn't work. Worse, even the workaround wouldn't work anymore.
Attachment #659329 - Attachment mime type: text/plain → text/html
I think we should delay the load event for an SVG image until the load event for the SVG image document itself has fired (which would be delayed by the load of the data: URIs, in this case).

Robert, do you want to try that?
I'm not sure what you mean. We've got an html background image on a <div> which is inside a <foreignObject>. We draw the whole lot to canvas and the html background image has gone.

If I wait for all images of any type to load before firing an onload I think that's basically implementing externalResourcesRequired - bug 277955

What the modified testcase does is load the background image into a javascript Image object and wait for that to load but even that doesn't work so perhaps it's not a timing issue at all.

Comment 10

6 years ago
I don't know whether this observation helps, but in some other context just loading the background-image in a div connected to the document isn't enough. Best results, though still indeterministic, are reached by attaching the rendered SVG to the DOM. 

The report here for background-image seems to hold equally true for webfonts embedded in data: URIs.
The testcase builds an SVG image as a data: URI, sets it as the source of an Image, waits for that Image to fire its "load" event, then paints it to the canvas.

What I'm saying is that the Image should not fire its "load" event until all the images in the internal document for the SVG image have finished loading.

In other words, an SVG image has not finished loading until the load event has fired on its internal document.
Component: Untriaged → SVG
Product: Firefox → Core
We should do that if externalResourcesRequired is set. But we don't yet support externalResourcesRequired and it's due to be replaced by something else in SVG 2. It might be worth waiting to see what that replacement looks like.
I don't think this behavior needs to depend on externalResourcesRequired, especially since the resource in question is a CSS background image. I think it's quite natural for the "load" event of an SVG image to depend on the "load" event of its document. It matches the behavior for an SVG <iframe> or <object>, whose "load" event is delayed until the "load" event of the subdocument has fired.
Does the onload event in html documents i.e. on the body element wait for image loading?
Perhaps it doesn't need to as it can't be used as an image.
(In reply to Robert Longson from comment #14)
> Does the onload event in html documents i.e. on the body element wait for
> image loading?


Comment 17

6 years ago
This issue doesn't exist under Firefox 17.0.1. Neither is background image rendering fragile nor is the workaround still needed. From my part this issue can be closed as "FIXED".
Excellent, we use WORKSFORME when we don't know why something works and FIXED if we do know what bug fixed it.
Last Resolved: 6 years ago
Resolution: --- → WORKSFORME

Comment 19

2 years ago
Created attachment 8859755 [details]
foreignObject background data-uri bug

I can reproduce it on Firefox 52.0.2, Ubuntu 16.04. (https://gist.github.com/flapenguin/5503b96e235c2a8fc1197ff634eba7bc)

First render does nothing, but all following renders (simply refresh the page) will render correctly.
"reproduce" button will "generate" completely new image by adding 3 dummy zero bytes to end of data uri, which will make render do nothing again.

Adding immediate timeout doesn't fix the problem, looks like onload firing way too early.
Ever confirmed: true
Resolution: WORKSFORME → ---
You need to log in before you can comment on or make changes to this bug.