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.
7 * Provides shared view port management utilities.
10 /** @suppress {duplicate} */
11 var remoting
= remoting
|| {};
18 remoting
.Viewport
= {};
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
29 * @param {{x: number, y: number}} desktopDpi DPI of the host desktop in both
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
+
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
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 // adjusting for the specified desktopScale.
68 // b. If host DPI is less than the client's then up-scale accordingly.
69 // 2. If the natural size of the desktop is smaller than the client device
70 // then apply up-scaling by an integer scale factor to avoid excessive
72 // 3. If shrink-to-fit is configured then:
73 // a. If the natural size exceeds the client size then apply down-scaling
74 // by an arbitrary scale factor.
75 // b. If we're in full-screen mode and the client & host aspect-ratios
76 // are radically different (e.g. the host is actually multi-monitor)
77 // then shrink-to-fit to the shorter dimension, rather than leaving
78 // huge letterboxes; the user can then bump-scroll around the desktop.
79 // 4. If the overall scale factor is fractionally over an integer factor
80 // then reduce it to that integer factor, to avoid blurring.
82 // All calculations are performed in client device pixels, but taking into
83 // account |desktopScale|.
84 var clientWidth
= clientSizeDips
.width
* clientPixelRatio
/ desktopScale
;
85 var clientHeight
= clientSizeDips
.height
* clientPixelRatio
/ desktopScale
;
87 // 1. Determine a "natural" size at which to display the desktop.
90 // Determine the effective host device pixel ratio.
91 // Note that we round up or down to the closest integer pixel ratio.
92 var hostPixelRatioX
= Math
.round(desktopDpi
.x
/ 96);
93 var hostPixelRatioY
= Math
.round(desktopDpi
.y
/ 96);
94 var hostPixelRatio
= Math
.min(hostPixelRatioX
, hostPixelRatioY
);
96 // Allow up-scaling to account for DPI.
97 scale
= Math
.max(scale
, clientPixelRatio
/ hostPixelRatio
);
99 // 2. If the host is still much smaller than the client, then up-scale to
100 // avoid wasting space, but only by an integer factor, to avoid blurring.
101 // Don't drop the scale below that determined based on DPI, though.
102 if (desktopSize
.width
* scale
<= clientWidth
&&
103 desktopSize
.height
* scale
<= clientHeight
) {
104 var scaleX
= Math
.floor(clientWidth
/ desktopSize
.width
);
105 var scaleY
= Math
.floor(clientHeight
/ desktopSize
.height
);
106 scale
= Math
.max(scale
, Math
.min(scaleX
, scaleY
));
107 console
.assert(scale
>= 1.0, 'Bad scale: ' + scale
+ '.');
110 // 3. Apply shrink-to-fit, if configured.
112 var scaleFitWidth
= Math
.min(scale
, clientWidth
/ desktopSize
.width
);
113 var scaleFitHeight
= Math
.min(scale
, clientHeight
/ desktopSize
.height
);
114 scale
= Math
.min(scaleFitHeight
, scaleFitWidth
);
116 // If we're running full-screen then try to handle common side-by-side
117 // multi-monitor combinations more intelligently.
119 // If the host has two monitors each the same size as the client then
120 // scale-to-fit will have the desktop occupy only 50% of the client area,
121 // in which case it would be preferable to down-scale less and let the
122 // user bump-scroll around ("scale-and-pan").
123 // Triggering scale-and-pan if less than 65% of the client area would be
124 // used adds enough fuzz to cope with e.g. 1280x800 client connecting to
125 // a (2x1280)x1024 host nicely.
126 // Note that we don't need to account for scrollbars while fullscreen.
127 if (scale
<= scaleFitHeight
* 0.65) {
128 scale
= scaleFitHeight
;
130 if (scale
<= scaleFitWidth
* 0.65) {
131 scale
= scaleFitWidth
;
136 // 4. Avoid blurring for close-to-integer up-scaling factors.
138 var scaleBlurriness
= scale
/ Math
.floor(scale
);
139 if (scaleBlurriness
< 1.1) {
140 scale
= Math
.floor(scale
);
144 // Return the necessary plugin dimensions in DIPs.
145 scale
= scale
/ clientPixelRatio
;
146 scale
= scale
* desktopScale
;
147 var pluginWidth
= Math
.round(desktopSize
.width
* scale
);
148 var pluginHeight
= Math
.round(desktopSize
.height
* scale
);
149 return { width
: pluginWidth
, height
: pluginHeight
};