OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 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 * Provides view port management utilities below for a desktop remoting session. | 7 * Provides view port management utilities below for a desktop remoting session. |
8 * - Enabling bump scrolling | 8 * - Enabling bump scrolling |
9 * - Resizing the viewport to fit the host desktop | 9 * - Resizing the viewport to fit the host desktop |
10 * - Resizing the host desktop to fit the client viewport. | 10 * - Resizing the host desktop to fit the client viewport. |
(...skipping 312 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
323 remoting.DesktopViewport.prototype.updateDimensions_ = function() { | 323 remoting.DesktopViewport.prototype.updateDimensions_ = function() { |
324 var dimensions = this.hostDesktop_.getDimensions(); | 324 var dimensions = this.hostDesktop_.getDimensions(); |
325 if (dimensions.width === 0 || dimensions.height === 0) { | 325 if (dimensions.width === 0 || dimensions.height === 0) { |
326 return; | 326 return; |
327 } | 327 } |
328 | 328 |
329 var desktopSize = { width: dimensions.width, | 329 var desktopSize = { width: dimensions.width, |
330 height: dimensions.height }; | 330 height: dimensions.height }; |
331 var desktopDpi = { x: dimensions.xDpi, | 331 var desktopDpi = { x: dimensions.xDpi, |
332 y: dimensions.yDpi }; | 332 y: dimensions.yDpi }; |
333 var newSize = remoting.DesktopViewport.choosePluginSize( | 333 var newSize = remoting.Viewport.choosePluginSize( |
334 this.getClientArea(), window.devicePixelRatio, | 334 this.getClientArea(), window.devicePixelRatio, |
335 desktopSize, desktopDpi, this.hostOptions_.desktopScale, | 335 desktopSize, desktopDpi, this.hostOptions_.desktopScale, |
336 remoting.fullscreen.isActive(), this.hostOptions_.shrinkToFit); | 336 remoting.fullscreen.isActive(), this.hostOptions_.shrinkToFit); |
337 | 337 |
338 // Resize the plugin if necessary. | 338 // Resize the plugin if necessary. |
339 console.log('plugin dimensions:' + newSize.width + 'x' + newSize.height); | 339 console.log('plugin dimensions:' + newSize.width + 'x' + newSize.height); |
340 this.pluginElement_.style.width = newSize.width + 'px'; | 340 this.pluginElement_.style.width = newSize.width + 'px'; |
341 this.pluginElement_.style.height = newSize.height + 'px'; | 341 this.pluginElement_.style.height = newSize.height + 'px'; |
342 }; | 342 }; |
343 | 343 |
344 /** | |
345 * Helper function accepting client and host dimensions, and returning a chosen | |
346 * size for the plugin element, in DIPs. | |
347 * | |
348 * @param {{width: number, height: number}} clientSizeDips Available client | |
349 * dimensions, in DIPs. | |
350 * @param {number} clientPixelRatio Number of physical pixels per client DIP. | |
351 * @param {{width: number, height: number}} desktopSize Size of the host desktop | |
352 * in physical pixels. | |
353 * @param {{x: number, y: number}} desktopDpi DPI of the host desktop in both | |
354 * dimensions. | |
355 * @param {number} desktopScale The scale factor configured for the host. | |
356 * @param {boolean} isFullscreen True if full-screen mode is active. | |
357 * @param {boolean} shrinkToFit True if shrink-to-fit should be applied. | |
358 * @return {{width: number, height: number}} Chosen plugin dimensions, in DIPs. | |
359 */ | |
360 remoting.DesktopViewport.choosePluginSize = function( | |
361 clientSizeDips, clientPixelRatio, desktopSize, desktopDpi, desktopScale, | |
362 isFullscreen, shrinkToFit) { | |
363 base.debug.assert(clientSizeDips.width > 0); | |
364 base.debug.assert(clientSizeDips.height > 0); | |
365 base.debug.assert(clientPixelRatio >= 1.0); | |
366 base.debug.assert(desktopSize.width > 0); | |
367 base.debug.assert(desktopSize.height > 0); | |
368 base.debug.assert(desktopDpi.x > 0); | |
369 base.debug.assert(desktopDpi.y > 0); | |
370 base.debug.assert(desktopScale > 0); | |
371 | |
372 // We have the following goals in sizing the desktop display at the client: | |
373 // 1. Avoid losing detail by down-scaling beyond 1:1 host:device pixels. | |
374 // 2. Avoid up-scaling if that will cause the client to need scrollbars. | |
375 // 3. Avoid introducing blurriness with non-integer up-scaling factors. | |
376 // 4. Avoid having huge "letterboxes" around the desktop, if it's really | |
377 // small. | |
378 // 5. Compensate for mismatched DPIs, so that the behaviour of features like | |
379 // shrink-to-fit matches their "natural" rather than their pixel size. | |
380 // e.g. with shrink-to-fit active a 1024x768 low-DPI host on a 640x480 | |
381 // high-DPI client will be up-scaled to 1280x960, rather than displayed | |
382 // at 1:1 host:physical client pixels. | |
383 // | |
384 // To determine the ideal size we follow a four-stage process: | |
385 // 1. Determine the "natural" size at which to display the desktop. | |
386 // a. Initially assume 1:1 mapping of desktop to client device pixels. | |
387 // b. If host DPI is less than the client's then up-scale accordingly. | |
388 // c. If desktopScale is configured for the host then allow that to | |
389 // reduce the amount of up-scaling from (b). e.g. if the client:host | |
390 // DPIs are 2:1 then a desktopScale of 1.5 would reduce the up-scale | |
391 // to 4:3, while a desktopScale of 3.0 would result in no up-scaling. | |
392 // 2. If the natural size of the desktop is smaller than the client device | |
393 // then apply up-scaling by an integer scale factor to avoid excessive | |
394 // letterboxing. | |
395 // 3. If shrink-to-fit is configured then: | |
396 // a. If the natural size exceeds the client size then apply down-scaling | |
397 // by an arbitrary scale factor. | |
398 // b. If we're in full-screen mode and the client & host aspect-ratios | |
399 // are radically different (e.g. the host is actually multi-monitor) | |
400 // then shrink-to-fit to the shorter dimension, rather than leaving | |
401 // huge letterboxes; the user can then bump-scroll around the desktop. | |
402 // 4. If the overall scale factor is fractionally over an integer factor | |
403 // then reduce it to that integer factor, to avoid blurring. | |
404 | |
405 // All calculations are performed in device pixels. | |
406 var clientWidth = clientSizeDips.width * clientPixelRatio; | |
407 var clientHeight = clientSizeDips.height * clientPixelRatio; | |
408 | |
409 // 1. Determine a "natural" size at which to display the desktop. | |
410 var scale = 1.0; | |
411 | |
412 // Determine the effective host device pixel ratio. | |
413 // Note that we round up or down to the closest integer pixel ratio. | |
414 var hostPixelRatioX = Math.round(desktopDpi.x / 96); | |
415 var hostPixelRatioY = Math.round(desktopDpi.y / 96); | |
416 var hostPixelRatio = Math.min(hostPixelRatioX, hostPixelRatioY); | |
417 | |
418 // Allow up-scaling to account for DPI. | |
419 scale = Math.max(scale, clientPixelRatio / hostPixelRatio); | |
420 | |
421 // Allow some or all of the up-scaling to be cancelled by the desktopScale. | |
422 if (desktopScale > 1.0) { | |
423 scale = Math.max(1.0, scale / desktopScale); | |
424 } | |
425 | |
426 // 2. If the host is still much smaller than the client, then up-scale to | |
427 // avoid wasting space, but only by an integer factor, to avoid blurring. | |
428 if (desktopSize.width * scale <= clientWidth && | |
429 desktopSize.height * scale <= clientHeight) { | |
430 var scaleX = Math.floor(clientWidth / desktopSize.width); | |
431 var scaleY = Math.floor(clientHeight / desktopSize.height); | |
432 scale = Math.min(scaleX, scaleY); | |
433 base.debug.assert(scale >= 1.0); | |
434 } | |
435 | |
436 // 3. Apply shrink-to-fit, if configured. | |
437 if (shrinkToFit) { | |
438 var scaleFitWidth = Math.min(scale, clientWidth / desktopSize.width); | |
439 var scaleFitHeight = Math.min(scale, clientHeight / desktopSize.height); | |
440 scale = Math.min(scaleFitHeight, scaleFitWidth); | |
441 | |
442 // If we're running full-screen then try to handle common side-by-side | |
443 // multi-monitor combinations more intelligently. | |
444 if (isFullscreen) { | |
445 // If the host has two monitors each the same size as the client then | |
446 // scale-to-fit will have the desktop occupy only 50% of the client area, | |
447 // in which case it would be preferable to down-scale less and let the | |
448 // user bump-scroll around ("scale-and-pan"). | |
449 // Triggering scale-and-pan if less than 65% of the client area would be | |
450 // used adds enough fuzz to cope with e.g. 1280x800 client connecting to | |
451 // a (2x1280)x1024 host nicely. | |
452 // Note that we don't need to account for scrollbars while fullscreen. | |
453 if (scale <= scaleFitHeight * 0.65) { | |
454 scale = scaleFitHeight; | |
455 } | |
456 if (scale <= scaleFitWidth * 0.65) { | |
457 scale = scaleFitWidth; | |
458 } | |
459 } | |
460 } | |
461 | |
462 // 4. Avoid blurring for close-to-integer up-scaling factors. | |
463 if (scale > 1.0) { | |
464 var scaleBlurriness = scale / Math.floor(scale); | |
465 if (scaleBlurriness < 1.1) { | |
466 scale = Math.floor(scale); | |
467 } | |
468 } | |
469 | |
470 // Return the necessary plugin dimensions in DIPs. | |
471 scale = scale / clientPixelRatio; | |
472 var pluginWidth = Math.round(desktopSize.width * scale); | |
473 var pluginHeight = Math.round(desktopSize.height * scale); | |
474 return { width: pluginWidth, height: pluginHeight }; | |
475 }; | |
476 | |
477 /** @private */ | 344 /** @private */ |
478 remoting.DesktopViewport.prototype.resetScroll_ = function() { | 345 remoting.DesktopViewport.prototype.resetScroll_ = function() { |
479 this.pluginContainer_.style.marginTop = '0px'; | 346 this.pluginContainer_.style.marginTop = '0px'; |
480 this.pluginContainer_.style.marginLeft = '0px'; | 347 this.pluginContainer_.style.marginLeft = '0px'; |
481 }; | 348 }; |
482 | 349 |
483 /** | 350 /** |
484 * Sets and stores the scale factor to apply to host sizing requests. | 351 * Sets and stores the scale factor to apply to host sizing requests. |
485 * The desktopScale applies to the dimensions reported to the host, not | 352 * The desktopScale applies to the dimensions reported to the host, not |
486 * to the client DPI reported to it. | 353 * to the client DPI reported to it. |
487 * | 354 * |
488 * @param {number} desktopScale Scale factor to apply. | 355 * @param {number} desktopScale Scale factor to apply. |
489 */ | 356 */ |
490 remoting.DesktopViewport.prototype.setDesktopScale = function(desktopScale) { | 357 remoting.DesktopViewport.prototype.setDesktopScale = function(desktopScale) { |
491 this.hostOptions_.desktopScale = desktopScale; | 358 this.hostOptions_.desktopScale = desktopScale; |
492 | 359 |
493 // onResize() will update the plugin size and scrollbars for the new | 360 // onResize() will update the plugin size and scrollbars for the new |
494 // scaled plugin dimensions, and send a client resolution notification. | 361 // scaled plugin dimensions, and send a client resolution notification. |
495 this.onResize(); | 362 this.onResize(); |
496 | 363 |
497 // Save the new desktop scale setting. | 364 // Save the new desktop scale setting. |
498 this.hostOptions_.save(); | 365 this.hostOptions_.save(); |
499 }; | 366 }; |
500 | 367 |
501 }()); | 368 }()); |
OLD | NEW |