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
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: