OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 /** | 5 /** |
6 * @fileoverview | 6 * @fileoverview |
7 * Class handling creation and teardown of a remoting client session. | 7 * Class handling creation and teardown of a remoting client session. |
8 * | 8 * |
9 * The ClientSession class controls lifetime of the client plugin | 9 * The ClientSession class controls lifetime of the client plugin |
10 * object and provides the plugin with the functionality it needs to | 10 * object and provides the plugin with the functionality it needs to |
(...skipping 1226 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1237 * remote desktop and client window, and the current scale-to-fit setting. | 1237 * remote desktop and client window, and the current scale-to-fit setting. |
1238 * | 1238 * |
1239 * @return {void} Nothing. | 1239 * @return {void} Nothing. |
1240 */ | 1240 */ |
1241 remoting.ClientSession.prototype.updateDimensions = function() { | 1241 remoting.ClientSession.prototype.updateDimensions = function() { |
1242 if (this.plugin_.getDesktopWidth() == 0 || | 1242 if (this.plugin_.getDesktopWidth() == 0 || |
1243 this.plugin_.getDesktopHeight() == 0) { | 1243 this.plugin_.getDesktopHeight() == 0) { |
1244 return; | 1244 return; |
1245 } | 1245 } |
1246 | 1246 |
1247 var clientArea = this.getClientArea_(); | 1247 var desktopSize = { width: this.plugin_.getDesktopWidth(), |
1248 var desktopWidth = this.plugin_.getDesktopWidth(); | 1248 height: this.plugin_.getDesktopHeight() }; |
1249 var desktopHeight = this.plugin_.getDesktopHeight(); | 1249 var desktopDpi = { x: this.plugin_.getDesktopXDpi(), |
1250 y: this.plugin_.getDesktopYDpi() }; | |
1251 var newSize = remoting.ClientSession.choosePluginSize( | |
1252 this.getClientArea_(), window.devicePixelRatio, | |
1253 desktopSize, desktopDpi, this.desktopScale_, | |
1254 remoting.fullscreen.isActive(), this.shrinkToFit_); | |
1250 | 1255 |
1251 // When configured to display a host at its original size, we aim to display | 1256 // Resize the plugin if necessary. |
1252 // it as close to its physical size as possible, without losing data: | 1257 // TODO(wez): Handle high-DPI to high-DPI properly (crbug.com/135089). |
1253 // - If client and host have matching DPI, render the host pixel-for-pixel. | 1258 this.plugin_.element().style.width = newSize.width + 'px'; |
1254 // - If the host has higher DPI then still render pixel-for-pixel. | 1259 this.plugin_.element().style.height = newSize.height + 'px'; |
1255 // - If the host has lower DPI then let Chrome up-scale it to natural size. | |
1256 | 1260 |
1257 // We specify the plugin dimensions in Density-Independent Pixels, so to | 1261 // Position the container. |
Jamie
2015/02/06 23:06:02
I realize your CL doesn't add this, but AFAICT, th
Wez
2015/02/09 21:32:28
Done.
| |
1258 // render pixel-for-pixel we need to down-scale the host dimensions by the | 1262 // Note that clientWidth/Height take into account scrollbars. |
1259 // devicePixelRatio of the client. To match the host pixel density, we choose | 1263 var clientWidth = document.documentElement.clientWidth; |
1260 // an initial scale factor based on the client devicePixelRatio and host DPI. | 1264 var clientHeight = document.documentElement.clientHeight; |
1265 var parentNode = this.plugin_.element().parentNode; | |
1261 | 1266 |
1262 // Determine the effective device pixel ratio of the host, based on DPI. | 1267 console.log('plugin dimensions: ' + |
1263 var hostPixelRatioX = Math.ceil(this.plugin_.getDesktopXDpi() / 96); | 1268 parentNode.style.left + ',' + |
1264 var hostPixelRatioY = Math.ceil(this.plugin_.getDesktopYDpi() / 96); | 1269 parentNode.style.top + '-' + |
1270 newSize.width + 'x' + newSize.height + '.'); | |
1271 | |
1272 // When we receive the first plugin dimensions from the host, we know that | |
1273 // remote host has started. | |
1274 remoting.app.onVideoStreamingStarted(); | |
1275 } | |
1276 | |
1277 /** | |
1278 * Helper function accepting client and host dimensions, and returning a chosen | |
1279 * size for the plugin element, in DIPs. | |
1280 * | |
1281 * @param {{width: number, height: number}} clientSizeDips Available client | |
1282 * dimensions, in DIPs. | |
1283 * @param {number} clientPixelRatio Number of physical pixels per client DIP. | |
1284 * @param {{width: number, height: number}} desktopSize Size of the host desktop | |
1285 * in physical pixels. | |
1286 * @param {{x: number, y: number}} desktopDpi DPI of the host desktop in both | |
1287 * dimensions. | |
1288 * @param {number} desktopScale The scale factor configured for the host. | |
1289 * @param {boolean} isFullscreen True if full-screen mode is active. | |
1290 * @param {boolean} shrinkToFit True if shrink-to-fit should be applied. | |
1291 * @return {{width: number, height: number}} | |
Jamie
2015/02/06 23:06:02
Since the inputs are in a variety of different uni
Wez
2015/02/09 21:32:28
Done.
| |
1292 */ | |
1293 remoting.ClientSession.choosePluginSize = function( | |
1294 clientSizeDips, clientPixelRatio, desktopSize, desktopDpi, desktopScale, | |
1295 isFullscreen, shrinkToFit) { | |
1296 base.debug.assert(clientSizeDips.width > 0); | |
1297 base.debug.assert(clientSizeDips.height > 0); | |
1298 base.debug.assert(clientPixelRatio >= 1.0); | |
1299 base.debug.assert(desktopSize.width > 0); | |
1300 base.debug.assert(desktopSize.height > 0); | |
1301 base.debug.assert(desktopDpi.x > 0); | |
1302 base.debug.assert(desktopDpi.y > 0); | |
1303 base.debug.assert(desktopScale > 0); | |
1304 | |
1305 // We have the following goals in sizing the desktop display at the client: | |
1306 // 1. Avoid losing detail by down-scaling beyond 1:1 host:device pixels. | |
1307 // 2. Avoid up-scaling if that will cause the client to need scrollbars. | |
1308 // 3. Avoid introducing blurriness with non-integer up-scaling factors. | |
1309 // 4. Avoid having huge "letterboxes" around the desktop, if it's really | |
1310 // small. | |
1311 // 5. Compensate for mismatched DPIs, so that the behaviour of features like | |
1312 // shrink-to-fit matches their "natural" rather than their pixel size. | |
1313 // e.g. with shrink-to-fit active a 1024x768 low-DPI host on a 640x480 | |
1314 // high-DPI client will be up-scaled to 1280x960, rather than displayed | |
1315 // at 1:1 host:physical client pixels. | |
1316 // | |
1317 // To determine the ideal size we follow a four-stage process: | |
1318 // 1. Determine the "natural" size at which to display the desktop. | |
1319 // a. Initially assume 1:1 mapping of desktop to client device pixels. | |
1320 // b. If host DPI is less than the client's then up-scale accordingly. | |
1321 // c. If desktopScale is configured for the host then allow that to | |
1322 // reduce the amount of up-scaling from (b). e.g. if the client:host | |
1323 // DPIs are 2:1 then a desktopScale of 1.5 would reduce the up-scale | |
1324 // to 4:3, while a desktopScale of 3.0 would result in no up-scaling. | |
1325 // 2. If the natural size of the desktop is smaller than the client device | |
1326 // then apply up-scaling by an integer scale factor to avoid excessive | |
1327 // letterboxing. | |
1328 // 3. If shrink-to-fit is configured, and the natural size exceeds the | |
1329 // client size then apply down-scaling by an arbitrary scale factor. | |
1330 // 4. If the overall scale factor is fractionally over an integer factor | |
1331 // then reduce it to that integer factor, to avoid blurring. | |
1332 | |
1333 // All calculations are performed in device pixels. | |
1334 var clientWidth = clientSizeDips.width * clientPixelRatio; | |
1335 var clientHeight = clientSizeDips.height * clientPixelRatio; | |
1336 | |
1337 // 1. Determine a "natural" size at which to display the desktop. | |
1338 var scale = 1.0; | |
1339 | |
1340 // Determine the effective host device pixel ratio. | |
1341 var hostPixelRatioX = Math.ceil(desktopDpi.x / 96); | |
1342 var hostPixelRatioY = Math.ceil(desktopDpi.y / 96); | |
1265 var hostPixelRatio = Math.min(hostPixelRatioX, hostPixelRatioY); | 1343 var hostPixelRatio = Math.min(hostPixelRatioX, hostPixelRatioY); |
1266 | 1344 |
1267 // Include the desktopScale in the hostPixelRatio before comparing it with | 1345 // Allow up-scaling to account for DPI. |
1268 // the client devicePixelRatio to determine the "natural" scale to use. | 1346 scale = Math.max(scale, clientPixelRatio / hostPixelRatio); |
1269 hostPixelRatio *= this.desktopScale_; | |
1270 | 1347 |
1271 // Down-scale by the smaller of the client and host ratios. | 1348 // Allow some or all of the up-scaling to be cancelled by the desktopScale. |
1272 var scale = 1.0 / Math.min(window.devicePixelRatio, hostPixelRatio); | 1349 if (desktopScale > 1.0) { |
1350 scale = Math.max(1.0, scale / desktopScale); | |
1351 } | |
1273 | 1352 |
1274 if (this.shrinkToFit_) { | 1353 // 2. Up-scale to avoid excessive letterboxing, if necessary. |
Jamie
2015/02/06 23:06:02
If I'm reading this correctly, this block eliminat
Wez
2015/02/09 21:32:28
No; letterboxing is the wrong term - you basically
| |
1275 // Reduce the scale, if necessary, to fit the whole desktop in the window. | 1354 if (desktopSize.width * scale <= clientWidth && |
1276 var scaleFitWidth = Math.min(scale, 1.0 * clientArea.width / desktopWidth); | 1355 desktopSize.height * scale <= clientHeight) { |
1356 var scaleX = Math.floor(clientWidth / desktopSize.width); | |
1357 var scaleY = Math.floor(clientHeight / desktopSize.height); | |
1358 scale = Math.min(scaleX, scaleY); | |
1359 base.debug.assert(scale >= 1.0); | |
1360 } | |
1361 | |
1362 // 3. Apply shrink-to-fit, if configured. | |
1363 if (shrinkToFit) { | |
1364 var scaleFitWidth = Math.min(scale, clientWidth / desktopSize.width); | |
1277 var scaleFitHeight = | 1365 var scaleFitHeight = |
1278 Math.min(scale, 1.0 * clientArea.height / desktopHeight); | 1366 Math.min(scale, clientHeight / desktopSize.height); |
1279 scale = Math.min(scaleFitHeight, scaleFitWidth); | 1367 scale = Math.min(scaleFitHeight, scaleFitWidth); |
Jamie
2015/02/06 23:06:02
I think it would be clearer (at least with the cur
Wez
2015/02/09 21:32:28
Done.
Jamie
2015/02/09 23:52:34
I don't think you've changed this (or is your "un-
Wez
2015/02/13 18:59:08
Yes, this is what got un-done.
| |
1280 | 1368 |
1369 // TODO(wez): Fix multi-monitor and wide/tall desktop handling. | |
1281 // If we're running full-screen then try to handle common side-by-side | 1370 // If we're running full-screen then try to handle common side-by-side |
1282 // multi-monitor combinations more intelligently. | 1371 // multi-monitor combinations more intelligently. |
Jamie
2015/02/06 23:06:02
This part of the algorithm is not covered by your
Wez
2015/02/09 21:32:28
Done.
Wez
2015/02/09 21:51:45
Un-done, since that breaks the multi-monitor speci
| |
1283 if (remoting.fullscreen.isActive()) { | 1372 if (isFullscreen) { |
1284 // If the host has two monitors each the same size as the client then | 1373 // If the host has two monitors each the same size as the client then |
1285 // scale-to-fit will have the desktop occupy only 50% of the client area, | 1374 // scale-to-fit will have the desktop occupy only 50% of the client area, |
1286 // in which case it would be preferable to down-scale less and let the | 1375 // in which case it would be preferable to down-scale less and let the |
1287 // user bump-scroll around ("scale-and-pan"). | 1376 // user bump-scroll around ("scale-and-pan"). |
1288 // Triggering scale-and-pan if less than 65% of the client area would be | 1377 // Triggering scale-and-pan if less than 65% of the client area would be |
1289 // used adds enough fuzz to cope with e.g. 1280x800 client connecting to | 1378 // used adds enough fuzz to cope with e.g. 1280x800 client connecting to |
1290 // a (2x1280)x1024 host nicely. | 1379 // a (2x1280)x1024 host nicely. |
1291 // Note that we don't need to account for scrollbars while fullscreen. | 1380 // Note that we don't need to account for scrollbars while fullscreen. |
1292 if (scale <= scaleFitHeight * 0.65) { | 1381 if (scale <= scaleFitHeight * 0.65) { |
1293 scale = scaleFitHeight; | 1382 scale = scaleFitHeight; |
1294 } | 1383 } |
1295 if (scale <= scaleFitWidth * 0.65) { | 1384 if (scale <= scaleFitWidth * 0.65) { |
1296 scale = scaleFitWidth; | 1385 scale = scaleFitWidth; |
1297 } | 1386 } |
1298 } | 1387 } |
1299 } | 1388 } |
1300 | 1389 |
1301 var pluginWidth = Math.round(desktopWidth * scale); | 1390 // 4. Avoid blurring for close-to-integer up-scaling factors. |
1302 var pluginHeight = Math.round(desktopHeight * scale); | 1391 if (scale > 1.0) { |
1392 var scaleBlurriness = scale / Math.floor(scale); | |
1393 if (scaleBlurriness < 1.1) { | |
1394 scale = Math.floor(scale); | |
1395 } | |
1396 } | |
1303 | 1397 |
1304 // Resize the plugin if necessary. | 1398 // Return the necessary plugin dimensions in DIPs. |
1305 // TODO(wez): Handle high-DPI to high-DPI properly (crbug.com/135089). | 1399 scale = scale / clientPixelRatio; |
1306 this.plugin_.element().style.width = pluginWidth + 'px'; | 1400 var pluginWidth = Math.round(desktopSize.width * scale); |
1307 this.plugin_.element().style.height = pluginHeight + 'px'; | 1401 var pluginHeight = Math.round(desktopSize.height * scale); |
1308 | 1402 return { width: pluginWidth, height: pluginHeight }; |
1309 // Position the container. | 1403 } |
1310 // Note that clientWidth/Height take into account scrollbars. | |
1311 var clientWidth = document.documentElement.clientWidth; | |
1312 var clientHeight = document.documentElement.clientHeight; | |
1313 var parentNode = this.plugin_.element().parentNode; | |
1314 | |
1315 console.log('plugin dimensions: ' + | |
1316 parentNode.style.left + ',' + | |
1317 parentNode.style.top + '-' + | |
1318 pluginWidth + 'x' + pluginHeight + '.'); | |
1319 | |
1320 // When we receive the first plugin dimensions from the host, we know that | |
1321 // remote host has started. | |
1322 remoting.app.onVideoStreamingStarted(); | |
1323 }; | |
1324 | 1404 |
1325 /** | 1405 /** |
1326 * Returns an associative array with a set of stats for this connection. | 1406 * Returns an associative array with a set of stats for this connection. |
1327 * | 1407 * |
1328 * @return {remoting.ClientSession.PerfStats} The connection statistics. | 1408 * @return {remoting.ClientSession.PerfStats} The connection statistics. |
1329 */ | 1409 */ |
1330 remoting.ClientSession.prototype.getPerfStats = function() { | 1410 remoting.ClientSession.prototype.getPerfStats = function() { |
1331 return this.plugin_.getPerfStats(); | 1411 return this.plugin_.getPerfStats(); |
1332 }; | 1412 }; |
1333 | 1413 |
(...skipping 382 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1716 * @param {Object} message The parsed extension message data. | 1796 * @param {Object} message The parsed extension message data. |
1717 * @return {boolean} True if the message was recognized, false otherwise. | 1797 * @return {boolean} True if the message was recognized, false otherwise. |
1718 */ | 1798 */ |
1719 remoting.ClientSession.prototype.handleExtensionMessage = | 1799 remoting.ClientSession.prototype.handleExtensionMessage = |
1720 function(type, message) { | 1800 function(type, message) { |
1721 if (this.videoFrameRecorder_) { | 1801 if (this.videoFrameRecorder_) { |
1722 return this.videoFrameRecorder_.handleMessage(type, message); | 1802 return this.videoFrameRecorder_.handleMessage(type, message); |
1723 } | 1803 } |
1724 return false; | 1804 return false; |
1725 } | 1805 } |
OLD | NEW |