]> git.proxmox.com Git - mirror_novnc.git/commitdiff
Handle slow loading of images
authorPierre Ossman <ossman@cendio.se>
Mon, 23 Dec 2019 14:40:17 +0000 (15:40 +0100)
committerPierre Ossman <ossman@cendio.se>
Mon, 23 Dec 2019 14:52:54 +0000 (15:52 +0100)
Internet Explorer seems to flag images as loaded prematurely, which
can result in rendering bugs. We can detect this by looking at the
dimensions though.

core/display.js
tests/test.display.js

index c89571704660f8feadaca87f06ef1a613c362f28..3dd5fcea12c78646ba8e04678f16dacb220b634d 100644 (file)
@@ -360,8 +360,14 @@ export default class Display {
     }
 
     imageRect(x, y, width, height, mime, arr) {
+        /* The internal logic cannot handle empty images, so bail early */
+        if ((width === 0) || (height === 0)) {
+            return;
+        }
+
         const img = new Image();
         img.src = "data: " + mime + ";base64," + Base64.encode(arr);
+
         this._renderQ_push({
             'type': 'img',
             'img': img,
@@ -617,7 +623,8 @@ export default class Display {
                     this.blitRgbxImage(a.x, a.y, a.width, a.height, a.data, 0, true);
                     break;
                 case 'img':
-                    if (a.img.complete) {
+                    /* IE tends to set "complete" prematurely, so check dimensions */
+                    if (a.img.complete && (a.img.width !== 0) && (a.img.height !== 0)) {
                         if (a.img.width !== a.width || a.img.height !== a.height) {
                             Log.Error("Decoded image has incorrect dimensions. Got " +
                                       a.img.width + "x" + a.img.height + ". Expected " +
index 05dd8a7038ed9737d1063cfd516423147b2ac2ce..594f9514feda3985646d00ffeb089fb22cdf520e 100644 (file)
@@ -300,7 +300,7 @@ describe('Display/Canvas Helper', function () {
         });
 
         it('should support drawing images via #imageRect', function (done) {
-            display.imageRect(0, 0, "image/png", make_image_png(checked_data));
+            display.imageRect(0, 0, 4, 4, "image/png", make_image_png(checked_data));
             display.flip();
             display.onflush = () => {
                 expect(display).to.have.displayed(checked_data);
@@ -401,8 +401,8 @@ describe('Display/Canvas Helper', function () {
         });
 
         it('should wait until an image is loaded to attempt to draw it and the rest of the queue', function () {
-            const img = { complete: false, addEventListener: sinon.spy() };
-            display._renderQ = [{ type: 'img', x: 3, y: 4, img: img },
+            const img = { complete: false, width: 4, height: 4, addEventListener: sinon.spy() };
+            display._renderQ = [{ type: 'img', x: 3, y: 4, width: 4, height: 4, img: img },
                                 { type: 'fill', x: 1, y: 2, width: 3, height: 4, color: 5 }];
             display.drawImage = sinon.spy();
             display.fillRect = sinon.spy();
@@ -419,6 +419,27 @@ describe('Display/Canvas Helper', function () {
             expect(img.addEventListener).to.have.been.calledOnce;
         });
 
+        it('should wait if an image is incorrectly loaded', function () {
+            const img = { complete: true, width: 0, height: 0, addEventListener: sinon.spy() };
+            display._renderQ = [{ type: 'img', x: 3, y: 4, width: 4, height: 4, img: img },
+                                { type: 'fill', x: 1, y: 2, width: 3, height: 4, color: 5 }];
+            display.drawImage = sinon.spy();
+            display.fillRect = sinon.spy();
+
+            display._scan_renderQ();
+            expect(display.drawImage).to.not.have.been.called;
+            expect(display.fillRect).to.not.have.been.called;
+            expect(img.addEventListener).to.have.been.calledOnce;
+
+            display._renderQ[0].img.complete = true;
+            display._renderQ[0].img.width = 4;
+            display._renderQ[0].img.height = 4;
+            display._scan_renderQ();
+            expect(display.drawImage).to.have.been.calledOnce;
+            expect(display.fillRect).to.have.been.calledOnce;
+            expect(img.addEventListener).to.have.been.calledOnce;
+        });
+
         it('should call callback when queue is flushed', function () {
             display.onflush = sinon.spy();
             display.fillRect(0, 0, 4, 4, [0, 0xff, 0]);