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

Proposed by Gerry Boland
Status: Merged
Approved by: Zsombor Egri
Approved revision: 1205
Merged at revision: 1605
Proposed branch: lp:~ubuntu-sdk-team/ubuntu-ui-toolkit/dpr
Merge into: lp:ubuntu-ui-toolkit/staging
Diff against target: 1044 lines (+747/-26)
22 files modified
debian/control (+5/-0)
src/Ubuntu/Components/plugin/ucqquickimageextension.cpp (+23/-3)
src/Ubuntu/Components/plugin/ucubuntushape.cpp (+17/-13)
src/Ubuntu/Components/plugin/ucunits.cpp (+46/-5)
src/Ubuntu/Components/plugin/ucunits.h (+1/-0)
tests/unit/add_makecheck.pri (+12/-1)
tests/unit/custom_qpa/README (+15/-0)
tests/unit/custom_qpa/custom.json (+3/-0)
tests/unit/custom_qpa/custom_qpa.pro (+15/-0)
tests/unit/custom_qpa/main.cpp (+54/-0)
tests/unit/custom_qpa/qcustombackingstore.cpp (+64/-0)
tests/unit/custom_qpa/qcustombackingstore.h (+55/-0)
tests/unit/custom_qpa/qcustomintegration.cpp (+112/-0)
tests/unit/custom_qpa/qcustomintegration.h (+74/-0)
tests/unit/runtest.sh (+2/-0)
tests/unit/tst_units/dpr1/dpr1.pro (+3/-0)
tests/unit/tst_units/dpr2/dpr2.pro (+3/-0)
tests/unit/tst_units/dpr2/tst_units_dpr2.cpp (+143/-0)
tests/unit/tst_units/dpr3/dpr3.pro (+3/-0)
tests/unit/tst_units/dpr3/tst_units_dpr3.cpp (+88/-0)
tests/unit/tst_units/tst_units.pro (+6/-3)
tests/unit/unit.pro (+3/-1)
To merge this branch: bzr merge lp:~ubuntu-sdk-team/ubuntu-ui-toolkit/dpr
Reviewer Review Type Date Requested Status
Zsombor Egri Approve
PS Jenkins bot continuous-integration Approve
Loïc Molinari (community) Approve
Gerry Boland (community) Needs Information
Review via email: mp+256470@code.launchpad.net

This proposal supersedes a proposal from 2015-04-16.

Commit message

Compensate for Qt's device pixel ratio multiplier

Description of the change

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=16
then a box of height units.gu(1) will be drawn 32 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=16
QT_DEVICE_PIXEL_RATIO=2 GRID_UNIT_PX=16

Some visual inconsistencies at small GU values are due to exact font rendering sizes and some rounding issues causing off-by-one positioning errors. QT_DEVICE_PIXEL_RATIO=2 GRID_UNIT_PX=8 is not a realistic choice however, likely would only switch to DPR2 when GU>=16.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Gerry Boland (gerboland) wrote :

Ok, think this is ready for review. I added tests where I could, but would appreciate feedback on how I could test more.

Revision history for this message
Gerry Boland (gerboland) wrote :

+++ modules/Ubuntu/Components/plugin/ucunits.h
+ float devicePixelRatio() const;
should I worry about ABI breaking?

review: Needs Information
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Loïc Molinari (loic.molinari) wrote :

Just a quick comment before going deeper in the review, the ProgressBar is broken because ucubuntushapeoverlay.cpp hasn't been modified.

review: Needs Fixing
Revision history for this message
Gerry Boland (gerboland) wrote :

Thanks for the initial look, no idea how I missed that overlay issue, it's fixed now

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Loïc Molinari (loic.molinari) wrote :

> +++ modules/Ubuntu/Components/plugin/ucunits.h
> + float devicePixelRatio() const;
> should I worry about ABI breaking?

No worries, it's not an ABI break. And actually we don't care about ABI breaks since we don't export the shared object as a lib.

Revision history for this message
Loïc Molinari (loic.molinari) wrote :

> > +++ modules/Ubuntu/Components/plugin/ucunits.h
> > + float devicePixelRatio() const;
> > should I worry about ABI breaking?
>
> No worries, it's not an ABI break. And actually we don't care about ABI
> breaks since we don't export the shared object as a lib.

(Thinking about it the added floating-point value in the class would be an ABI break if we'd expose the lib)

Revision history for this message
Loïc Molinari (loic.molinari) wrote :
Download full text (3.7 KiB)

Good stuff. Here is a bunch of questions and remarks.

1)
In the shape, storing the radius as device-independent pixel like that

- float radius = UCUnits::instance().gridUnit() * (m_radius == Small ? smallRadiusGU : mediumRadiusGU);
- const float scaledDownRadius = qMin(itemSize.width(), itemSize.height()) * dpr * 0.5f * 0.8f;
+ float radius = UCUnits::instance().gu((m_radius == Small ? smallRadiusGU : mediumRadiusGU));
+ const float scaledDownRadius = qMin(itemSize.width(), itemSize.height()) * 0.5f * 0.8f;

would remove the need to multiply the item size by the dpr for the shape coordinates attributes in updateVertices() (for both UbuntuShape and UbuntuShapeOverlay). That would require to do change updateMaterial() though, but in a less intrusive way IMO:

@@ -1217,16 +1218,18 @@
         materialData->sourceOpacity = 0;
     }

+ const float physicalRadius = UCUnits::instance().devicePixelRatio() * radius;
+
     // Mapping of radius size range from [0, 4] to [0, 1] with clamping, plus quantization.
     const float start = 0.0f + radiusSizeOffset;
     const float end = 4.0f + radiusSizeOffset;
     materialData->distanceAAFactor = qMin(
- (radius / (end - start)) - (start / (end - start)), 1.0f) * 255.0f;
+ (physicalRadius / (end - start)) - (start / (end - start)), 1.0f) * 255.0f;

     // When the radius is equal to radiusSizeOffset (which means radius size is 0), no aspect is
     // flagged so that a dedicated (statically flow controlled) shaved off shader can be used for
     // optimal performance.
- if (radius > radiusSizeOffset) {
+ if (physicalRadius > radiusSizeOffset) {
         const quint8 aspectFlags[] = {
             ShapeMaterial::Data::Flat, ShapeMaterial::Data::Inset,
             ShapeMaterial::Data::Inset | ShapeMaterial::Data::Pressed

2) The previous change would allow to move the devicePixelRatio retrieval in updateGeometryNode() to the "if (m_flags & DirtySourceTransform) {" scope.

3)
- Q_INVOKABLE float dp(float value);
- Q_INVOKABLE float gu(float value);
+ Q_INVOKABLE float dp(const float value);
+ Q_INVOKABLE float gu(const float value);

Using const for value parameters (not for reference or pointer parameters) isn't a common practice in the toolkit (neither in Qt AFAIK). Is there a particular reason for it?

4) Wouldn't it be better (faster) to inline UCUnits::devicePixelRatio() definition in the header?

5) Talking about UCUnits::devicePixelRatio(), why do we have to expose it instead of using QGuiApplication::devicePixelRation() or QWindow::devicePixelRatio() directly? Same question for the "manual" retrieval of QT_DEVICE_PIXEL_RATIO in UCUnits constructor.

6) UCUnits::gu() and UCUnits:dp() returns "qRound(value * m_gridUnit) / m_devicePixelRatio", I'm wondering if the division should be applied before the rounding?

7) It took me some time to figure out the logic because I didn't realize we had to support QtWidgets as well. I think we'd better explain the whole decision somewhere in the project, either in the README or in the UCUnits module. I'd tend to go for a good explanation in the ucunits.cpp module documentation maybe adding toolkit implementation...

Read more...

review: Needs Fixing
Revision history for this message
Gerry Boland (gerboland) wrote :
Download full text (3.7 KiB)

> Good stuff. Here is a bunch of questions and remarks.
>
> 1)
> In the shape, storing the radius as device-independent pixel like that
>
> - float radius = UCUnits::instance().gridUnit() * (m_radius == Small ?
> smallRadiusGU : mediumRadiusGU);
> - const float scaledDownRadius = qMin(itemSize.width(), itemSize.height())
> * dpr * 0.5f * 0.8f;
> + float radius = UCUnits::instance().gu((m_radius == Small ? smallRadiusGU
> : mediumRadiusGU));
> + const float scaledDownRadius = qMin(itemSize.width(), itemSize.height())
> * 0.5f * 0.8f;
>
> would remove the need to multiply the item size by the dpr for the shape
> coordinates attributes in updateVertices() (for both UbuntuShape and
> UbuntuShapeOverlay). That would require to do change updateMaterial() though,
> but in a less intrusive way IMO:
<snip>
Done!

> 2) The previous change would allow to move the devicePixelRatio retrieval in
> updateGeometryNode() to the "if (m_flags & DirtySourceTransform) {" scope.
Done

> 3)
> - Q_INVOKABLE float dp(float value);
> - Q_INVOKABLE float gu(float value);
> + Q_INVOKABLE float dp(const float value);
> + Q_INVOKABLE float gu(const float value);
>
> Using const for value parameters (not for reference or pointer parameters)
> isn't a common practice in the toolkit (neither in Qt AFAIK). Is there a
> particular reason for it?
I had thought compiler could optimize a little better with this, but I'm told it's of no use. Reverted.

> 4) Wouldn't it be better (faster) to inline UCUnits::devicePixelRatio()
> definition in the header?
>
> 5) Talking about UCUnits::devicePixelRatio(), why do we have to expose it
> instead of using QGuiApplication::devicePixelRation() or
> QWindow::devicePixelRatio() directly? Same question for the "manual" retrieval
> of QT_DEVICE_PIXEL_RATIO in UCUnits constructor.

Yeah I got rid of this. I had mainly added it to UCUnits to ease mocking it for testing. Instead I've added a custom minimal QPA plugin to mock the value of devicePixelRatio(). So UCUnits API has be left unchanged by this MR.

>
> 6) UCUnits::gu() and UCUnits:dp() returns "qRound(value * m_gridUnit) /
> m_devicePixelRatio", I'm wondering if the division should be applied before
> the rounding?

I left the division after the rounding as Qt will take this value, multiply it by devicePixelRatio to calculate the physical pixels. I.e.
physicalPixels = [qRound(value * m_gridUnit) / m_devicePixelRatio] * m_devicePixelRatio
should be more correct than
physicalPixels = qRound(value * m_gridUnit / m_devicePixelRatio) * m_devicePixelRatio

> 7) It took me some time to figure out the logic because I didn't realize we
> had to support QtWidgets as well. I think we'd better explain the whole
> decision somewhere in the project, either in the README or in the UCUnits
> module. I'd tend to go for a good explanation in the ucunits.cpp module
> documentation maybe adding toolkit implementation details in there in a "non-
> exposed" comment if needed. We should also agree on a better naming for the
> units, currently there are grid units, device pixels, value density
> independent pixels, actual pixels, physical pixels, etc, it's very confusing.
> I...

Read more...

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
1195. By Gerry Boland

Add missing build dependencies

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
1196. By Gerry Boland

Bump version

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
1197. By Gerry Boland

Merge staging and fix conflicts

1198. By Gerry Boland

Revert rev 1196

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
1199. By Gerry Boland

Merge staging, fix a conflict

1200. By Gerry Boland

Undo changes to paths for gallery launcher

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
1201. By Gerry Boland

Merge staging

Revision history for this message
Zsombor Egri (zsombi) wrote :

Small fixes, and we're good.

review: Needs Fixing
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Loïc Molinari (loic.molinari) wrote :

I guess there's a merge problem, m_relativeRadius is defined two times in UCUbuntuShape initialisation list. Apart from that, everything looks good to me now.

Thanks for the changes and sorry for the delay to take a look back at that...

review: Approve
1202. By Gerry Boland

Fix build fail - variable inited twice

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
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

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Zsombor Egri (zsombi) wrote :

Good to go now! Thanks allot!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'debian/control'
2--- debian/control 2015-07-10 05:40:21 +0000
3+++ debian/control 2015-08-12 11:28:41 +0000
4@@ -45,6 +45,11 @@
5 suru-icon-theme,
6 uuid-runtime,
7 python3-sphinx,
8+ libfontconfig1-dev,
9+ libfreetype6-dev,
10+ libmtdev-dev,
11+ libudev-dev,
12+ libxrender-dev
13 Standards-Version: 3.9.4
14 Homepage: https://launchpad.net/ubuntu-ui-toolkit
15 # If you aren't a member of ~ubuntu-sdk-team but need to upload packaging
16
17=== modified file 'src/Ubuntu/Components/plugin/ucqquickimageextension.cpp'
18--- src/Ubuntu/Components/plugin/ucqquickimageextension.cpp 2014-11-24 13:14:35 +0000
19+++ src/Ubuntu/Components/plugin/ucqquickimageextension.cpp 2015-08-12 11:28:41 +0000
20@@ -19,6 +19,7 @@
21 #include <QtCore/QFile>
22 #include <QtCore/QFileInfo>
23 #include <QtCore/QDir>
24+#include <QtGui/QGuiApplication>
25 #include <QtQuick/private/qquickimagebase_p.h>
26
27 #include "ucqquickimageextension.h"
28@@ -78,8 +79,18 @@
29 QString selectedFilePath = resolved.mid(separatorPosition+1);
30
31 if (scaleFactor == "1") {
32- // No scaling. Just pass the file as is.
33- m_image->setSource(QUrl::fromLocalFile(selectedFilePath));
34+ if (qFuzzyCompare(qGuiApp->devicePixelRatio(), (qreal)1.0)
35+ || selectedFilePath.endsWith(".svg") || selectedFilePath.endsWith(".svgz")) {
36+ // No scaling necessary. Just pass the file as is.
37+ m_image->setSource(QUrl::fromLocalFile(selectedFilePath));
38+ } else {
39+ // Need to scale the pixel-based image to suit the devicePixelRatio setting ourselves.
40+ // If we let Qt do it, Qt will not choose the UITK-supported "@gu" scaled images.
41+ m_image->setSource(QUrl("image://scaling/1/" + selectedFilePath));
42+ // explicitly set the source size in the QQuickImageBase, this persuades it that the
43+ // supplied image is suitable for the current devicePixelRatio.
44+ m_image->setSourceSize(m_image->sourceSize());
45+ }
46 } else {
47 // Prepend "image://scaling" for the image to be loaded by UCScalingImageProvider.
48 if (!m_source.path().endsWith(".sci")) {
49@@ -100,7 +111,13 @@
50 rewrittenSciFile->setFileTemplate(QDir::tempPath() + QDir::separator() + "XXXXXX.sci");
51 rewrittenSciFile->open();
52 QTextStream output(rewrittenSciFile);
53- rewritten = rewriteSciFile(selectedFilePath, scaleFactor, output);
54+
55+ if (qFuzzyCompare(qGuiApp->devicePixelRatio(), (qreal)1.0)) {
56+ rewritten = rewriteSciFile(selectedFilePath, scaleFactor, output);
57+ } else {
58+ QString scaleFactorInDevicePixels = QString::number(scaleFactor.toFloat() / qGuiApp->devicePixelRatio());
59+ rewritten = rewriteSciFile(selectedFilePath, scaleFactorInDevicePixels, output);
60+ }
61 rewrittenSciFile->close();
62
63 s_rewrittenSciFiles.insert(m_source, QSharedPointer<QTemporaryFile>(rewrittenSciFile));
64@@ -112,6 +129,9 @@
65 m_image->setSource(m_source);
66 }
67 }
68+ // explicitly set the source size in the QQuickImageBase, this persuades it that the
69+ // supplied image is suitable for the current devicePixelRatio.
70+ m_image->setSourceSize(m_image->sourceSize());
71 }
72 }
73
74
75=== modified file 'src/Ubuntu/Components/plugin/ucubuntushape.cpp'
76--- src/Ubuntu/Components/plugin/ucubuntushape.cpp 2015-08-06 13:16:24 +0000
77+++ src/Ubuntu/Components/plugin/ucubuntushape.cpp 2015-08-12 11:28:41 +0000
78@@ -308,10 +308,7 @@
79 setFlag(ItemHasContents);
80 QObject::connect(&UCUnits::instance(), SIGNAL(gridUnitChanged()), this,
81 SLOT(_q_gridUnitChanged()));
82- const float gridUnit = UCUnits::instance().gridUnit();
83- setImplicitWidth(implicitWidthGU * gridUnit);
84- setImplicitHeight(implicitHeightGU * gridUnit);
85- update();
86+ _q_gridUnitChanged();
87 }
88
89 /*! \qmlproperty string UbuntuShape::radius
90@@ -998,9 +995,9 @@
91
92 void UCUbuntuShape::_q_gridUnitChanged()
93 {
94- const float gridUnit = UCUnits::instance().gridUnit();
95- setImplicitWidth(implicitWidthGU * gridUnit);
96- setImplicitHeight(implicitHeightGU * gridUnit);
97+ const float gridUnitInDevicePixels = UCUnits::instance().gridUnit() / qGuiApp->devicePixelRatio();
98+ setImplicitWidth(implicitWidthGU * gridUnitInDevicePixels);
99+ setImplicitHeight(implicitHeightGU * gridUnitInDevicePixels);
100 update();
101 }
102
103@@ -1162,13 +1159,15 @@
104 sourceTextureRect = sourceTexture->normalizedTextureSubRect();
105 }
106 if (m_flags & DirtySourceTransform) {
107+ const float dpr = qGuiApp->devicePixelRatio();
108+
109 if (m_flags & SourceApiSet) {
110- updateSourceTransform(itemSize.width(), itemSize.height(), m_sourceFillMode,
111+ updateSourceTransform(itemSize.width() * dpr, itemSize.height() * dpr, m_sourceFillMode,
112 m_sourceHorizontalAlignment, m_sourceVerticalAlignment,
113 sourceTexture->textureSize());
114 } else {
115 FillMode imageFillMode = (m_flags & Stretched) ? Stretch : PreserveAspectCrop;
116- updateSourceTransform(itemSize.width(), itemSize.height(), imageFillMode,
117+ updateSourceTransform(itemSize.width() * dpr, itemSize.height() * dpr, imageFillMode,
118 m_imageHorizontalAlignment, m_imageVerticalAlignment,
119 sourceTexture->textureSize());
120 }
121@@ -1198,13 +1197,15 @@
122 // accordingly. The shape was using a fixed image for the corner before switching to a
123 // distance field, since the corner wasn't taking the whole image (ending at ~80%) we need
124 // to take that into account when the size is scaled down.
125- radius = UCUnits::instance().gridUnit() * radiusGuMap[m_radius];
126+ radius = UCUnits::instance().gridUnit() * radiusGuMap[m_radius]
127+ / qGuiApp->devicePixelRatio();
128 const float scaledDownRadius = qMin(itemSize.width(), itemSize.height()) * 0.5f * 0.8f;
129 if (radius > scaledDownRadius) {
130 radius = scaledDownRadius;
131 }
132 } else {
133- radius = qMin(itemSize.width(), itemSize.height()) * 0.5f * (m_relativeRadius * 0.01f);
134+ radius = qMin(itemSize.width(), itemSize.height()) * 0.5f * (m_relativeRadius * 0.01f)
135+ / qGuiApp->devicePixelRatio();
136 }
137
138 updateMaterial(node, radius, shapeTextureId, sourceTexture && m_sourceOpacity);
139@@ -1284,16 +1285,19 @@
140 materialData->sourceOpacity = 0;
141 }
142
143+ const float physicalRadius = radius * qGuiApp->devicePixelRatio();
144+
145 // Mapping of radius size range from [0, 4] to [0, 1] with clamping, plus quantization.
146 const float start = 0.0f + radiusSizeOffset;
147 const float end = 4.0f + radiusSizeOffset;
148+
149 materialData->distanceAAFactor =
150- qMin((radius / (end - start)) - (start / (end - start)), 1.0f) * 255.0f;
151+ qMin((physicalRadius / (end - start)) - (start / (end - start)), 1.0f) * 255.0f;
152
153 // When the radius is equal to radiusSizeOffset (which means radius size is 0), no aspect is
154 // flagged so that a dedicated (statically flow controlled) shaved off shader can be used for
155 // optimal performance.
156- if (radius > radiusSizeOffset) {
157+ if (physicalRadius > radiusSizeOffset) {
158 const quint8 aspectFlags[] = {
159 ShapeMaterial::Data::Flat, ShapeMaterial::Data::Inset, ShapeMaterial::Data::DropShadow,
160 ShapeMaterial::Data::Inset | ShapeMaterial::Data::Pressed
161
162=== modified file 'src/Ubuntu/Components/plugin/ucunits.cpp'
163--- src/Ubuntu/Components/plugin/ucunits.cpp 2015-03-03 13:47:48 +0000
164+++ src/Ubuntu/Components/plugin/ucunits.cpp 2015-08-12 11:28:41 +0000
165@@ -24,6 +24,8 @@
166 #include <QtCore/QDir>
167 #include <QtCore/QRegularExpression>
168 #include <QtCore/qmath.h>
169+#include <QtGui/QGuiApplication>
170+#include <QtGui/QScreen>
171
172 #define ENV_GRID_UNIT_PX "GRID_UNIT_PX"
173 #define DEFAULT_GRID_UNIT_PX 8
174@@ -62,10 +64,46 @@
175
176 \sa {Resolution Independence}
177 */
178+
179+/*
180+ * Note on the interaction between GRID_UNIT_PX and QT_DEVICE_PIXEL_RATIO
181+ *
182+ * In Qt5.4 there is a single means to scale the UI: the QT_DEVICE_PIXEL_RATIO environment
183+ * variable. This accepts only integer values, thus allowing a x2 or x3 scaling of any
184+ * Qt-based UI, that includes QWidget as well as any QML UI.
185+ *
186+ * Setting QT_DEVICE_PIXEL_RATIO=2 implies one density-independent pixel corresponds to 2
187+ * physical pixels. Developers describe their UI in terms of density-independent pixels.
188+ * Qt scales accordingly.
189+ *
190+ * The Ubuntu UI Toolkit has solved the scaling problem with the GRID_UNIT_PX variable.
191+ * It offers more flexibility, but only scales QML applications written to use the UITK
192+ * (since it uses this Units class) as it is built on top of QML.
193+ *
194+ * There are additional areas in Qt where QT_DEVICE_PIXEL_RATIO causes correct scaling which
195+ * GRID_UNIT_PX cannot, for example:
196+ * 1. cacheBuffer for ListView/GridViews - specified in density-independent pixels
197+ * 2. gesture recognition matches what is on screen better, as it is density-independent
198+ * pixel aware
199+ *
200+ * In order to get the best of both worlds, Ubuntu will set both GRID_UNIT_PX and
201+ * QT_DEVICE_PIXEL_RATIO. Thus all Qt apps will scale reasonably well, with UITK-based apps
202+ * scaling perfectly for any desired scale (i.e. non-integer scales).
203+ *
204+ * However UITK developers can just use this Units class as usual, and will be almost totally
205+ * isolated from Qt's own scaling concept.
206+ */
207+
208 UCUnits::UCUnits(QObject *parent) :
209- QObject(parent)
210+ QObject(parent),
211+ m_devicePixelRatio(qGuiApp->devicePixelRatio())
212 {
213- m_gridUnit = getenvFloat(ENV_GRID_UNIT_PX, DEFAULT_GRID_UNIT_PX);
214+ // If GRID_UNIT_PX set, always use it. If not, 1GU := DEFAULT_GRID_UNIT_PX * m_devicePixelRatio
215+ if (qEnvironmentVariableIsSet(ENV_GRID_UNIT_PX)) {
216+ m_gridUnit = getenvFloat(ENV_GRID_UNIT_PX, DEFAULT_GRID_UNIT_PX);
217+ } else {
218+ m_gridUnit = DEFAULT_GRID_UNIT_PX * m_devicePixelRatio;
219+ }
220 }
221
222 /*!
223@@ -89,14 +127,15 @@
224
225 Returns the number of pixels \a value density independent pixels correspond to.
226 */
227+// Density-independent pixels (and not physical pixels) because Qt sizes in terms of density-independent pixels.
228 float UCUnits::dp(float value)
229 {
230 const float ratio = m_gridUnit / DEFAULT_GRID_UNIT_PX;
231 if (value <= 2.0) {
232 // for values under 2dp, return only multiples of the value
233- return qRound(value * qFloor(ratio));
234+ return qRound(value * qFloor(ratio)) / m_devicePixelRatio;
235 } else {
236- return qRound(value * ratio);
237+ return qRound(value * ratio) / m_devicePixelRatio;
238 }
239 }
240
241@@ -105,9 +144,11 @@
242
243 Returns the number of pixels \a value grid units correspond to.
244 */
245+// Density-independent pixels (and not physical pixels) because Qt sizes in terms of density-independent pixels.
246+
247 float UCUnits::gu(float value)
248 {
249- return qRound(value * m_gridUnit);
250+ return qRound(value * m_gridUnit) / m_devicePixelRatio;
251 }
252
253 QString UCUnits::resolveResource(const QUrl& url)
254
255=== modified file 'src/Ubuntu/Components/plugin/ucunits.h'
256--- src/Ubuntu/Components/plugin/ucunits.h 2013-10-18 08:56:39 +0000
257+++ src/Ubuntu/Components/plugin/ucunits.h 2015-08-12 11:28:41 +0000
258@@ -53,6 +53,7 @@
259 float gridUnitSuffixFromFileName(const QString &fileName);
260
261 private:
262+ float m_devicePixelRatio;
263 float m_gridUnit;
264 };
265
266
267=== modified file 'tests/unit/add_makecheck.pri'
268--- tests/unit/add_makecheck.pri 2015-05-19 07:55:27 +0000
269+++ tests/unit/add_makecheck.pri 2015-08-12 11:28:41 +0000
270@@ -5,4 +5,15 @@
271 check.target = check
272 check.commands += cd $$_PRO_FILE_PWD_;
273 check.commands += env LD_LIBRARY_PATH=$${ROOT_BUILD_DIR}/qml/Ubuntu/Components:$${ROOT_BUILD_DIR}/qml/Ubuntu/Layouts:$${ROOT_BUILD_DIR}/qml/Ubuntu/PerformanceMetrics:$${ROOT_BUILD_DIR}/qml/Ubuntu/Test UITK_TEST_KEEP_RUNNING=1
274-check.commands += '$${ROOT_SOURCE_DIR}/tests/unit/runtest.sh "$$shadowed($$_PRO_FILE_PWD_)/$${TARGET}" "$$shadowed($$_PRO_FILE_PWD_)/$${TARGET}" minimal';
275+
276+TEST_COMMAND = '$${ROOT_SOURCE_DIR}/tests/unit/runtest.sh "$$shadowed($$_PRO_FILE_PWD_)/$${TARGET}" "$$shadowed($$_PRO_FILE_PWD_)/$${TARGET}"'
277+
278+message($$TEST_COMMAND)
279+
280+# if "CONFIG += custom_qpa" is set, use our custom QPA plugin for the test
281+custom_qpa {
282+ check.commands += env QT_QPA_PLATFORM_PLUGIN_PATH=$${ROOT_BUILD_DIR}/tests/unit/custom_qpa
283+ check.commands += '$$TEST_COMMAND custom';
284+} else {
285+ check.commands += '$$TEST_COMMAND minimal';
286+}
287
288=== added directory 'tests/unit/custom_qpa'
289=== added file 'tests/unit/custom_qpa/README'
290--- tests/unit/custom_qpa/README 1970-01-01 00:00:00 +0000
291+++ tests/unit/custom_qpa/README 2015-08-12 11:28:41 +0000
292@@ -0,0 +1,15 @@
293+In order to correctly test Qt's Device Pixel Ratio system in a
294+unit test, one needs to have the QPA plugin for the platform
295+support reading the DEVICE_PIXEL_RATIO environment variable.
296+
297+These unit tests use the "minimal" QPA plugin, which
298+unfortunately does not support that variable.
299+
300+The contents of this directory is a near-complete duplicate of
301+"minimal" QPA plugin source from Qt, with added support for the
302+DEVICE_PIXEL_RATIO environment variable.
303+
304+One can use this plugin as follows:
305+
306+DEVICE_PIXEL_RATIO=2 QT_QPA_PLATFORM_PLUGIN_PATH=$PWD \
307+ QT_QPA_PLATFORM=custom qmlscene ~/tmp.qml
308
309=== added file 'tests/unit/custom_qpa/custom.json'
310--- tests/unit/custom_qpa/custom.json 1970-01-01 00:00:00 +0000
311+++ tests/unit/custom_qpa/custom.json 2015-08-12 11:28:41 +0000
312@@ -0,0 +1,3 @@
313+{
314+ "Keys": [ "custom" ]
315+}
316
317=== added file 'tests/unit/custom_qpa/custom_qpa.pro'
318--- tests/unit/custom_qpa/custom_qpa.pro 1970-01-01 00:00:00 +0000
319+++ tests/unit/custom_qpa/custom_qpa.pro 2015-08-12 11:28:41 +0000
320@@ -0,0 +1,15 @@
321+TARGET = qcustom
322+TEMPLATE = lib
323+
324+CONFIG += plugin no_keywords c++11
325+
326+QT -= gui
327+QT += core-private gui-private platformsupport-private
328+
329+SOURCES = main.cpp \
330+ qcustomintegration.cpp \
331+ qcustombackingstore.cpp
332+HEADERS = qcustomintegration.h \
333+ qcustombackingstore.h
334+
335+OTHER_FILES += custom.json
336
337=== added file 'tests/unit/custom_qpa/main.cpp'
338--- tests/unit/custom_qpa/main.cpp 1970-01-01 00:00:00 +0000
339+++ tests/unit/custom_qpa/main.cpp 2015-08-12 11:28:41 +0000
340@@ -0,0 +1,54 @@
341+/****************************************************************************
342+**
343+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
344+** Contact: http://www.qt-project.org/legal
345+**
346+** This file is part of the plugins of the Qt Toolkit.
347+**
348+** $QT_BEGIN_LICENSE:LGPL21$
349+** Commercial License Usage
350+** Licensees holding valid commercial Qt licenses may use this file in
351+** accordance with the commercial license agreement provided with the
352+** Software or, alternatively, in accordance with the terms contained in
353+** a written agreement between you and Digia. For licensing terms and
354+** conditions see http://qt.digia.com/licensing. For further information
355+** use the contact form at http://qt.digia.com/contact-us.
356+**
357+** GNU Lesser General Public License Usage
358+** Alternatively, this file may be used under the terms of the GNU Lesser
359+** General Public License version 2.1 or version 3 as published by the Free
360+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
361+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
362+** following information to ensure the GNU Lesser General Public License
363+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
364+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
365+**
366+** In addition, as a special exception, Digia gives you certain additional
367+** rights. These rights are described in the Digia Qt LGPL Exception
368+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
369+**
370+** $QT_END_LICENSE$
371+**
372+****************************************************************************/
373+
374+
375+#include <qpa/qplatformintegrationplugin.h>
376+#include "qcustomintegration.h"
377+
378+class QCustomIntegrationPlugin : public QPlatformIntegrationPlugin
379+{
380+ Q_OBJECT
381+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.2" FILE "custom.json")
382+public:
383+ QPlatformIntegration *create(const QString&, const QStringList&);
384+};
385+
386+QPlatformIntegration *QCustomIntegrationPlugin::create(const QString& system, const QStringList& /*paramList*/)
387+{
388+ if (!system.compare(QLatin1String("custom"), Qt::CaseInsensitive))
389+ return new QCustomIntegration();
390+
391+ return 0;
392+}
393+
394+#include "main.moc"
395
396=== added file 'tests/unit/custom_qpa/qcustombackingstore.cpp'
397--- tests/unit/custom_qpa/qcustombackingstore.cpp 1970-01-01 00:00:00 +0000
398+++ tests/unit/custom_qpa/qcustombackingstore.cpp 2015-08-12 11:28:41 +0000
399@@ -0,0 +1,64 @@
400+/****************************************************************************
401+**
402+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
403+** Contact: http://www.qt-project.org/legal
404+**
405+** This file is part of the plugins of the Qt Toolkit.
406+**
407+** $QT_BEGIN_LICENSE:LGPL21$
408+** Commercial License Usage
409+** Licensees holding valid commercial Qt licenses may use this file in
410+** accordance with the commercial license agreement provided with the
411+** Software or, alternatively, in accordance with the terms contained in
412+** a written agreement between you and Digia. For licensing terms and
413+** conditions see http://qt.digia.com/licensing. For further information
414+** use the contact form at http://qt.digia.com/contact-us.
415+**
416+** GNU Lesser General Public License Usage
417+** Alternatively, this file may be used under the terms of the GNU Lesser
418+** General Public License version 2.1 or version 3 as published by the Free
419+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
420+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
421+** following information to ensure the GNU Lesser General Public License
422+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
423+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
424+**
425+** In addition, as a special exception, Digia gives you certain additional
426+** rights. These rights are described in the Digia Qt LGPL Exception
427+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
428+**
429+** $QT_END_LICENSE$
430+**
431+****************************************************************************/
432+
433+
434+#include "qcustombackingstore.h"
435+#include "qcustomintegration.h"
436+#include "qscreen.h"
437+#include <qpa/qplatformscreen.h>
438+#include <private/qguiapplication_p.h>
439+
440+
441+QCustomBackingStore::QCustomBackingStore(QWindow *window)
442+ : QPlatformBackingStore(window)
443+{
444+}
445+
446+QPaintDevice *QCustomBackingStore::paintDevice()
447+{
448+ return &mImage;
449+}
450+
451+void QCustomBackingStore::flush(QWindow *window, const QRegion &region, const QPoint &offset)
452+{
453+ Q_UNUSED(window);
454+ Q_UNUSED(region);
455+ Q_UNUSED(offset);
456+}
457+
458+void QCustomBackingStore::resize(const QSize &size, const QRegion &)
459+{
460+ QImage::Format format = QGuiApplication::primaryScreen()->handle()->format();
461+ if (mImage.size() != size)
462+ mImage = QImage(size, format);
463+}
464
465=== added file 'tests/unit/custom_qpa/qcustombackingstore.h'
466--- tests/unit/custom_qpa/qcustombackingstore.h 1970-01-01 00:00:00 +0000
467+++ tests/unit/custom_qpa/qcustombackingstore.h 2015-08-12 11:28:41 +0000
468@@ -0,0 +1,55 @@
469+/****************************************************************************
470+**
471+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
472+** Contact: http://www.qt-project.org/legal
473+**
474+** This file is part of the plugins of the Qt Toolkit.
475+**
476+** $QT_BEGIN_LICENSE:LGPL21$
477+** Commercial License Usage
478+** Licensees holding valid commercial Qt licenses may use this file in
479+** accordance with the commercial license agreement provided with the
480+** Software or, alternatively, in accordance with the terms contained in
481+** a written agreement between you and Digia. For licensing terms and
482+** conditions see http://qt.digia.com/licensing. For further information
483+** use the contact form at http://qt.digia.com/contact-us.
484+**
485+** GNU Lesser General Public License Usage
486+** Alternatively, this file may be used under the terms of the GNU Lesser
487+** General Public License version 2.1 or version 3 as published by the Free
488+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
489+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
490+** following information to ensure the GNU Lesser General Public License
491+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
492+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
493+**
494+** In addition, as a special exception, Digia gives you certain additional
495+** rights. These rights are described in the Digia Qt LGPL Exception
496+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
497+**
498+** $QT_END_LICENSE$
499+**
500+****************************************************************************/
501+
502+#ifndef QBACKINGSTORE_MINIMAL_H
503+#define QBACKINGSTORE_MINIMAL_H
504+
505+#include <qpa/qplatformbackingstore.h>
506+#include <qpa/qplatformwindow.h>
507+#include <QtGui/QImage>
508+
509+class QCustomBackingStore : public QPlatformBackingStore
510+{
511+public:
512+ QCustomBackingStore(QWindow *window);
513+ ~QCustomBackingStore() = default;
514+
515+ QPaintDevice *paintDevice();
516+ void flush(QWindow *window, const QRegion &region, const QPoint &offset);
517+ void resize(const QSize &size, const QRegion &staticContents);
518+
519+private:
520+ QImage mImage;
521+};
522+
523+#endif
524
525=== added file 'tests/unit/custom_qpa/qcustomintegration.cpp'
526--- tests/unit/custom_qpa/qcustomintegration.cpp 1970-01-01 00:00:00 +0000
527+++ tests/unit/custom_qpa/qcustomintegration.cpp 2015-08-12 11:28:41 +0000
528@@ -0,0 +1,112 @@
529+/****************************************************************************
530+**
531+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
532+** Contact: http://www.qt-project.org/legal
533+**
534+** This file is part of the plugins of the Qt Toolkit.
535+**
536+** $QT_BEGIN_LICENSE:LGPL21$
537+** Commercial License Usage
538+** Licensees holding valid commercial Qt licenses may use this file in
539+** accordance with the commercial license agreement provided with the
540+** Software or, alternatively, in accordance with the terms contained in
541+** a written agreement between you and Digia. For licensing terms and
542+** conditions see http://qt.digia.com/licensing. For further information
543+** use the contact form at http://qt.digia.com/contact-us.
544+**
545+** GNU Lesser General Public License Usage
546+** Alternatively, this file may be used under the terms of the GNU Lesser
547+** General Public License version 2.1 or version 3 as published by the Free
548+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
549+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
550+** following information to ensure the GNU Lesser General Public License
551+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
552+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
553+**
554+** In addition, as a special exception, Digia gives you certain additional
555+** rights. These rights are described in the Digia Qt LGPL Exception
556+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
557+**
558+** $QT_END_LICENSE$
559+**
560+****************************************************************************/
561+
562+#include "qcustomintegration.h"
563+#include "qcustombackingstore.h"
564+
565+#include <QtGui/private/qguiapplication_p.h>
566+#include <qpa/qplatformwindow.h>
567+#include <qpa/qplatformfontdatabase.h>
568+
569+#include <QtPlatformSupport/private/qgenericunixeventdispatcher_p.h>
570+
571+static const char devicePixelRatioEnvironmentVariable[] = "QT_DEVICE_PIXEL_RATIO";
572+
573+QCustomScreen::QCustomScreen()
574+ : mDepth(32), mFormat(QImage::Format_ARGB32_Premultiplied), mDpr(1.0)
575+{
576+ if (qEnvironmentVariableIsSet(devicePixelRatioEnvironmentVariable)) {
577+ bool ok = false;
578+ const float dpr = qgetenv(devicePixelRatioEnvironmentVariable).toFloat(&ok);
579+ if (ok && dpr > 0) {
580+ mDpr = dpr;
581+ }
582+ }
583+}
584+
585+QCustomIntegration::QCustomIntegration()
586+{
587+ QCustomScreen *mPrimaryScreen = new QCustomScreen();
588+
589+ mPrimaryScreen->mGeometry = QRect(0, 0, 240, 320);
590+ mPrimaryScreen->mDepth = 32;
591+ mPrimaryScreen->mFormat = QImage::Format_ARGB32_Premultiplied;
592+
593+ screenAdded(mPrimaryScreen);
594+}
595+
596+bool QCustomIntegration::hasCapability(QPlatformIntegration::Capability cap) const
597+{
598+ switch (cap) {
599+ case ThreadedPixmaps: return true;
600+ case MultipleWindows: return true;
601+ default: return QPlatformIntegration::hasCapability(cap);
602+ }
603+}
604+
605+// Dummy font database that does not scan the fonts directory to be
606+// used for command line tools like qmlplugindump that do not create windows
607+// unless DebugBackingStore is activated.
608+class DummyFontDatabase : public QPlatformFontDatabase
609+{
610+public:
611+ void populateFontDatabase() override {}
612+};
613+
614+QPlatformFontDatabase *QCustomIntegration::fontDatabase() const
615+{
616+ return new DummyFontDatabase;
617+}
618+
619+
620+QPlatformWindow *QCustomIntegration::createPlatformWindow(QWindow *window) const
621+{
622+ QPlatformWindow *w = new QPlatformWindow(window);
623+ w->requestActivateWindow();
624+ return w;
625+}
626+
627+QPlatformBackingStore *QCustomIntegration::createPlatformBackingStore(QWindow *window) const
628+{
629+ return new QCustomBackingStore(window);
630+}
631+
632+QAbstractEventDispatcher *QCustomIntegration::createEventDispatcher() const
633+{
634+ return createUnixEventDispatcher();
635+}
636+
637+QCustomIntegration *QCustomIntegration::instance()
638+{
639+ return static_cast<QCustomIntegration *>(QGuiApplicationPrivate::platformIntegration());
640+}
641
642=== added file 'tests/unit/custom_qpa/qcustomintegration.h'
643--- tests/unit/custom_qpa/qcustomintegration.h 1970-01-01 00:00:00 +0000
644+++ tests/unit/custom_qpa/qcustomintegration.h 2015-08-12 11:28:41 +0000
645@@ -0,0 +1,74 @@
646+/****************************************************************************
647+**
648+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
649+** Contact: http://www.qt-project.org/legal
650+**
651+** This file is part of the plugins of the Qt Toolkit.
652+**
653+** $QT_BEGIN_LICENSE:LGPL21$
654+** Commercial License Usage
655+** Licensees holding valid commercial Qt licenses may use this file in
656+** accordance with the commercial license agreement provided with the
657+** Software or, alternatively, in accordance with the terms contained in
658+** a written agreement between you and Digia. For licensing terms and
659+** conditions see http://qt.digia.com/licensing. For further information
660+** use the contact form at http://qt.digia.com/contact-us.
661+**
662+** GNU Lesser General Public License Usage
663+** Alternatively, this file may be used under the terms of the GNU Lesser
664+** General Public License version 2.1 or version 3 as published by the Free
665+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
666+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
667+** following information to ensure the GNU Lesser General Public License
668+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
669+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
670+**
671+** In addition, as a special exception, Digia gives you certain additional
672+** rights. These rights are described in the Digia Qt LGPL Exception
673+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
674+**
675+** $QT_END_LICENSE$
676+**
677+****************************************************************************/
678+
679+#ifndef QPLATFORMINTEGRATION_MINIMAL_H
680+#define QPLATFORMINTEGRATION_MINIMAL_H
681+
682+#include <qpa/qplatformintegration.h>
683+#include <qpa/qplatformscreen.h>
684+
685+class QCustomScreen : public QPlatformScreen
686+{
687+public:
688+ QCustomScreen();
689+
690+ QRect geometry() const override { return mGeometry; }
691+ int depth() const override { return mDepth; }
692+ QImage::Format format() const override { return mFormat; }
693+ qreal devicePixelRatio() const override { return mDpr; }
694+
695+public:
696+ QRect mGeometry;
697+ int mDepth;
698+ QImage::Format mFormat;
699+ QSize mPhysicalSize;
700+ qreal mDpr;
701+};
702+
703+class QCustomIntegration : public QPlatformIntegration
704+{
705+public:
706+ explicit QCustomIntegration();
707+ ~QCustomIntegration() = default;
708+
709+ bool hasCapability(QPlatformIntegration::Capability cap) const override;
710+ QPlatformFontDatabase *fontDatabase() const override;
711+
712+ QPlatformWindow *createPlatformWindow(QWindow *window) const override;
713+ QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const override;
714+ QAbstractEventDispatcher *createEventDispatcher() const override;
715+
716+ static QCustomIntegration *instance();
717+};
718+
719+#endif
720
721=== modified file 'tests/unit/runtest.sh'
722--- tests/unit/runtest.sh 2015-06-17 18:18:04 +0000
723+++ tests/unit/runtest.sh 2015-08-12 11:28:41 +0000
724@@ -43,6 +43,8 @@
725
726 if [ "$_MINIMAL" = "minimal" ]; then
727 _CMD="$_CMD -p -platform -p minimal"
728+ elif [ "$_MINIMAL" = "custom" ]; then
729+ _CMD="$_CMD -p -platform -p custom"
730 fi
731
732 if [ $_TARGETPATH != $_TESTFILEPATH ]; then
733
734=== added directory 'tests/unit/tst_units/dpr1'
735=== added file 'tests/unit/tst_units/dpr1/dpr1.pro'
736--- tests/unit/tst_units/dpr1/dpr1.pro 1970-01-01 00:00:00 +0000
737+++ tests/unit/tst_units/dpr1/dpr1.pro 2015-08-12 11:28:41 +0000
738@@ -0,0 +1,3 @@
739+include(../../test-include.pri)
740+SOURCES += tst_units.cpp
741+RESOURCES += dpr1.qrc
742
743=== renamed file 'tests/unit/tst_units/tst_units.qrc' => 'tests/unit/tst_units/dpr1/dpr1.qrc'
744=== renamed file 'tests/unit/tst_units/exact_match@8.png' => 'tests/unit/tst_units/dpr1/exact_match@8.png'
745=== renamed file 'tests/unit/tst_units/exact_match_no_suffix.png' => 'tests/unit/tst_units/dpr1/exact_match_no_suffix.png'
746=== renamed file 'tests/unit/tst_units/higher_scale.png' => 'tests/unit/tst_units/dpr1/higher_scale.png'
747=== renamed file 'tests/unit/tst_units/lower_scale.png' => 'tests/unit/tst_units/dpr1/lower_scale.png'
748=== renamed file 'tests/unit/tst_units/resource@1.png' => 'tests/unit/tst_units/dpr1/resource@1.png'
749=== renamed file 'tests/unit/tst_units/resource@10.png' => 'tests/unit/tst_units/dpr1/resource@10.png'
750=== renamed file 'tests/unit/tst_units/resource@15.png' => 'tests/unit/tst_units/dpr1/resource@15.png'
751=== renamed file 'tests/unit/tst_units/resource@18.png' => 'tests/unit/tst_units/dpr1/resource@18.png'
752=== renamed file 'tests/unit/tst_units/resource@19.png' => 'tests/unit/tst_units/dpr1/resource@19.png'
753=== renamed file 'tests/unit/tst_units/resource@8.png' => 'tests/unit/tst_units/dpr1/resource@8.png'
754=== renamed file 'tests/unit/tst_units/resource_only_higher@13.png' => 'tests/unit/tst_units/dpr1/resource_only_higher@13.png'
755=== renamed file 'tests/unit/tst_units/resource_only_smaller@7.png' => 'tests/unit/tst_units/dpr1/resource_only_smaller@7.png'
756=== renamed file 'tests/unit/tst_units/resources_unit' => 'tests/unit/tst_units/dpr1/resources_unit'
757=== renamed file 'tests/unit/tst_units/tst_units.cpp' => 'tests/unit/tst_units/dpr1/tst_units.cpp'
758=== added directory 'tests/unit/tst_units/dpr2'
759=== added file 'tests/unit/tst_units/dpr2/dpr2.pro'
760--- tests/unit/tst_units/dpr2/dpr2.pro 1970-01-01 00:00:00 +0000
761+++ tests/unit/tst_units/dpr2/dpr2.pro 2015-08-12 11:28:41 +0000
762@@ -0,0 +1,3 @@
763+CONFIG += custom_qpa # needed by test to set device pixel ratio correctly
764+include(../../test-include.pri)
765+SOURCES += tst_units_dpr2.cpp
766
767=== added file 'tests/unit/tst_units/dpr2/tst_units_dpr2.cpp'
768--- tests/unit/tst_units/dpr2/tst_units_dpr2.cpp 1970-01-01 00:00:00 +0000
769+++ tests/unit/tst_units/dpr2/tst_units_dpr2.cpp 2015-08-12 11:28:41 +0000
770@@ -0,0 +1,143 @@
771+/*
772+ * Copyright (C) 2015 Canonical, Ltd.
773+ *
774+ * This program is free software: you can redistribute it and/or modify it under
775+ * the terms of the GNU Lesser General Public License version 3, as published by
776+ * the Free Software Foundation.
777+ *
778+ * This program is distributed in the hope that it will be useful, but WITHOUT
779+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
780+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
781+ * Lesser General Public License for more details.
782+ *
783+ * You should have received a copy of the GNU Lesser General Public License
784+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
785+ */
786+
787+#include <QtTest/QtTest>
788+#include "ucunits.h"
789+
790+class tst_UCUnitsDPR2: public QObject
791+{
792+ Q_OBJECT
793+
794+private Q_SLOTS:
795+
796+ void dpGridUnitDefaultWithDPR2() {
797+ UCUnits units;
798+
799+ QCOMPARE(units.dp(1.0), 1.0f);
800+ QCOMPARE(units.dp(1.32), 1.5f);
801+ QCOMPARE(units.dp(1.72), 1.5f);
802+ QCOMPARE(units.dp(0.23), 0.0f);
803+ QCOMPARE(units.dp(0.51), 0.5f);
804+ QCOMPARE(units.dp(0.9999), 1.0f);
805+ QCOMPARE(units.dp(1000.01), 1000.0f);
806+ }
807+
808+ void guGridUnitDefaultWithDPR2() {
809+ UCUnits units;
810+
811+ QCOMPARE(units.gu(0.5), 4.0f);
812+ QCOMPARE(units.gu(1), 8.0f);
813+ QCOMPARE(units.gu(1.5), 12.0f);
814+ QCOMPARE(units.gu(2), 16.0f);
815+ QCOMPARE(units.gu(4), 32.0f);
816+ QCOMPARE(units.gu(100000), 800000.0f);
817+ QCOMPARE(units.gu(150.51983), 1204.0f);
818+ }
819+
820+ void dpGridUnitEightWithDPR2() {
821+ UCUnits units;
822+ units.setGridUnit(8);
823+
824+ QCOMPARE(units.dp(1.0), 0.5f);
825+ QCOMPARE(units.dp(1.32), 0.5f);
826+ QCOMPARE(units.dp(1.72), 1.0f);
827+ QCOMPARE(units.dp(0.23), 0.0f);
828+ QCOMPARE(units.dp(0.51), 0.5f);
829+ QCOMPARE(units.dp(0.9999), 0.5f);
830+ QCOMPARE(units.dp(1000.01), 500.0f);
831+ }
832+
833+ void guGridUnitEightWithDPR2() {
834+ UCUnits units;
835+ units.setGridUnit(8);
836+
837+ QCOMPARE(units.gu(0.5), 2.0f);
838+ QCOMPARE(units.gu(1), 4.0f);
839+ QCOMPARE(units.gu(1.5), 6.0f);
840+ QCOMPARE(units.gu(2), 8.0f);
841+ QCOMPARE(units.gu(4), 16.0f);
842+ QCOMPARE(units.gu(100000), 400000.0f);
843+ QCOMPARE(units.gu(150.51983), 602.0f);
844+ }
845+
846+ void dpGridUnitSixteenWithDPR2() {
847+ UCUnits units;
848+ units.setGridUnit(16);
849+ /* This testcase covers unit calculations when the Qt device pixel ratio is 2.
850+ *
851+ */
852+
853+ QCOMPARE(units.dp(1.0), 1.0f);
854+ QCOMPARE(units.dp(1.32), 1.5f);
855+ QCOMPARE(units.dp(1.72), 1.5f);
856+ QCOMPARE(units.dp(0.23), 0.0f);
857+ QCOMPARE(units.dp(0.51), 0.5f);
858+ QCOMPARE(units.dp(0.9999), 1.0f);
859+ QCOMPARE(units.dp(1000.01), 1000.0f);
860+ }
861+
862+ void guGridUnitSixteenWithDPR2() {
863+ UCUnits units;
864+ units.setGridUnit(16);
865+
866+ QCOMPARE(units.gu(0.5), 4.0f);
867+ QCOMPARE(units.gu(1), 8.0f);
868+ QCOMPARE(units.gu(1.5), 12.0f);
869+ QCOMPARE(units.gu(2), 16.0f);
870+ QCOMPARE(units.gu(4), 32.0f);
871+ QCOMPARE(units.gu(100000), 800000.0f);
872+ QCOMPARE(units.gu(150.51983), 1204.0f);
873+ }
874+
875+ void dpGridUnitTwentyWithDPR2() {
876+ UCUnits units;
877+ units.setGridUnit(20);
878+
879+ QCOMPARE(units.dp(1.0), 1.0f);
880+ QCOMPARE(units.dp(1.32), 1.5f);
881+ QCOMPARE(units.dp(1.72), 1.5f);
882+ QCOMPARE(units.dp(0.23), 0.0f);
883+ QCOMPARE(units.dp(0.51), 0.5f);
884+ QCOMPARE(units.dp(0.9999), 1.0f);
885+ QCOMPARE(units.dp(1000.01), 1250.0f);
886+ }
887+
888+ void guGridUnitTenWithDPR2() {
889+ UCUnits units;
890+ units.setGridUnit(10);
891+
892+ QCOMPARE(units.gu(0.5), 2.5f);
893+ QCOMPARE(units.gu(1), 5.0f);
894+ QCOMPARE(units.gu(1.5), 7.5f);
895+ QCOMPARE(units.gu(2), 10.0f);
896+ QCOMPARE(units.gu(4), 20.0f);
897+ QCOMPARE(units.gu(100000), 500000.0f);
898+ QCOMPARE(units.gu(150.51983), 752.5f);
899+ }
900+};
901+
902+//QTEST_MAIN(tst_UCUnitsDPR2) - want to set custom env var, so need to use actual code:
903+int main(int argc, char *argv[])
904+{
905+ qputenv("QT_DEVICE_PIXEL_RATIO", "2");
906+
907+ QGuiApplication app(argc, argv);
908+ app.setAttribute(Qt::AA_Use96Dpi, true);
909+ tst_UCUnitsDPR2 tc;
910+ return QTest::qExec(&tc, argc, argv);
911+}
912+
913+#include "tst_units_dpr2.moc"
914
915=== added directory 'tests/unit/tst_units/dpr3'
916=== added file 'tests/unit/tst_units/dpr3/dpr3.pro'
917--- tests/unit/tst_units/dpr3/dpr3.pro 1970-01-01 00:00:00 +0000
918+++ tests/unit/tst_units/dpr3/dpr3.pro 2015-08-12 11:28:41 +0000
919@@ -0,0 +1,3 @@
920+CONFIG += custom_qpa # needed by test to set device pixel ratio correctly
921+include(../../test-include.pri)
922+SOURCES += tst_units_dpr3.cpp
923
924=== added file 'tests/unit/tst_units/dpr3/tst_units_dpr3.cpp'
925--- tests/unit/tst_units/dpr3/tst_units_dpr3.cpp 1970-01-01 00:00:00 +0000
926+++ tests/unit/tst_units/dpr3/tst_units_dpr3.cpp 2015-08-12 11:28:41 +0000
927@@ -0,0 +1,88 @@
928+/*
929+ * Copyright (C) 2015 Canonical, Ltd.
930+ *
931+ * This program is free software: you can redistribute it and/or modify it under
932+ * the terms of the GNU Lesser General Public License version 3, as published by
933+ * the Free Software Foundation.
934+ *
935+ * This program is distributed in the hope that it will be useful, but WITHOUT
936+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
937+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
938+ * Lesser General Public License for more details.
939+ *
940+ * You should have received a copy of the GNU Lesser General Public License
941+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
942+ */
943+
944+#include <QtTest/QtTest>
945+#include "ucunits.h"
946+
947+class tst_UCUnitsDPR3: public QObject
948+{
949+ Q_OBJECT
950+
951+private Q_SLOTS:
952+
953+ void dpGridUnitDefaultWithDPR3() {
954+ UCUnits units;
955+
956+ QCOMPARE(units.dp(1.0), 1.0f);
957+ QCOMPARE(units.dp(1.32), 1.33333f);
958+ QCOMPARE(units.dp(1.72), 1.66666f);
959+ QCOMPARE(units.dp(0.23), 0.333333f);
960+ QCOMPARE(units.dp(0.51), 0.666666f);
961+ QCOMPARE(units.dp(0.9999), 1.0f);
962+ QCOMPARE(units.dp(1000.01), 1000.0f);
963+ }
964+
965+ void guGridUnitDefaultWithDPR3() {
966+ UCUnits units;
967+
968+ QCOMPARE(units.gu(0.5), 4.0f);
969+ QCOMPARE(units.gu(1), 8.0f);
970+ QCOMPARE(units.gu(1.5), 12.0f);
971+ QCOMPARE(units.gu(2), 16.0f);
972+ QCOMPARE(units.gu(4), 32.0f);
973+ QCOMPARE(units.gu(100000), 800000.0f);
974+ QCOMPARE(units.gu(150.51983), 1204.0f);
975+ }
976+
977+ void dpGridUnitSixteenWithDPR3() {
978+ UCUnits units;
979+ units.setGridUnit(16);
980+
981+ QCOMPARE(units.dp(1.0), 0.666666f);
982+ QCOMPARE(units.dp(1.32), 1.0f);
983+ QCOMPARE(units.dp(1.72), 1.0f);
984+ QCOMPARE(units.dp(0.23), 0.0f);
985+ QCOMPARE(units.dp(0.51), 0.333333f);
986+ QCOMPARE(units.dp(0.9999), 0.666666f);
987+ QCOMPARE(units.dp(1000.01), 666.666666f);
988+ }
989+
990+ void guGridUnitSixteenWithDPR3() {
991+ UCUnits units;
992+ units.setGridUnit(16);
993+
994+ QCOMPARE(units.gu(0.5), 2.666666f);
995+ QCOMPARE(units.gu(1), 5.333333f);
996+ QCOMPARE(units.gu(1.5), 8.0f);
997+ QCOMPARE(units.gu(2), 10.666666f);
998+ QCOMPARE(units.gu(4), 21.333333f);
999+ QCOMPARE(units.gu(100000), 533333.333333f);
1000+ QCOMPARE(units.gu(150.51983), 802.666666f);
1001+ }
1002+};
1003+
1004+//QTEST_MAIN(tst_UCUnitsDPR3) - want to set custom env var, so need to use actual code:
1005+int main(int argc, char *argv[])
1006+{
1007+ qputenv("QT_DEVICE_PIXEL_RATIO", "3");
1008+
1009+ QGuiApplication app(argc, argv);
1010+ app.setAttribute(Qt::AA_Use96Dpi, true);
1011+ tst_UCUnitsDPR3 tc;
1012+ return QTest::qExec(&tc, argc, argv);
1013+}
1014+
1015+#include "tst_units_dpr3.moc"
1016
1017=== modified file 'tests/unit/tst_units/tst_units.pro'
1018--- tests/unit/tst_units/tst_units.pro 2012-10-09 17:54:43 +0000
1019+++ tests/unit/tst_units/tst_units.pro 2015-08-12 11:28:41 +0000
1020@@ -1,3 +1,6 @@
1021-include(../test-include.pri)
1022-SOURCES += tst_units.cpp
1023-RESOURCES += tst_units.qrc
1024+TEMPLATE = subdirs
1025+
1026+SUBDIRS += \
1027+ dpr1 \
1028+ dpr2 \
1029+ dpr3
1030
1031=== modified file 'tests/unit/unit.pro'
1032--- tests/unit/unit.pro 2015-03-10 11:49:27 +0000
1033+++ tests/unit/unit.pro 2015-08-12 11:28:41 +0000
1034@@ -14,7 +14,9 @@
1035 tst_components_benchmark
1036 #}
1037
1038-SUBDIRS += tst_units \
1039+SUBDIRS += \
1040+ custom_qpa \
1041+ tst_units \
1042 tst_scaling_image_provider \
1043 tst_qquick_image_extension \
1044 tst_performance \

Subscribers

People subscribed via source and target branches