The Underlying Issue
There are some values that are not settable due to DIP <=> physical pixel rounding at non 100% scaling. It causes jitter and drift when you act on such values.
Background
Helpful terms:
DPI: Dots Per Inch. In windows there are 96 dots (pixels) in a logical inch.
DIP: Device Independent Pixel. 1/96 of a logical inch in windows.
DIP-safe: (made up) A value that if you call setBounds
with, followed by a getBounds
you will always get the same value back.
DIPs = pixels / (DPI / 96)
Pixels = DIPs * (DPI / 96)
When a user sets scaling at the desktop level, what they are doing is setting the DPI part of those equations above to a percentage of pixels per logical inch. For example, 125% scaling would be 1.25 * 96 = 120 DPI
. Notice that in the calculations above the * 96
and the / 96
cancel leaving you with just the scale factor. So for DPI at 120 (125% scaling):DIPs = pixels / (120 / 96)
DIPs = pixels / 1.25
In OpenFin (and Electron) the users of our API deal in DIPs. Let’s take the width, for example, when you use setBounds
to place a window at x: 0, y:0, width: 401, height: 401
under different scale factors. Note: that To Pixels is effectively setBounds
and Back to DIP is getBounds
.
Set DIP | Scale Factor | DPI | To Pixels | Back to DIP |
---|---|---|---|---|
401 | 100% | 96 | 401 | 401 |
401 | 125% | 120 | 502 | 402 |
401 | 150% | 144 | 602 | 402 |
401 | 175% | 168 | 702 | 402 |
401 | 200% | 192 | 802 | 401 |
Notice those nasty 402's on the way back in some cases. What's happening? During the course of the calculations non integer values are being produced for pixel values. Take 401 at 125% for example, to get the pixels you need to do 401 * 1.25 = 501.25
which gets ceiling-ed up to 502
as you can't have .25
of a physical pixel. Basically 401 @ 125% scaling is unsettable, which obviously is a problem when it (or anything like it) comes up in window position calculations.
To see it live, you can set scaling and run the following:
(async () => { let i = 0; const base = 400; const w = fin.Window.getCurrentSync(); while (i < 26) { const setTo = base + i; await w.setBounds({ top: 0, left: 0, height: setTo, width: setTo }); let { height, width } = await w.getBounds() console.log(`set to ${setTo} => height: ${height} width: ${width}`); i++; } })()
If you grab electron quickstart and run the following at 125% scaling, note the same rounding issues are present.
const electron = require('electron'); electron.remote.getCurrentWindow().setBounds({x: 0, y: 0, width: 401, height: 401}); electron.remote.getCurrentWindow().getBounds();
Comments
0 comments
Please sign in to leave a comment.