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