]>
git.proxmox.com Git - mirror_novnc.git/blob - tests/test.display.js
1 const expect
= chai
.expect
;
3 import Base64
from '../core/base64.js';
4 import Display
from '../core/display.js';
6 describe('Display/Canvas Helper', function () {
7 const checkedData
= new Uint8ClampedArray([
8 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255,
9 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255,
10 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255,
11 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255
14 const basicData
= new Uint8ClampedArray([0xff, 0x00, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0xff, 0xff, 0xff, 255]);
16 function makeImageCanvas(inputData
, width
, height
) {
17 const canvas
= document
.createElement('canvas');
19 canvas
.height
= height
;
20 const ctx
= canvas
.getContext('2d');
21 const data
= new ImageData(inputData
, width
, height
);
22 ctx
.putImageData(data
, 0, 0);
26 function makeImagePng(inputData
, width
, height
) {
27 const canvas
= makeImageCanvas(inputData
, width
, height
);
28 const url
= canvas
.toDataURL();
29 const data
= url
.split(",")[1];
30 return Base64
.decode(data
);
33 describe('viewport handling', function () {
35 beforeEach(function () {
36 display
= new Display(document
.createElement('canvas'));
37 display
.clipViewport
= true;
39 display
.viewportChangeSize(3, 3);
40 display
.viewportChangePos(1, 1);
43 it('should take viewport location into consideration when drawing images', function () {
45 display
.viewportChangeSize(2, 2);
46 display
.drawImage(makeImageCanvas(basicData
, 4, 1), 1, 1);
49 const expected
= new Uint8Array(16);
50 for (let i
= 0; i
< 8; i
++) { expected
[i
] = basicData
[i
]; }
51 for (let i
= 8; i
< 16; i
++) { expected
[i
] = 0; }
52 expect(display
).to
.have
.displayed(expected
);
55 it('should resize the target canvas when resizing the viewport', function () {
56 display
.viewportChangeSize(2, 2);
57 expect(display
._target
.width
).to
.equal(2);
58 expect(display
._target
.height
).to
.equal(2);
61 it('should move the viewport if necessary', function () {
62 display
.viewportChangeSize(5, 5);
63 expect(display
.absX(0)).to
.equal(0);
64 expect(display
.absY(0)).to
.equal(0);
65 expect(display
._target
.width
).to
.equal(5);
66 expect(display
._target
.height
).to
.equal(5);
69 it('should limit the viewport to the framebuffer size', function () {
70 display
.viewportChangeSize(6, 6);
71 expect(display
._target
.width
).to
.equal(5);
72 expect(display
._target
.height
).to
.equal(5);
75 it('should redraw when moving the viewport', function () {
76 display
.flip
= sinon
.spy();
77 display
.viewportChangePos(-1, 1);
78 expect(display
.flip
).to
.have
.been
.calledOnce
;
81 it('should redraw when resizing the viewport', function () {
82 display
.flip
= sinon
.spy();
83 display
.viewportChangeSize(2, 2);
84 expect(display
.flip
).to
.have
.been
.calledOnce
;
87 it('should show the entire framebuffer when disabling the viewport', function () {
88 display
.clipViewport
= false;
89 expect(display
.absX(0)).to
.equal(0);
90 expect(display
.absY(0)).to
.equal(0);
91 expect(display
._target
.width
).to
.equal(5);
92 expect(display
._target
.height
).to
.equal(5);
95 it('should ignore viewport changes when the viewport is disabled', function () {
96 display
.clipViewport
= false;
97 display
.viewportChangeSize(2, 2);
98 display
.viewportChangePos(1, 1);
99 expect(display
.absX(0)).to
.equal(0);
100 expect(display
.absY(0)).to
.equal(0);
101 expect(display
._target
.width
).to
.equal(5);
102 expect(display
._target
.height
).to
.equal(5);
105 it('should show the entire framebuffer just after enabling the viewport', function () {
106 display
.clipViewport
= false;
107 display
.clipViewport
= true;
108 expect(display
.absX(0)).to
.equal(0);
109 expect(display
.absY(0)).to
.equal(0);
110 expect(display
._target
.width
).to
.equal(5);
111 expect(display
._target
.height
).to
.equal(5);
115 describe('resizing', function () {
117 beforeEach(function () {
118 display
= new Display(document
.createElement('canvas'));
119 display
.clipViewport
= false;
120 display
.resize(4, 4);
123 it('should change the size of the logical canvas', function () {
124 display
.resize(5, 7);
125 expect(display
._fbWidth
).to
.equal(5);
126 expect(display
._fbHeight
).to
.equal(7);
129 it('should keep the framebuffer data', function () {
130 display
.fillRect(0, 0, 4, 4, [0xff, 0, 0]);
131 display
.resize(2, 2);
134 for (let i
= 0; i
< 4 * 2*2; i
+= 4) {
136 expected
[i
+1] = expected
[i
+2] = 0;
137 expected
[i
+3] = 0xff;
139 expect(display
).to
.have
.displayed(new Uint8Array(expected
));
142 describe('viewport', function () {
143 beforeEach(function () {
144 display
.clipViewport
= true;
145 display
.viewportChangeSize(3, 3);
146 display
.viewportChangePos(1, 1);
149 it('should keep the viewport position and size if possible', function () {
150 display
.resize(6, 6);
151 expect(display
.absX(0)).to
.equal(1);
152 expect(display
.absY(0)).to
.equal(1);
153 expect(display
._target
.width
).to
.equal(3);
154 expect(display
._target
.height
).to
.equal(3);
157 it('should move the viewport if necessary', function () {
158 display
.resize(3, 3);
159 expect(display
.absX(0)).to
.equal(0);
160 expect(display
.absY(0)).to
.equal(0);
161 expect(display
._target
.width
).to
.equal(3);
162 expect(display
._target
.height
).to
.equal(3);
165 it('should shrink the viewport if necessary', function () {
166 display
.resize(2, 2);
167 expect(display
.absX(0)).to
.equal(0);
168 expect(display
.absY(0)).to
.equal(0);
169 expect(display
._target
.width
).to
.equal(2);
170 expect(display
._target
.height
).to
.equal(2);
175 describe('rescaling', function () {
179 beforeEach(function () {
180 canvas
= document
.createElement('canvas');
181 display
= new Display(canvas
);
182 display
.clipViewport
= true;
183 display
.resize(4, 4);
184 display
.viewportChangeSize(3, 3);
185 display
.viewportChangePos(1, 1);
186 document
.body
.appendChild(canvas
);
189 afterEach(function () {
190 document
.body
.removeChild(canvas
);
193 it('should not change the bitmap size of the canvas', function () {
195 expect(canvas
.width
).to
.equal(3);
196 expect(canvas
.height
).to
.equal(3);
199 it('should change the effective rendered size of the canvas', function () {
201 expect(canvas
.clientWidth
).to
.equal(6);
202 expect(canvas
.clientHeight
).to
.equal(6);
205 it('should not change when resizing', function () {
207 display
.resize(5, 5);
208 expect(display
.scale
).to
.equal(2.0);
209 expect(canvas
.width
).to
.equal(3);
210 expect(canvas
.height
).to
.equal(3);
211 expect(canvas
.clientWidth
).to
.equal(6);
212 expect(canvas
.clientHeight
).to
.equal(6);
216 describe('autoscaling', function () {
220 beforeEach(function () {
221 canvas
= document
.createElement('canvas');
222 display
= new Display(canvas
);
223 display
.clipViewport
= true;
224 display
.resize(4, 3);
225 display
.viewportChangeSize(4, 3);
226 document
.body
.appendChild(canvas
);
229 afterEach(function () {
230 document
.body
.removeChild(canvas
);
233 it('should preserve aspect ratio while autoscaling', function () {
234 display
.autoscale(16, 9);
235 expect(canvas
.clientWidth
/ canvas
.clientHeight
).to
.equal(4 / 3);
238 it('should use width to determine scale when the current aspect ratio is wider than the target', function () {
239 display
.autoscale(9, 16);
240 expect(display
.absX(9)).to
.equal(4);
241 expect(display
.absY(18)).to
.equal(8);
242 expect(canvas
.clientWidth
).to
.equal(9);
243 expect(canvas
.clientHeight
).to
.equal(7); // round 9 / (4 / 3)
246 it('should use height to determine scale when the current aspect ratio is taller than the target', function () {
247 display
.autoscale(16, 9);
248 expect(display
.absX(9)).to
.equal(3);
249 expect(display
.absY(18)).to
.equal(6);
250 expect(canvas
.clientWidth
).to
.equal(12); // 16 * (4 / 3)
251 expect(canvas
.clientHeight
).to
.equal(9);
255 it('should not change the bitmap size of the canvas', function () {
256 display
.autoscale(16, 9);
257 expect(canvas
.width
).to
.equal(4);
258 expect(canvas
.height
).to
.equal(3);
262 describe('drawing', function () {
264 // TODO(directxman12): improve the tests for each of the drawing functions to cover more than just the
267 beforeEach(function () {
268 display
= new Display(document
.createElement('canvas'));
269 display
.resize(4, 4);
272 it('should not draw directly on the target canvas', function () {
273 display
.fillRect(0, 0, 4, 4, [0xff, 0, 0]);
275 display
.fillRect(0, 0, 4, 4, [0, 0xff, 0]);
277 for (let i
= 0; i
< 4 * display
._fbWidth
* display
._fbHeight
; i
+= 4) {
279 expected
[i
+1] = expected
[i
+2] = 0;
280 expected
[i
+3] = 0xff;
282 expect(display
).to
.have
.displayed(new Uint8Array(expected
));
285 it('should support filling a rectangle with particular color via #fillRect', function () {
286 display
.fillRect(0, 0, 4, 4, [0, 0xff, 0]);
287 display
.fillRect(0, 0, 2, 2, [0, 0, 0xff]);
288 display
.fillRect(2, 2, 2, 2, [0, 0, 0xff]);
290 expect(display
).to
.have
.displayed(checkedData
);
293 it('should support copying an portion of the canvas via #copyImage', function () {
294 display
.fillRect(0, 0, 4, 4, [0, 0xff, 0]);
295 display
.fillRect(0, 0, 2, 2, [0, 0, 0xff]);
296 display
.copyImage(0, 0, 2, 2, 2, 2);
298 expect(display
).to
.have
.displayed(checkedData
);
301 it('should support drawing images via #imageRect', function (done
) {
302 display
.imageRect(0, 0, 4, 4, "image/png", makeImagePng(checkedData
, 4, 4));
304 display
.onflush
= () => {
305 expect(display
).to
.have
.displayed(checkedData
);
311 it('should support blit images with true color via #blitImage', function () {
312 display
.blitImage(0, 0, 4, 4, checkedData
, 0);
314 expect(display
).to
.have
.displayed(checkedData
);
317 it('should support drawing an image object via #drawImage', function () {
318 const img
= makeImageCanvas(checkedData
, 4, 4);
319 display
.drawImage(img
, 0, 0);
321 expect(display
).to
.have
.displayed(checkedData
);
325 describe('the render queue processor', function () {
327 beforeEach(function () {
328 display
= new Display(document
.createElement('canvas'));
329 display
.resize(4, 4);
330 sinon
.spy(display
, '_scanRenderQ');
333 it('should try to process an item when it is pushed on, if nothing else is on the queue', function () {
334 display
._renderQPush({ type
: 'noop' }); // does nothing
335 expect(display
._scanRenderQ
).to
.have
.been
.calledOnce
;
338 it('should not try to process an item when it is pushed on if we are waiting for other items', function () {
339 display
._renderQ
.length
= 2;
340 display
._renderQPush({ type
: 'noop' });
341 expect(display
._scanRenderQ
).to
.not
.have
.been
.called
;
344 it('should wait until an image is loaded to attempt to draw it and the rest of the queue', function () {
345 const img
= { complete
: false, width
: 4, height
: 4, addEventListener
: sinon
.spy() };
346 display
._renderQ
= [{ type
: 'img', x
: 3, y
: 4, width
: 4, height
: 4, img
: img
},
347 { type
: 'fill', x
: 1, y
: 2, width
: 3, height
: 4, color
: 5 }];
348 display
.drawImage
= sinon
.spy();
349 display
.fillRect
= sinon
.spy();
351 display
._scanRenderQ();
352 expect(display
.drawImage
).to
.not
.have
.been
.called
;
353 expect(display
.fillRect
).to
.not
.have
.been
.called
;
354 expect(img
.addEventListener
).to
.have
.been
.calledOnce
;
356 display
._renderQ
[0].img
.complete
= true;
357 display
._scanRenderQ();
358 expect(display
.drawImage
).to
.have
.been
.calledOnce
;
359 expect(display
.fillRect
).to
.have
.been
.calledOnce
;
360 expect(img
.addEventListener
).to
.have
.been
.calledOnce
;
363 it('should call callback when queue is flushed', function () {
364 display
.onflush
= sinon
.spy();
365 display
.fillRect(0, 0, 4, 4, [0, 0xff, 0]);
366 expect(display
.onflush
).to
.not
.have
.been
.called
;
368 expect(display
.onflush
).to
.have
.been
.calledOnce
;
371 it('should draw a blit image on type "blit"', function () {
372 display
.blitImage
= sinon
.spy();
373 display
._renderQPush({ type
: 'blit', x
: 3, y
: 4, width
: 5, height
: 6, data
: [7, 8, 9] });
374 expect(display
.blitImage
).to
.have
.been
.calledOnce
;
375 expect(display
.blitImage
).to
.have
.been
.calledWith(3, 4, 5, 6, [7, 8, 9], 0);
378 it('should copy a region on type "copy"', function () {
379 display
.copyImage
= sinon
.spy();
380 display
._renderQPush({ type
: 'copy', x
: 3, y
: 4, width
: 5, height
: 6, oldX
: 7, oldY
: 8 });
381 expect(display
.copyImage
).to
.have
.been
.calledOnce
;
382 expect(display
.copyImage
).to
.have
.been
.calledWith(7, 8, 3, 4, 5, 6);
385 it('should fill a rect with a given color on type "fill"', function () {
386 display
.fillRect
= sinon
.spy();
387 display
._renderQPush({ type
: 'fill', x
: 3, y
: 4, width
: 5, height
: 6, color
: [7, 8, 9]});
388 expect(display
.fillRect
).to
.have
.been
.calledOnce
;
389 expect(display
.fillRect
).to
.have
.been
.calledWith(3, 4, 5, 6, [7, 8, 9]);
392 it('should draw an image from an image object on type "img" (if complete)', function () {
393 display
.drawImage
= sinon
.spy();
394 display
._renderQPush({ type
: 'img', x
: 3, y
: 4, img
: { complete
: true } });
395 expect(display
.drawImage
).to
.have
.been
.calledOnce
;
396 expect(display
.drawImage
).to
.have
.been
.calledWith({ complete
: true }, 3, 4);