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

Proposed by Gerry Boland on 2015-04-16
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 2015-04-16 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 on 2015-04-16

Cleanup debug output and re-enable tests

1173. By Gerry Boland on 2015-04-16

Remove translation changes in trunk to clean up diff with staging

1174. By Gerry Boland on 2015-04-20

UbuntuShape fixes for low GU values

1175. By Gerry Boland on 2015-04-20

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

1176. By Gerry Boland on 2015-04-21

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

1177. By Gerry Boland on 2015-04-24

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 on 2015-04-27

Merge current staging branch

1179. By Gerry Boland on 2015-04-27

Revert 1173

1180. By Gerry Boland on 2015-04-28

Fix bad math

1181. By Gerry Boland on 2015-05-07

Merge staging

1182. By Gerry Boland on 2015-05-07

Update Ubuntu shape overlay for device pixel ratio too

1183. By Gerry Boland on 2015-05-19

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

1184. By Gerry Boland on 2015-05-19

UCUnits - deconstify value params

1185. By Gerry Boland on 2015-05-19

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

1186. By Gerry Boland on 2015-05-22

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 on 2015-05-22

Fix bug in SCI file rewriter for DPR>1

1188. By Gerry Boland on 2015-06-17

Merge trunk

1189. By Gerry Boland on 2015-06-17

Unnecessary copy of dpr value removed

1190. By Gerry Boland on 2015-06-17

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

1191. By Gerry Boland on 2015-07-10

Merge trunk

1192. By Gerry Boland on 2015-07-10

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

1193. By Gerry Boland on 2015-07-10

Add explanation text about DPR and GU

1194. By Gerry Boland on 2015-07-10

Consolidate the vocabulary a bit

1195. By Gerry Boland on 2015-07-10

Add missing build dependencies

1196. By Gerry Boland on 2015-07-14

Bump version

1197. By Gerry Boland on 2015-07-27

Merge staging and fix conflicts

1198. By Gerry Boland on 2015-07-27

Revert rev 1196

1199. By Gerry Boland on 2015-08-04

Merge staging, fix a conflict

1200. By Gerry Boland on 2015-08-11

Undo changes to paths for gallery launcher

1201. By Gerry Boland on 2015-08-11

Merge staging

1202. By Gerry Boland on 2015-08-12

Fix build fail - variable inited twice

1203. By Gerry Boland on 2015-08-12

Merge staging again

1204. By Gerry Boland on 2015-08-12

Merge staging again

1205. By Gerry Boland on 2015-08-12

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
1=== modified file 'modules/Ubuntu/Components/plugin/ucqquickimageextension.cpp'
2--- modules/Ubuntu/Components/plugin/ucqquickimageextension.cpp 2014-11-24 13:14:35 +0000
3+++ modules/Ubuntu/Components/plugin/ucqquickimageextension.cpp 2015-04-16 11:47:11 +0000
4@@ -78,13 +78,19 @@
5 QString selectedFilePath = resolved.mid(separatorPosition+1);
6
7 if (scaleFactor == "1") {
8- // No scaling. Just pass the file as is.
9- m_image->setSource(QUrl::fromLocalFile(selectedFilePath));
10+ if (qFuzzyCompare(UCUnits::instance().devicePixelRatio(), 1.0f)) {
11+ // No scaling. Just pass the file as is.
12+ m_image->setSource(QUrl::fromLocalFile(selectedFilePath));
13+ } else {
14+ m_image->setSource(QUrl("image://scaling/1/" + selectedFilePath));
15+ m_image->setSourceSize(m_image->sourceSize()); // explicitly set the source size as we know it
16+ }
17 } else {
18 // Prepend "image://scaling" for the image to be loaded by UCScalingImageProvider.
19- if (!m_source.path().endsWith(".sci")) {
20+ if (!m_source.path().endsWith(".sci")) { qDebug() << "scaled";
21 // Regular image file
22 m_image->setSource(QUrl("image://scaling/" + resolved));
23+ m_image->setSourceSize(m_image->sourceSize()); // explicitly set the source size as we know it
24 } else {
25 // .sci image file. Rewrite the .sci file into a temporary file.
26 bool rewritten = true;
27@@ -111,6 +117,7 @@
28 } else {
29 m_image->setSource(m_source);
30 }
31+ m_image->setSourceSize(m_image->sourceSize()); // explicitly set the source size as we know it
32 }
33 }
34 }
35
36=== modified file 'modules/Ubuntu/Components/plugin/ucubuntushape.cpp'
37--- modules/Ubuntu/Components/plugin/ucubuntushape.cpp 2015-04-16 11:47:10 +0000
38+++ modules/Ubuntu/Components/plugin/ucubuntushape.cpp 2015-04-16 11:47:11 +0000
39@@ -320,10 +320,7 @@
40 setFlag(ItemHasContents);
41 QObject::connect(&UCUnits::instance(), SIGNAL(gridUnitChanged()), this,
42 SLOT(_q_gridUnitChanged()));
43- const float gridUnit = UCUnits::instance().gridUnit();
44- setImplicitWidth(implicitWidthGU * gridUnit);
45- setImplicitHeight(implicitHeightGU * gridUnit);
46- update();
47+ _q_gridUnitChanged();
48 }
49
50 /*! \qmlproperty string UbuntuShape::radius
51@@ -968,9 +965,9 @@
52
53 void UCUbuntuShape::_q_gridUnitChanged()
54 {
55- const float gridUnit = UCUnits::instance().gridUnit();
56- setImplicitWidth(implicitWidthGU * gridUnit);
57- setImplicitHeight(implicitHeightGU * gridUnit);
58+ const float gridUnitInDevicePixels = UCUnits::instance().gridUnit() / UCUnits::instance().devicePixelRatio();
59+ setImplicitWidth(implicitWidthGU * gridUnitInDevicePixels);
60+ setImplicitHeight(implicitHeightGU * gridUnitInDevicePixels);
61 update();
62 }
63
64@@ -1063,6 +1060,7 @@
65 {
66 Q_UNUSED(data);
67
68+ const float dpr = UCUnits::instance().devicePixelRatio();
69 const QSizeF itemSize(width(), height());
70 if (itemSize.isEmpty()) {
71 delete oldNode;
72@@ -1101,12 +1099,12 @@
73 }
74 if (m_flags & DirtySourceTransform) {
75 if (m_flags & SourceApiSet) {
76- updateSourceTransform(itemSize.width(), itemSize.height(), m_sourceFillMode,
77+ updateSourceTransform(itemSize.width() * dpr, itemSize.height() * dpr, m_sourceFillMode,
78 m_sourceHorizontalAlignment, m_sourceVerticalAlignment,
79 sourceTexture->textureSize());
80 } else {
81 FillMode imageFillMode = (m_flags & Stretched) ? Stretch : PreserveAspectCrop;
82- updateSourceTransform(itemSize.width(), itemSize.height(), imageFillMode,
83+ updateSourceTransform(itemSize.width() * dpr, itemSize.height() * dpr, imageFillMode,
84 m_imageHorizontalAlignment, m_imageVerticalAlignment,
85 sourceTexture->textureSize());
86 }
87@@ -1133,7 +1131,7 @@
88 // scaled down accordingly. The shape was using a fixed image for the corner before switching to
89 // a distance field, since the corner wasn't taking the whole image (ending at ~80%) we need
90 // to take that into account when the size is scaled down.
91- float radius = UCUnits::instance().gridUnit()
92+ float radius = UCUnits::instance().gridUnit() / UCUnits::instance().devicePixelRatio()
93 * (m_radius == Small ? smallRadiusGU : mediumRadiusGU);
94 const float scaledDownRadius = qMin(itemSize.width(), itemSize.height()) * 0.5f * 0.8f;
95 if (radius > scaledDownRadius) {
96
97=== modified file 'modules/Ubuntu/Components/plugin/ucunits.cpp'
98--- modules/Ubuntu/Components/plugin/ucunits.cpp 2015-03-03 13:47:48 +0000
99+++ modules/Ubuntu/Components/plugin/ucunits.cpp 2015-04-16 11:47:11 +0000
100@@ -24,6 +24,9 @@
101 #include <QtCore/QDir>
102 #include <QtCore/QRegularExpression>
103 #include <QtCore/qmath.h>
104+#include <QtCore/QDebug>
105+#include <QtGui/QGuiApplication>
106+#include <QtGui/QScreen>
107
108 #define ENV_GRID_UNIT_PX "GRID_UNIT_PX"
109 #define DEFAULT_GRID_UNIT_PX 8
110@@ -65,7 +68,20 @@
111 UCUnits::UCUnits(QObject *parent) :
112 QObject(parent)
113 {
114- m_gridUnit = getenvFloat(ENV_GRID_UNIT_PX, DEFAULT_GRID_UNIT_PX);
115+ QScreen *screen = QGuiApplication::primaryScreen();
116+ if (screen) {
117+ m_devicePixelRatio = screen->devicePixelRatio();
118+ } else {
119+ m_devicePixelRatio = 1.0;
120+ }
121+
122+ // If GRID_UNIT_PX set, always use it. If not, 1GU := DEFAULT_GRID_UNIT_PX * m_devicePixelRatio
123+ if (qEnvironmentVariableIsSet(ENV_GRID_UNIT_PX)) {
124+ m_gridUnit = getenvFloat(ENV_GRID_UNIT_PX, DEFAULT_GRID_UNIT_PX);
125+ } else {
126+ m_gridUnit = DEFAULT_GRID_UNIT_PX * m_devicePixelRatio;
127+ }
128+ qDebug() << "Initial GU" << m_gridUnit;
129 }
130
131 /*!
132@@ -78,8 +94,8 @@
133 return m_gridUnit;
134 }
135
136-void UCUnits::setGridUnit(float gridUnit)
137-{
138+void UCUnits::setGridUnit(const float gridUnit)
139+{ qDebug() << "Override GU" << gridUnit;
140 m_gridUnit = gridUnit;
141 Q_EMIT gridUnitChanged();
142 }
143@@ -87,27 +103,35 @@
144 /*!
145 \qmlmethod real Units::dp(real value)
146
147- Returns the number of pixels \a value density independent pixels correspond to.
148+ Returns the number of device pixels \a value density independent pixels correspond to.
149 */
150-float UCUnits::dp(float value)
151+// Device pixels (and not actual pixels) because QML sizes in terms of device pixels.
152+float UCUnits::dp(const float value)
153 {
154 const float ratio = m_gridUnit / DEFAULT_GRID_UNIT_PX;
155 if (value <= 2.0) {
156 // for values under 2dp, return only multiples of the value
157- return qRound(value * qFloor(ratio));
158+ return qRound(value * qFloor(ratio)) / m_devicePixelRatio;
159 } else {
160- return qRound(value * ratio);
161+ return qRound(value * ratio) / m_devicePixelRatio;
162 }
163 }
164
165 /*!
166 \qmlmethod real Units::gu(real value)
167
168- Returns the number of pixels \a value grid units correspond to.
169+ Returns the number of device pixels \a value grid units correspond to.
170 */
171-float UCUnits::gu(float value)
172-{
173- return qRound(value * m_gridUnit);
174+// Device pixels (and not actual pixels) because QML sizes in terms of device pixels.
175+
176+float UCUnits::gu(const float value)
177+{
178+ return qRound(value * m_gridUnit) / m_devicePixelRatio;
179+}
180+
181+float UCUnits::devicePixelRatio() const
182+{
183+ return m_devicePixelRatio;
184 }
185
186 QString UCUnits::resolveResource(const QUrl& url)
187@@ -172,11 +196,12 @@
188
189 path = prefix + suffixForGridUnit(selectedGridUnitSuffix) + suffix;
190 float scaleFactor = m_gridUnit / selectedGridUnitSuffix;
191+ qDebug() << "P" << path << scaleFactor;
192 return QString::number(scaleFactor) + "/" + path;
193 }
194
195 path = prefix + suffix;
196- if (QFile::exists(path)) {
197+ if (QFile::exists(path)) { qDebug() << "P" << path;
198 return QString("1") + "/" + path;
199 }
200
201
202=== modified file 'modules/Ubuntu/Components/plugin/ucunits.h'
203--- modules/Ubuntu/Components/plugin/ucunits.h 2013-10-18 08:56:39 +0000
204+++ modules/Ubuntu/Components/plugin/ucunits.h 2015-04-16 11:47:11 +0000
205@@ -35,15 +35,16 @@
206 }
207
208 explicit UCUnits(QObject *parent = 0);
209- Q_INVOKABLE float dp(float value);
210- Q_INVOKABLE float gu(float value);
211+ Q_INVOKABLE float dp(const float value);
212+ Q_INVOKABLE float gu(const float value);
213 QString resolveResource(const QUrl& url);
214
215 // getters
216 float gridUnit();
217+ float devicePixelRatio() const;
218
219 // setters
220- void setGridUnit(float gridUnit);
221+ void setGridUnit(const float gridUnit);
222
223 Q_SIGNALS:
224 void gridUnitChanged();
225@@ -53,6 +54,7 @@
226 float gridUnitSuffixFromFileName(const QString &fileName);
227
228 private:
229+ float m_devicePixelRatio;
230 float m_gridUnit;
231 };
232
233
234=== modified file 'ubuntu-sdk.pro'
235--- ubuntu-sdk.pro 2015-03-12 14:13:58 +0000
236+++ ubuntu-sdk.pro 2015-04-16 11:47:11 +0000
237@@ -1,7 +1,7 @@
238 include( documentation/documentation.pri )
239
240 TEMPLATE = subdirs
241-SUBDIRS += modules/ubuntu-ui-toolkit.pro tests examples po
242+SUBDIRS += modules/ubuntu-ui-toolkit.pro #tests examples po
243
244 BUILD_PATH_CONTENTS="SRC_DIR=\"$$PWD\"" \
245 "BUILD_DIR=\"$$OUT_PWD\""

Subscribers

People subscribed via source and target branches

to status/vote changes: