In iOS all the units are provided in points, what is fine. The problems appear when you're working with devices on which Apple does some additional transformation (downsampling\upsampling), currently these are iPhone 6 (only in Display Zoom mode) and iPhone 6 Plus.
Look at this scheme: http://www.paintcodeapp.com/news/ultimate-guide-to-iphone-resolutions
I'm talking now about that Rendered Pixels -> Physical Pixels step.
1) Use Qt 5.6.0 Beta (high dpi is not supported properly in 5.5.1)
2) Create a rectangle in QML and set it's width and height to 50 * Screen.pixelDensity (so you make it have physical size of 5cm in both directions)
3) Run the app on iPhone 6S Plus and use ruler to measure the physical size of displayed rectangle, it will be less than 5cm.
4) If you run it on any Android smartphone you will see that it's geometry is 5cm sharp.
Now if you multiply the width and height by 1.15 (if you use iPhone 6s Plus and Display Zoom mode is off), you will see that at this time it works as it should.
More complicated (and real) example is when you are using dp in your calculations like this:
property real dp: Screen.pixelDensity * 25.4 / 160
Now, this will work fine on any Android smartphone, iPhone 3G/3GS/4/4S/5/5S/6, but on iPhone 6S with enabled Display Zoom mode or iPhone 6S Plus you'll get the wrong result. I hope it's clear for you now why it's happening: Qt provides us the resolution in points, let's say it is 414 for width. Also we have devicePixelRatio, which is 3. Then 414 * 3 = 1242, but the real width of iPhone 6S plus in pixels is 1080. 1242 / 1080 = 1.15. Voila.
The possible solution:
I checked the interface of QScreen class, there's nothing currently gives us the real pixel size of iOS device (all values are provided in point units). So, I guess, we have not that many options. I'd add a new property which would expose the value of that transformation to Qt/QML. I checked iOS API, UIScreen class provides the real size of iPhone in pixels by nativeBounds property, so the expression would be like
return [UIScreen mainScreen].fixedCoordinateSpace.bounds.size.width * [[UIScreen mainScreen] scale] / [[UIScreen mainScreen] nativeBounds].size.width;
(this is the first Objective C code I've written)
It is important, because using of dp units is a very common approach for mobile apps.
Here are some useful articles if you are not familiar with all these calculations:
> Dot vs Pixel: https://99designs.com/designer-blog/2013/02/26/ppi-vs-dpi-whats-the-difference/
> DP: http://developer.android.com/guide/practices/screens_support.html
> iPhone resolutions: http://www.paintcodeapp.com/news/ultimate-guide-to-iphone-resolutions
I just found that it's even more serious than I thought. QScreen returns wrong physical size with the same error as this transformation in 5.6 Release Candidate!
QQuickWindow window = qobject_cast<QQuickWindow>(engine.rootObjects().first());
qDebug() << window->screen()->physicalSize();
Here are results of the test I've done oniPhone 6S Plus:
Display zoom off: QSizeF(78.6703, 139.858)
Display zoom on: QSizeF(71.2594, 126.747)
The real physical size of iPhone 6S Plus screen is about 69x122mm (I just measured it with a ruler). Now, again:
69 * 1.15 = 79.35
122 * 1.15 = 140.3
69 / 0.96 = 81.875
122 / 0.96 = 127.08
So, resuming, there are two things need to be done:
1) Add a new property which would expose the coefficient of downsampling/upsampling transformation on iPhone 6S Plus and it would return 1.0 on any other platform/device (see the expression above);
2) The result of physicalSize() method needs to be multiplied by that new property.
|For Gerrit Dashboard: QTBUG-50941|
|157140,2||iOS: Report correct physicalSize and physicalDotsPerInch for iPhone6+||5.6||qt/qtbase||Status: MERGED||+2||0|
|161333,4||QScreen: Don’t scale physical DPI||dev||qt/qtbase||Status: DEFERRED||-1||0|
|183407,1||QScreen: Don’t scale physical DPI||5.8||qt/qtbase||Status: ABANDONED||0||0|