summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPierre Ossman <ossman@cendio.se>2016-11-11 15:32:11 +0100
committerPierre Ossman <ossman@cendio.se>2016-12-09 09:20:50 +0100
commitadf345fdc4409537bf2599c0550d771344da38e6 (patch)
tree830deefa95ab5a47c1a374ddaed65d6ffc3fd514
parent3f781f2aa34bdec0b6d06eaba91827a822a07c6e (diff)
downloadnovnc-adf345fdc4409537bf2599c0550d771344da38e6.tar.gz
Clean up viewport handling
Make sure the viewport is properly updated when necessary, on respects given restrictions.
-rw-r--r--app/ui.js17
-rw-r--r--core/display.js56
-rw-r--r--tests/test.display.js109
3 files changed, 132 insertions, 50 deletions
diff --git a/app/ui.js b/app/ui.js
index f238fad..8b88926 100644
--- a/app/ui.js
+++ b/app/ui.js
@@ -1187,22 +1187,7 @@ var UI;
if (new_clip && size) {
// When clipping is enabled, the screen is limited to
// the size of the browser window.
-
- var screen = document.getElementById('noVNC_screen');
- var canvas = document.getElementById('noVNC_canvas');
-
- // Hide potential scrollbars that can skew the position
- screen.style.overflow = "hidden";
-
- // The x position marks the left margin of the canvas,
- // remove the margin from both sides to keep it centered.
- var new_w = size.w - (2 * Util.getPosition(canvas).x);
-
- screen.style.overflow = "visible";
-
- display.viewportChangeSize(new_w, size.h);
- } else {
- display.viewportChangeSize();
+ display.viewportChangeSize(size.w, size.h);
}
},
diff --git a/core/display.js b/core/display.js
index fd0d9ee..ac2e1e5 100644
--- a/core/display.js
+++ b/core/display.js
@@ -26,9 +26,6 @@
this._fb_width = 0;
this._fb_height = 0;
- // the visible "physical canvas" viewport
- this._viewportLoc = { 'x': 0, 'y': 0, 'w': 0, 'h': 0 };
-
this._prevDrawStyle = "";
this._tile = null;
this._tile16x16 = null;
@@ -61,6 +58,9 @@
this._targetCtx = this._target.getContext('2d');
+ // the visible canvas viewport (i.e. what actually gets seen)
+ this._viewportLoc = { 'x': 0, 'y': 0, 'w': this._target.width, 'h': this._target.height };
+
// The hidden canvas, where we do the actual rendering
this._backbuffer = document.createElement('canvas');
this._drawCtx = this._backbuffer.getContext('2d');
@@ -156,31 +156,39 @@
viewportChangeSize: function(width, height) {
- if (typeof(width) === "undefined" || typeof(height) === "undefined") {
+ if (!this._viewport ||
+ typeof(width) === "undefined" ||
+ typeof(height) === "undefined") {
Util.Debug("Setting viewport to full display region");
width = this._fb_width;
height = this._fb_height;
}
+ if (width > this._fb_width) {
+ width = this._fb_width;
+ }
+ if (height > this._fb_height) {
+ height = this._fb_height;
+ }
+
var vp = this._viewportLoc;
if (vp.w !== width || vp.h !== height) {
vp.w = width;
vp.h = height;
var canvas = this._target;
- if (canvas.width !== width || canvas.height !== height) {
- if (canvas.width !== width) {
- canvas.width = width;
- canvas.style.width = width + 'px';
- }
- if (canvas.height !== height) {
- canvas.height = height;
- canvas.style.height = height + 'px';
- }
- this._damage(vp.x, vp.y, vp.w, vp.h);
- this.flip();
- }
+ canvas.width = width;
+ canvas.height = height;
+
+ // The position might need to be updated if we've grown
+ this.viewportChangePos(0, 0);
+
+ this._damage(vp.x, vp.y, vp.w, vp.h);
+ this.flip();
+
+ // Update the visible size of the target canvas
+ this._rescale(this._scale);
}
},
@@ -219,9 +227,11 @@
}
}
- this._rescale(this._scale);
-
- this.viewportChangeSize();
+ // Readjust the viewport as it may be incorrectly sized
+ // and positioned
+ var vp = this._viewportLoc;
+ this.viewportChangeSize(vp.w, vp.h);
+ this.viewportChangePos(0, 0);
},
// Track what parts of the visible canvas that need updating
@@ -547,6 +557,14 @@
this._rescale(scale);
},
+ set_viewport: function (viewport) {
+ this._viewport = viewport;
+ // May need to readjust the viewport dimensions
+ var vp = this._viewportLoc;
+ this.viewportChangeSize(vp.w, vp.h);
+ this.viewportChangePos(0, 0);
+ },
+
get_width: function () {
return this._fb_width;
},
diff --git a/tests/test.display.js b/tests/test.display.js
index dd750ca..5f4eed1 100644
--- a/tests/test.display.js
+++ b/tests/test.display.js
@@ -89,6 +89,20 @@ describe('Display/Canvas Helper', function () {
expect(display._target.height).to.equal(2);
});
+ it('should move the viewport if necessary', function() {
+ display.viewportChangeSize(5, 5);
+ expect(display.absX(0)).to.equal(0);
+ expect(display.absY(0)).to.equal(0);
+ expect(display._target.width).to.equal(5);
+ expect(display._target.height).to.equal(5);
+ });
+
+ it('should limit the viewport to the framebuffer size', function() {
+ display.viewportChangeSize(6, 6);
+ expect(display._target.width).to.equal(5);
+ expect(display._target.height).to.equal(5);
+ });
+
it('should redraw when moving the viewport', function () {
display.flip = sinon.spy();
display.viewportChangePos(-1, 1);
@@ -111,13 +125,40 @@ describe('Display/Canvas Helper', function () {
var clipping = display.clippingDisplay();
expect(clipping).to.be.false;
});
+
+ it('should show the entire framebuffer when disabling the viewport', function() {
+ display.set_viewport(false);
+ expect(display.absX(0)).to.equal(0);
+ expect(display.absY(0)).to.equal(0);
+ expect(display._target.width).to.equal(5);
+ expect(display._target.height).to.equal(5);
+ });
+
+ it('should ignore viewport changes when the viewport is disabled', function() {
+ display.set_viewport(false);
+ display.viewportChangeSize(2, 2);
+ display.viewportChangePos(1, 1);
+ expect(display.absX(0)).to.equal(0);
+ expect(display.absY(0)).to.equal(0);
+ expect(display._target.width).to.equal(5);
+ expect(display._target.height).to.equal(5);
+ });
+
+ it('should show the entire framebuffer just after enabling the viewport', function() {
+ display.set_viewport(false);
+ display.set_viewport(true);
+ expect(display.absX(0)).to.equal(0);
+ expect(display.absY(0)).to.equal(0);
+ expect(display._target.width).to.equal(5);
+ expect(display._target.height).to.equal(5);
+ });
});
describe('resizing', function () {
var display;
beforeEach(function () {
- display = new Display({ target: document.createElement('canvas'), prefer_js: false, viewport: true });
- display.resize(4, 3);
+ display = new Display({ target: document.createElement('canvas'), prefer_js: false, viewport: false });
+ display.resize(4, 4);
});
it('should change the size of the logical canvas', function () {
@@ -126,14 +167,8 @@ describe('Display/Canvas Helper', function () {
expect(display._fb_height).to.equal(7);
});
- it('should update the viewport dimensions', function () {
- sinon.spy(display, 'viewportChangeSize');
- display.resize(2, 2);
- expect(display.viewportChangeSize).to.have.been.calledOnce;
- });
-
it('should keep the framebuffer data', function () {
- display.fillRect(0, 0, 4, 3, [0, 0, 0xff]);
+ display.fillRect(0, 0, 4, 4, [0, 0, 0xff]);
display.resize(2, 2);
display.flip();
var expected = [];
@@ -144,6 +179,38 @@ describe('Display/Canvas Helper', function () {
}
expect(display).to.have.displayed(new Uint8Array(expected));
});
+
+ describe('viewport', function () {
+ beforeEach(function () {
+ display.set_viewport(true);
+ display.viewportChangeSize(3, 3);
+ display.viewportChangePos(1, 1);
+ });
+
+ it('should keep the viewport position and size if possible', function () {
+ display.resize(6, 6);
+ expect(display.absX(0)).to.equal(1);
+ expect(display.absY(0)).to.equal(1);
+ expect(display._target.width).to.equal(3);
+ expect(display._target.height).to.equal(3);
+ });
+
+ it('should move the viewport if necessary', function () {
+ display.resize(3, 3);
+ expect(display.absX(0)).to.equal(0);
+ expect(display.absY(0)).to.equal(0);
+ expect(display._target.width).to.equal(3);
+ expect(display._target.height).to.equal(3);
+ });
+
+ it('should shrink the viewport if necessary', function () {
+ display.resize(2, 2);
+ expect(display.absX(0)).to.equal(0);
+ expect(display.absY(0)).to.equal(0);
+ expect(display._target.width).to.equal(2);
+ expect(display._target.height).to.equal(2);
+ });
+ });
});
describe('rescaling', function () {
@@ -152,7 +219,9 @@ describe('Display/Canvas Helper', function () {
beforeEach(function () {
display = new Display({ target: document.createElement('canvas'), prefer_js: false, viewport: true });
- display.resize(4, 3);
+ display.resize(4, 4);
+ display.viewportChangeSize(3, 3);
+ display.viewportChangePos(1, 1);
canvas = display.get_target();
document.body.appendChild(canvas);
});
@@ -162,15 +231,25 @@ describe('Display/Canvas Helper', function () {
});
it('should not change the bitmap size of the canvas', function () {
- display.set_scale(0.5);
- expect(canvas.width).to.equal(4);
+ display.set_scale(2.0);
+ expect(canvas.width).to.equal(3);
expect(canvas.height).to.equal(3);
});
it('should change the effective rendered size of the canvas', function () {
- display.set_scale(0.5);
- expect(canvas.clientWidth).to.equal(2);
- expect(canvas.clientHeight).to.equal(2);
+ display.set_scale(2.0);
+ expect(canvas.clientWidth).to.equal(6);
+ expect(canvas.clientHeight).to.equal(6);
+ });
+
+ it('should not change when resizing', function () {
+ display.set_scale(2.0);
+ display.resize(5, 5);
+ expect(display.get_scale()).to.equal(2.0);
+ expect(canvas.width).to.equal(3);
+ expect(canvas.height).to.equal(3);
+ expect(canvas.clientWidth).to.equal(6);
+ expect(canvas.clientHeight).to.equal(6);
});
});