OLD | NEW |
(Empty) | |
| 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 |
| 3 // found in the LICENSE file. |
| 4 |
| 5 /** |
| 6 * @fileoverview |
| 7 * Provides shared view port management utilities. |
| 8 */ |
| 9 |
| 10 /** @suppress {duplicate} */ |
| 11 var remoting = remoting || {}; |
| 12 |
| 13 (function() { |
| 14 |
| 15 'use strict'; |
| 16 |
| 17 /** @type {Object} */ |
| 18 remoting.Viewport = {}; |
| 19 |
| 20 /** |
| 21 * Helper function accepting client and host dimensions, and returning a chosen |
| 22 * size for the plugin element, in DIPs. |
| 23 * |
| 24 * @param {{width: number, height: number}} clientSizeDips Available client |
| 25 * dimensions, in DIPs. |
| 26 * @param {number} clientPixelRatio Number of physical pixels per client DIP. |
| 27 * @param {{width: number, height: number}} desktopSize Size of the host desktop |
| 28 * in physical pixels. |
| 29 * @param {{x: number, y: number}} desktopDpi DPI of the host desktop in both |
| 30 * dimensions. |
| 31 * @param {number} desktopScale The scale factor configured for the host. |
| 32 * @param {boolean} isFullscreen True if full-screen mode is active. |
| 33 * @param {boolean} shrinkToFit True if shrink-to-fit should be applied. |
| 34 * @return {{width: number, height: number}} Chosen plugin dimensions, in DIPs. |
| 35 */ |
| 36 remoting.Viewport.choosePluginSize = function( |
| 37 clientSizeDips, clientPixelRatio, desktopSize, desktopDpi, desktopScale, |
| 38 isFullscreen, shrinkToFit) { |
| 39 base.debug.assert(clientSizeDips.width > 0); |
| 40 base.debug.assert(clientSizeDips.height > 0); |
| 41 base.debug.assert(clientPixelRatio >= 1.0); |
| 42 base.debug.assert(desktopSize.width > 0); |
| 43 base.debug.assert(desktopSize.height > 0); |
| 44 base.debug.assert(desktopDpi.x > 0); |
| 45 base.debug.assert(desktopDpi.y > 0); |
| 46 base.debug.assert(desktopScale > 0); |
| 47 |
| 48 // We have the following goals in sizing the desktop display at the client: |
| 49 // 1. Avoid losing detail by down-scaling beyond 1:1 host:device pixels. |
| 50 // 2. Avoid up-scaling if that will cause the client to need scrollbars. |
| 51 // 3. Avoid introducing blurriness with non-integer up-scaling factors. |
| 52 // 4. Avoid having huge "letterboxes" around the desktop, if it's really |
| 53 // small. |
| 54 // 5. Compensate for mismatched DPIs, so that the behaviour of features like |
| 55 // shrink-to-fit matches their "natural" rather than their pixel size. |
| 56 // e.g. with shrink-to-fit active a 1024x768 low-DPI host on a 640x480 |
| 57 // high-DPI client will be up-scaled to 1280x960, rather than displayed |
| 58 // at 1:1 host:physical client pixels. |
| 59 // |
| 60 // To determine the ideal size we follow a four-stage process: |
| 61 // 1. Determine the "natural" size at which to display the desktop. |
| 62 // a. Initially assume 1:1 mapping of desktop to client device pixels. |
| 63 // b. If host DPI is less than the client's then up-scale accordingly. |
| 64 // c. If desktopScale is configured for the host then allow that to |
| 65 // reduce the amount of up-scaling from (b). e.g. if the client:host |
| 66 // DPIs are 2:1 then a desktopScale of 1.5 would reduce the up-scale |
| 67 // to 4:3, while a desktopScale of 3.0 would result in no up-scaling. |
| 68 // 2. If the natural size of the desktop is smaller than the client device |
| 69 // then apply up-scaling by an integer scale factor to avoid excessive |
| 70 // letterboxing. |
| 71 // 3. If shrink-to-fit is configured then: |
| 72 // a. If the natural size exceeds the client size then apply down-scaling |
| 73 // by an arbitrary scale factor. |
| 74 // b. If we're in full-screen mode and the client & host aspect-ratios |
| 75 // are radically different (e.g. the host is actually multi-monitor) |
| 76 // then shrink-to-fit to the shorter dimension, rather than leaving |
| 77 // huge letterboxes; the user can then bump-scroll around the desktop. |
| 78 // 4. If the overall scale factor is fractionally over an integer factor |
| 79 // then reduce it to that integer factor, to avoid blurring. |
| 80 |
| 81 // All calculations are performed in device pixels. |
| 82 var clientWidth = clientSizeDips.width * clientPixelRatio; |
| 83 var clientHeight = clientSizeDips.height * clientPixelRatio; |
| 84 |
| 85 // 1. Determine a "natural" size at which to display the desktop. |
| 86 var scale = 1.0; |
| 87 |
| 88 // Determine the effective host device pixel ratio. |
| 89 // Note that we round up or down to the closest integer pixel ratio. |
| 90 var hostPixelRatioX = Math.round(desktopDpi.x / 96); |
| 91 var hostPixelRatioY = Math.round(desktopDpi.y / 96); |
| 92 var hostPixelRatio = Math.min(hostPixelRatioX, hostPixelRatioY); |
| 93 |
| 94 // Allow up-scaling to account for DPI. |
| 95 scale = Math.max(scale, clientPixelRatio / hostPixelRatio); |
| 96 |
| 97 // Allow some or all of the up-scaling to be cancelled by the desktopScale. |
| 98 if (desktopScale > 1.0) { |
| 99 scale = Math.max(1.0, scale / desktopScale); |
| 100 } |
| 101 |
| 102 // 2. If the host is still much smaller than the client, then up-scale to |
| 103 // avoid wasting space, but only by an integer factor, to avoid blurring. |
| 104 if (desktopSize.width * scale <= clientWidth && |
| 105 desktopSize.height * scale <= clientHeight) { |
| 106 var scaleX = Math.floor(clientWidth / desktopSize.width); |
| 107 var scaleY = Math.floor(clientHeight / desktopSize.height); |
| 108 scale = Math.min(scaleX, scaleY); |
| 109 base.debug.assert(scale >= 1.0); |
| 110 } |
| 111 |
| 112 // 3. Apply shrink-to-fit, if configured. |
| 113 if (shrinkToFit) { |
| 114 var scaleFitWidth = Math.min(scale, clientWidth / desktopSize.width); |
| 115 var scaleFitHeight = Math.min(scale, clientHeight / desktopSize.height); |
| 116 scale = Math.min(scaleFitHeight, scaleFitWidth); |
| 117 |
| 118 // If we're running full-screen then try to handle common side-by-side |
| 119 // multi-monitor combinations more intelligently. |
| 120 if (isFullscreen) { |
| 121 // If the host has two monitors each the same size as the client then |
| 122 // scale-to-fit will have the desktop occupy only 50% of the client area, |
| 123 // in which case it would be preferable to down-scale less and let the |
| 124 // user bump-scroll around ("scale-and-pan"). |
| 125 // Triggering scale-and-pan if less than 65% of the client area would be |
| 126 // used adds enough fuzz to cope with e.g. 1280x800 client connecting to |
| 127 // a (2x1280)x1024 host nicely. |
| 128 // Note that we don't need to account for scrollbars while fullscreen. |
| 129 if (scale <= scaleFitHeight * 0.65) { |
| 130 scale = scaleFitHeight; |
| 131 } |
| 132 if (scale <= scaleFitWidth * 0.65) { |
| 133 scale = scaleFitWidth; |
| 134 } |
| 135 } |
| 136 } |
| 137 |
| 138 // 4. Avoid blurring for close-to-integer up-scaling factors. |
| 139 if (scale > 1.0) { |
| 140 var scaleBlurriness = scale / Math.floor(scale); |
| 141 if (scaleBlurriness < 1.1) { |
| 142 scale = Math.floor(scale); |
| 143 } |
| 144 } |
| 145 |
| 146 // Return the necessary plugin dimensions in DIPs. |
| 147 scale = scale / clientPixelRatio; |
| 148 var pluginWidth = Math.round(desktopSize.width * scale); |
| 149 var pluginHeight = Math.round(desktopSize.height * scale); |
| 150 return { width: pluginWidth, height: pluginHeight }; |
| 151 }; |
| 152 |
| 153 }()); |
OLD | NEW |