Merge lp:~ubuntu-sdk-team/ubuntu-ui-toolkit/dpr into lp:ubuntu-ui-toolkit

Proposed by Gerry Boland
Status: Superseded
Proposed branch: lp:~ubuntu-sdk-team/ubuntu-ui-toolkit/dpr
Merge into: lp:ubuntu-ui-toolkit
Prerequisite: lp:ubuntu-ui-toolkit/staging
Diff against target: 245 lines (+61/-29)
5 files modified
modules/Ubuntu/Components/plugin/ucqquickimageextension.cpp (+10/-3)
modules/Ubuntu/Components/plugin/ucubuntushape.cpp (+8/-10)
modules/Ubuntu/Components/plugin/ucunits.cpp (+37/-12)
modules/Ubuntu/Components/plugin/ucunits.h (+5/-3)
ubuntu-sdk.pro (+1/-1)
To merge this branch: bzr merge lp:~ubuntu-sdk-team/ubuntu-ui-toolkit/dpr
Reviewer Review Type Date Requested Status
Ubuntu SDK team Pending
Review via email: mp+256469@code.launchpad.net

This proposal has been superseded by a proposal from 2015-04-16.

Description of the change

[RFC] Compensate for Qt's device pixel ratio multiplier

The UITK has flexible UI scaling support through the use of Grid Units, where one can set a grid unit to be an integer number of pixels, and the whole UI adopts to suit this. GRID_UNIT_PX=10 is the way to set this.

Qt however has its own scaling solution: QScreen::devicePixelRatio->qreal which is a multiplier applied internally to all sizing/positioning calculations. Only integer values are well supported, so 1,2,3... are the options, resulting in a x2, x3 scaling of the entire UI. For linux and X11, devicePixelRatio is specified with QT_DEVICE_PIXEL_RATIO=2. In this case, if a QML item is set to have height 100, it will be drawn 200 pixels high (but QML has no idea of this, it is still 100 in height)

This latter solution works for all Qt apps, whereas Grid units only apply to UITK-based apps. For a HighDPI desktop, we want to use both solutions.

However these two scaling solutions are cumulative. Should one set
QT_DEVICE_PIXEL_RATIO=2 GRID_UNIT_PX=10
then a box of height units.gu(1) will be drawn 20 physical pixels high.

The intention of this MR is to guarantee that GRID_UNIT_PX corresponds to physical pixels, no matter what QScreen::devicePixelRatio returns. To do this, it divides units.{gu,dp} by devicePixelRatio, so that when Qt multiplies it by devicePixelRatio again on draw, the desired physical pixel size is obtained.

To test, open the gallery with these 2 different envs:
QT_DEVICE_PIXEL_RATIO=1 GRID_UNIT_PX=10
QT_DEVICE_PIXEL_RATIO=2 GRID_UNIT_PX=10

Some visual inconsistencies are exact font rendering sizes and some rounding issues causing off-by-one positioning errors.

To post a comment you must log in.
1172. By Gerry Boland

Cleanup debug output and re-enable tests

1173. By Gerry Boland

Remove translation changes in trunk to clean up diff with staging

1174. By Gerry Boland

UbuntuShape fixes for low GU values

1175. By Gerry Boland

More correct fix for UbuntuShape at different DPR, edges should render nicely now

1176. By Gerry Boland

Add tests to ensure units.gu and units.dp are being calculated correctly

1177. By Gerry Boland

No need to pass svg to scaling image provider for non-unit DPR. Expand on a comment explaining an odd line

1178. By Gerry Boland

Merge current staging branch

1179. By Gerry Boland

Revert 1173

1180. By Gerry Boland

Fix bad math

1181. By Gerry Boland

Merge staging

1182. By Gerry Boland

Update Ubuntu shape overlay for device pixel ratio too

1183. By Gerry Boland

In UbuntuShape, refactor DPR calculations to have radius in device pixels, simplifies updateGeometry

1184. By Gerry Boland

UCUnits - deconstify value params

1185. By Gerry Boland

Read device pixel ratio from QGuiApplication, instead of reading the env var

1186. By Gerry Boland

Rely on DPR from qGuiApp, do not read env var in UCUnits directly. Requires refactoring tests into separate binaries to be able to set that env var

1187. By Gerry Boland

Fix bug in SCI file rewriter for DPR>1

1188. By Gerry Boland

Merge trunk

1189. By Gerry Boland

Unnecessary copy of dpr value removed

1190. By Gerry Boland

[tests] added a custom minimal QPA plugin which includes device pixel support, to enable testing of dpr stuff

1191. By Gerry Boland

Merge trunk

1192. By Gerry Boland

Using custom QPA plugin, now have device pixel ratio unit tests passing

1193. By Gerry Boland

Add explanation text about DPR and GU

1194. By Gerry Boland

Consolidate the vocabulary a bit

1195. By Gerry Boland

Add missing build dependencies

1196. By Gerry Boland

Bump version

1197. By Gerry Boland

Merge staging and fix conflicts

1198. By Gerry Boland

Revert rev 1196

1199. By Gerry Boland

Merge staging, fix a conflict

1200. By Gerry Boland

Undo changes to paths for gallery launcher

1201. By Gerry Boland

Merge staging

1202. By Gerry Boland

Fix build fail - variable inited twice

1203. By Gerry Boland

Merge staging again

1204. By Gerry Boland

Merge staging again

1205. By Gerry Boland

Revert accidental changes to examples/ubuntu-ui-toolkit-gallery/po/nl.po

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'modules/Ubuntu/Components/plugin/ucqquickimageextension.cpp'
--- modules/Ubuntu/Components/plugin/ucqquickimageextension.cpp 2014-11-24 13:14:35 +0000
+++ modules/Ubuntu/Components/plugin/ucqquickimageextension.cpp 2015-04-16 11:47:11 +0000
@@ -78,13 +78,19 @@
78 QString selectedFilePath = resolved.mid(separatorPosition+1);78 QString selectedFilePath = resolved.mid(separatorPosition+1);
7979
80 if (scaleFactor == "1") {80 if (scaleFactor == "1") {
81 // No scaling. Just pass the file as is.81 if (qFuzzyCompare(UCUnits::instance().devicePixelRatio(), 1.0f)) {
82 m_image->setSource(QUrl::fromLocalFile(selectedFilePath));82 // No scaling. Just pass the file as is.
83 m_image->setSource(QUrl::fromLocalFile(selectedFilePath));
84 } else {
85 m_image->setSource(QUrl("image://scaling/1/" + selectedFilePath));
86 m_image->setSourceSize(m_image->sourceSize()); // explicitly set the source size as we know it
87 }
83 } else {88 } else {
84 // Prepend "image://scaling" for the image to be loaded by UCScalingImageProvider.89 // Prepend "image://scaling" for the image to be loaded by UCScalingImageProvider.
85 if (!m_source.path().endsWith(".sci")) {90 if (!m_source.path().endsWith(".sci")) { qDebug() << "scaled";
86 // Regular image file91 // Regular image file
87 m_image->setSource(QUrl("image://scaling/" + resolved));92 m_image->setSource(QUrl("image://scaling/" + resolved));
93 m_image->setSourceSize(m_image->sourceSize()); // explicitly set the source size as we know it
88 } else {94 } else {
89 // .sci image file. Rewrite the .sci file into a temporary file.95 // .sci image file. Rewrite the .sci file into a temporary file.
90 bool rewritten = true;96 bool rewritten = true;
@@ -111,6 +117,7 @@
111 } else {117 } else {
112 m_image->setSource(m_source);118 m_image->setSource(m_source);
113 }119 }
120 m_image->setSourceSize(m_image->sourceSize()); // explicitly set the source size as we know it
114 }121 }
115 }122 }
116}123}
117124
=== modified file 'modules/Ubuntu/Components/plugin/ucubuntushape.cpp'
--- modules/Ubuntu/Components/plugin/ucubuntushape.cpp 2015-04-16 11:47:10 +0000
+++ modules/Ubuntu/Components/plugin/ucubuntushape.cpp 2015-04-16 11:47:11 +0000
@@ -320,10 +320,7 @@
320 setFlag(ItemHasContents);320 setFlag(ItemHasContents);
321 QObject::connect(&UCUnits::instance(), SIGNAL(gridUnitChanged()), this,321 QObject::connect(&UCUnits::instance(), SIGNAL(gridUnitChanged()), this,
322 SLOT(_q_gridUnitChanged()));322 SLOT(_q_gridUnitChanged()));
323 const float gridUnit = UCUnits::instance().gridUnit();323 _q_gridUnitChanged();
324 setImplicitWidth(implicitWidthGU * gridUnit);
325 setImplicitHeight(implicitHeightGU * gridUnit);
326 update();
327}324}
328325
329/*! \qmlproperty string UbuntuShape::radius326/*! \qmlproperty string UbuntuShape::radius
@@ -968,9 +965,9 @@
968965
969void UCUbuntuShape::_q_gridUnitChanged()966void UCUbuntuShape::_q_gridUnitChanged()
970{967{
971 const float gridUnit = UCUnits::instance().gridUnit();968 const float gridUnitInDevicePixels = UCUnits::instance().gridUnit() / UCUnits::instance().devicePixelRatio();
972 setImplicitWidth(implicitWidthGU * gridUnit);969 setImplicitWidth(implicitWidthGU * gridUnitInDevicePixels);
973 setImplicitHeight(implicitHeightGU * gridUnit);970 setImplicitHeight(implicitHeightGU * gridUnitInDevicePixels);
974 update();971 update();
975}972}
976973
@@ -1063,6 +1060,7 @@
1063{1060{
1064 Q_UNUSED(data);1061 Q_UNUSED(data);
10651062
1063 const float dpr = UCUnits::instance().devicePixelRatio();
1066 const QSizeF itemSize(width(), height());1064 const QSizeF itemSize(width(), height());
1067 if (itemSize.isEmpty()) {1065 if (itemSize.isEmpty()) {
1068 delete oldNode;1066 delete oldNode;
@@ -1101,12 +1099,12 @@
1101 }1099 }
1102 if (m_flags & DirtySourceTransform) {1100 if (m_flags & DirtySourceTransform) {
1103 if (m_flags & SourceApiSet) {1101 if (m_flags & SourceApiSet) {
1104 updateSourceTransform(itemSize.width(), itemSize.height(), m_sourceFillMode,1102 updateSourceTransform(itemSize.width() * dpr, itemSize.height() * dpr, m_sourceFillMode,
1105 m_sourceHorizontalAlignment, m_sourceVerticalAlignment,1103 m_sourceHorizontalAlignment, m_sourceVerticalAlignment,
1106 sourceTexture->textureSize());1104 sourceTexture->textureSize());
1107 } else {1105 } else {
1108 FillMode imageFillMode = (m_flags & Stretched) ? Stretch : PreserveAspectCrop;1106 FillMode imageFillMode = (m_flags & Stretched) ? Stretch : PreserveAspectCrop;
1109 updateSourceTransform(itemSize.width(), itemSize.height(), imageFillMode,1107 updateSourceTransform(itemSize.width() * dpr, itemSize.height() * dpr, imageFillMode,
1110 m_imageHorizontalAlignment, m_imageVerticalAlignment,1108 m_imageHorizontalAlignment, m_imageVerticalAlignment,
1111 sourceTexture->textureSize());1109 sourceTexture->textureSize());
1112 }1110 }
@@ -1133,7 +1131,7 @@
1133 // scaled down accordingly. The shape was using a fixed image for the corner before switching to1131 // scaled down accordingly. The shape was using a fixed image for the corner before switching to
1134 // a distance field, since the corner wasn't taking the whole image (ending at ~80%) we need1132 // a distance field, since the corner wasn't taking the whole image (ending at ~80%) we need
1135 // to take that into account when the size is scaled down.1133 // to take that into account when the size is scaled down.
1136 float radius = UCUnits::instance().gridUnit()1134 float radius = UCUnits::instance().gridUnit() / UCUnits::instance().devicePixelRatio()
1137 * (m_radius == Small ? smallRadiusGU : mediumRadiusGU);1135 * (m_radius == Small ? smallRadiusGU : mediumRadiusGU);
1138 const float scaledDownRadius = qMin(itemSize.width(), itemSize.height()) * 0.5f * 0.8f;1136 const float scaledDownRadius = qMin(itemSize.width(), itemSize.height()) * 0.5f * 0.8f;
1139 if (radius > scaledDownRadius) {1137 if (radius > scaledDownRadius) {
11401138
=== modified file 'modules/Ubuntu/Components/plugin/ucunits.cpp'
--- modules/Ubuntu/Components/plugin/ucunits.cpp 2015-03-03 13:47:48 +0000
+++ modules/Ubuntu/Components/plugin/ucunits.cpp 2015-04-16 11:47:11 +0000
@@ -24,6 +24,9 @@
24#include <QtCore/QDir>24#include <QtCore/QDir>
25#include <QtCore/QRegularExpression>25#include <QtCore/QRegularExpression>
26#include <QtCore/qmath.h>26#include <QtCore/qmath.h>
27#include <QtCore/QDebug>
28#include <QtGui/QGuiApplication>
29#include <QtGui/QScreen>
2730
28#define ENV_GRID_UNIT_PX "GRID_UNIT_PX"31#define ENV_GRID_UNIT_PX "GRID_UNIT_PX"
29#define DEFAULT_GRID_UNIT_PX 832#define DEFAULT_GRID_UNIT_PX 8
@@ -65,7 +68,20 @@
65UCUnits::UCUnits(QObject *parent) :68UCUnits::UCUnits(QObject *parent) :
66 QObject(parent)69 QObject(parent)
67{70{
68 m_gridUnit = getenvFloat(ENV_GRID_UNIT_PX, DEFAULT_GRID_UNIT_PX);71 QScreen *screen = QGuiApplication::primaryScreen();
72 if (screen) {
73 m_devicePixelRatio = screen->devicePixelRatio();
74 } else {
75 m_devicePixelRatio = 1.0;
76 }
77
78 // If GRID_UNIT_PX set, always use it. If not, 1GU := DEFAULT_GRID_UNIT_PX * m_devicePixelRatio
79 if (qEnvironmentVariableIsSet(ENV_GRID_UNIT_PX)) {
80 m_gridUnit = getenvFloat(ENV_GRID_UNIT_PX, DEFAULT_GRID_UNIT_PX);
81 } else {
82 m_gridUnit = DEFAULT_GRID_UNIT_PX * m_devicePixelRatio;
83 }
84 qDebug() << "Initial GU" << m_gridUnit;
69}85}
7086
71/*!87/*!
@@ -78,8 +94,8 @@
78 return m_gridUnit;94 return m_gridUnit;
79}95}
8096
81void UCUnits::setGridUnit(float gridUnit)97void UCUnits::setGridUnit(const float gridUnit)
82{98{ qDebug() << "Override GU" << gridUnit;
83 m_gridUnit = gridUnit;99 m_gridUnit = gridUnit;
84 Q_EMIT gridUnitChanged();100 Q_EMIT gridUnitChanged();
85}101}
@@ -87,27 +103,35 @@
87/*!103/*!
88 \qmlmethod real Units::dp(real value)104 \qmlmethod real Units::dp(real value)
89105
90 Returns the number of pixels \a value density independent pixels correspond to.106 Returns the number of device pixels \a value density independent pixels correspond to.
91*/107*/
92float UCUnits::dp(float value)108// Device pixels (and not actual pixels) because QML sizes in terms of device pixels.
109float UCUnits::dp(const float value)
93{110{
94 const float ratio = m_gridUnit / DEFAULT_GRID_UNIT_PX;111 const float ratio = m_gridUnit / DEFAULT_GRID_UNIT_PX;
95 if (value <= 2.0) {112 if (value <= 2.0) {
96 // for values under 2dp, return only multiples of the value113 // for values under 2dp, return only multiples of the value
97 return qRound(value * qFloor(ratio));114 return qRound(value * qFloor(ratio)) / m_devicePixelRatio;
98 } else {115 } else {
99 return qRound(value * ratio);116 return qRound(value * ratio) / m_devicePixelRatio;
100 }117 }
101}118}
102119
103/*!120/*!
104 \qmlmethod real Units::gu(real value)121 \qmlmethod real Units::gu(real value)
105122
106 Returns the number of pixels \a value grid units correspond to.123 Returns the number of device pixels \a value grid units correspond to.
107*/124*/
108float UCUnits::gu(float value)125// Device pixels (and not actual pixels) because QML sizes in terms of device pixels.
109{126
110 return qRound(value * m_gridUnit);127float UCUnits::gu(const float value)
128{
129 return qRound(value * m_gridUnit) / m_devicePixelRatio;
130}
131
132float UCUnits::devicePixelRatio() const
133{
134 return m_devicePixelRatio;
111}135}
112136
113QString UCUnits::resolveResource(const QUrl& url)137QString UCUnits::resolveResource(const QUrl& url)
@@ -172,11 +196,12 @@
172196
173 path = prefix + suffixForGridUnit(selectedGridUnitSuffix) + suffix;197 path = prefix + suffixForGridUnit(selectedGridUnitSuffix) + suffix;
174 float scaleFactor = m_gridUnit / selectedGridUnitSuffix;198 float scaleFactor = m_gridUnit / selectedGridUnitSuffix;
199 qDebug() << "P" << path << scaleFactor;
175 return QString::number(scaleFactor) + "/" + path;200 return QString::number(scaleFactor) + "/" + path;
176 }201 }
177202
178 path = prefix + suffix;203 path = prefix + suffix;
179 if (QFile::exists(path)) {204 if (QFile::exists(path)) { qDebug() << "P" << path;
180 return QString("1") + "/" + path;205 return QString("1") + "/" + path;
181 }206 }
182207
183208
=== modified file 'modules/Ubuntu/Components/plugin/ucunits.h'
--- modules/Ubuntu/Components/plugin/ucunits.h 2013-10-18 08:56:39 +0000
+++ modules/Ubuntu/Components/plugin/ucunits.h 2015-04-16 11:47:11 +0000
@@ -35,15 +35,16 @@
35 }35 }
3636
37 explicit UCUnits(QObject *parent = 0);37 explicit UCUnits(QObject *parent = 0);
38 Q_INVOKABLE float dp(float value);38 Q_INVOKABLE float dp(const float value);
39 Q_INVOKABLE float gu(float value);39 Q_INVOKABLE float gu(const float value);
40 QString resolveResource(const QUrl& url);40 QString resolveResource(const QUrl& url);
4141
42 // getters42 // getters
43 float gridUnit();43 float gridUnit();
44 float devicePixelRatio() const;
4445
45 // setters46 // setters
46 void setGridUnit(float gridUnit);47 void setGridUnit(const float gridUnit);
4748
48Q_SIGNALS:49Q_SIGNALS:
49 void gridUnitChanged();50 void gridUnitChanged();
@@ -53,6 +54,7 @@
53 float gridUnitSuffixFromFileName(const QString &fileName);54 float gridUnitSuffixFromFileName(const QString &fileName);
5455
55private:56private:
57 float m_devicePixelRatio;
56 float m_gridUnit;58 float m_gridUnit;
57};59};
5860
5961
=== modified file 'ubuntu-sdk.pro'
--- ubuntu-sdk.pro 2015-03-12 14:13:58 +0000
+++ ubuntu-sdk.pro 2015-04-16 11:47:11 +0000
@@ -1,7 +1,7 @@
1include( documentation/documentation.pri )1include( documentation/documentation.pri )
22
3TEMPLATE = subdirs3TEMPLATE = subdirs
4SUBDIRS += modules/ubuntu-ui-toolkit.pro tests examples po4SUBDIRS += modules/ubuntu-ui-toolkit.pro #tests examples po
55
6BUILD_PATH_CONTENTS="SRC_DIR=\"$$PWD\"" \6BUILD_PATH_CONTENTS="SRC_DIR=\"$$PWD\"" \
7 "BUILD_DIR=\"$$OUT_PWD\""7 "BUILD_DIR=\"$$OUT_PWD\""

Subscribers

People subscribed via source and target branches

to status/vote changes: