~verzegnassi-stefano/+junk/pdf-viewer

« back to all changes in this revision

Viewing changes to src/plugin/poppler-qml-plugin/ucunits.cpp

  • Committer: Stefano Verzegnassi
  • Date: 2016-02-26 13:09:34 UTC
  • Revision ID: stefano92.100@gmail.com-20160226130934-hlvs30lh5zq446sh
Sync PDF plugin with latest LOK-plugin changes:
- Pinch to zoom (not tested)
- Double tap to zoom (not tested)
- Use UITK 1.3 ScrollView
- Zoom settings as a separate object
- Use UCUnits for a better scaling strategy/support
- Zoom modes: manual, fit width, fit page and automatic (as gnome-evince)
- Don't remove QImage data in SGTileItem

And probably some other minor change. There's some chance I've introduced some new bug here and there. Anyway that's not yet relevant because of the current status of the plugin.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright 2012 Canonical Ltd.
 
3
 *
 
4
 * This program is free software; you can redistribute it and/or modify
 
5
 * it under the terms of the GNU Lesser General Public License as published by
 
6
 * the Free Software Foundation; version 3.
 
7
 *
 
8
 * This program is distributed in the hope that it will be useful,
 
9
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
11
 * GNU Lesser General Public License for more details.
 
12
 *
 
13
 * You should have received a copy of the GNU Lesser General Public License
 
14
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
15
 *
 
16
 * Author: Florian Boucault <florian.boucault@canonical.com>
 
17
 */
 
18
 
 
19
#include "ucunits.h"
 
20
 
 
21
#include <QtQml/QQmlContext>
 
22
#include <QtQml/QQmlFile>
 
23
#include <QtCore/QFileInfo>
 
24
#include <QtCore/QDir>
 
25
#include <QtCore/QRegularExpression>
 
26
#include <QtCore/qmath.h>
 
27
#include <QtGui/QGuiApplication>
 
28
#include <QtGui/QScreen>
 
29
 
 
30
#define ENV_GRID_UNIT_PX "GRID_UNIT_PX"
 
31
#define DEFAULT_GRID_UNIT_PX 8
 
32
 
 
33
static float getenvFloat(const char* name, float defaultValue)
 
34
{
 
35
    QByteArray stringValue = qgetenv(name);
 
36
    bool ok;
 
37
    float value = stringValue.toFloat(&ok);
 
38
    return ok ? value : defaultValue;
 
39
}
 
40
 
 
41
 
 
42
/*!
 
43
    \qmltype Units
 
44
    \instantiates UCUnits
 
45
    \inqmlmodule Ubuntu.Components 1.1
 
46
    \ingroup resolution-independence
 
47
    \brief Units of measurement for sizes, spacing, margin, etc.
 
48
 
 
49
    Units provides facilities for measuring UI elements in a variety
 
50
    of units other than just pixels.
 
51
 
 
52
    A global instance of Units is exposed as the \b{units} context property.
 
53
    Example usage:
 
54
 
 
55
    \qml
 
56
    import QtQuick 2.4
 
57
    import Ubuntu.Components 1.2
 
58
 
 
59
    Item {
 
60
        width: units.gu(2)
 
61
        height: units.gu(5)
 
62
    }
 
63
    \endqml
 
64
 
 
65
    \sa {Resolution Independence}
 
66
*/
 
67
 
 
68
/*
 
69
 * Note on the interaction between GRID_UNIT_PX and QT_DEVICE_PIXEL_RATIO
 
70
 *
 
71
 * In Qt5.4 there is a single means to scale the UI: the QT_DEVICE_PIXEL_RATIO environment
 
72
 * variable. This accepts only integer values, thus allowing a x2 or x3 scaling of any
 
73
 * Qt-based UI, that includes QWidget as well as any QML UI.
 
74
 *
 
75
 * Setting QT_DEVICE_PIXEL_RATIO=2 implies one density-independent pixel corresponds to 2
 
76
 * physical pixels. Developers describe their UI in terms of density-independent pixels.
 
77
 * Qt scales accordingly.
 
78
 *
 
79
 * The Ubuntu UI Toolkit has solved the scaling problem with the GRID_UNIT_PX variable.
 
80
 * It offers more flexibility, but only scales QML applications written to use the UITK
 
81
 * (since it uses this Units class) as it is built on top of QML.
 
82
 *
 
83
 * There are additional areas in Qt where QT_DEVICE_PIXEL_RATIO causes correct scaling which
 
84
 * GRID_UNIT_PX cannot, for example:
 
85
 *   1. cacheBuffer for ListView/GridViews - specified in density-independent pixels
 
86
 *   2. gesture recognition  matches what is on screen better, as it is density-independent
 
87
 *      pixel aware
 
88
 *
 
89
 * In order to get the best of both worlds, Ubuntu will set both GRID_UNIT_PX and
 
90
 * QT_DEVICE_PIXEL_RATIO. Thus all Qt apps will scale reasonably well, with UITK-based apps
 
91
 * scaling perfectly for any desired scale (i.e. non-integer scales).
 
92
 *
 
93
 * However UITK developers can just use this Units class as usual, and will be almost totally
 
94
 * isolated from Qt's own scaling concept.
 
95
 */
 
96
 
 
97
UCUnits::UCUnits(QObject *parent) :
 
98
    QObject(parent),
 
99
    m_devicePixelRatio(qGuiApp->devicePixelRatio())
 
100
{
 
101
    // If GRID_UNIT_PX set, always use it. If not, 1GU := DEFAULT_GRID_UNIT_PX * m_devicePixelRatio
 
102
    if (qEnvironmentVariableIsSet(ENV_GRID_UNIT_PX)) {
 
103
        m_gridUnit = getenvFloat(ENV_GRID_UNIT_PX, DEFAULT_GRID_UNIT_PX);
 
104
    } else {
 
105
        m_gridUnit = DEFAULT_GRID_UNIT_PX * m_devicePixelRatio;
 
106
    }
 
107
}
 
108
 
 
109
/*!
 
110
    \qmlproperty real Units::gridUnit
 
111
 
 
112
    The number of pixels 1 grid unit corresponds to.
 
113
*/
 
114
float UCUnits::gridUnit()
 
115
{
 
116
    return m_gridUnit;
 
117
}
 
118
 
 
119
void UCUnits::setGridUnit(float gridUnit)
 
120
{
 
121
    m_gridUnit = gridUnit;
 
122
    Q_EMIT gridUnitChanged();
 
123
}
 
124
 
 
125
/*!
 
126
    \qmlmethod real Units::dp(real value)
 
127
 
 
128
    Returns the number of pixels \a value density independent pixels correspond to.
 
129
*/
 
130
// Density-independent pixels (and not physical pixels) because Qt sizes in terms of density-independent pixels.
 
131
float UCUnits::dp(float value)
 
132
{
 
133
    const float ratio = m_gridUnit / DEFAULT_GRID_UNIT_PX;
 
134
    if (value <= 2.0) {
 
135
        // for values under 2dp, return only multiples of the value
 
136
        return qRound(value * qFloor(ratio)) / m_devicePixelRatio;
 
137
    } else {
 
138
        return qRound(value * ratio) / m_devicePixelRatio;
 
139
    }
 
140
}
 
141
 
 
142
/*!
 
143
    \qmlmethod real Units::gu(real value)
 
144
 
 
145
    Returns the number of pixels \a value grid units correspond to.
 
146
*/
 
147
// Density-independent pixels (and not physical pixels) because Qt sizes in terms of density-independent pixels.
 
148
 
 
149
float UCUnits::gu(float value)
 
150
{
 
151
    return qRound(value * m_gridUnit) / m_devicePixelRatio;
 
152
}
 
153
 
 
154
QString UCUnits::resolveResource(const QUrl& url)
 
155
{
 
156
    if (url.isEmpty()) {
 
157
        return QString();
 
158
    }
 
159
 
 
160
    QString path = QQmlFile::urlToLocalFileOrQrc(url);
 
161
 
 
162
    if (path.isEmpty()) {
 
163
        return QString();
 
164
    }
 
165
 
 
166
    QFileInfo fileInfo(path);
 
167
    if (fileInfo.exists() && !fileInfo.isFile()) {
 
168
        return QString();
 
169
    }
 
170
 
 
171
    QString prefix = fileInfo.dir().absolutePath() + QDir::separator() + fileInfo.baseName();
 
172
    QString suffix = "." + fileInfo.completeSuffix();
 
173
 
 
174
    /* Use file with expected grid unit suffix if it exists.
 
175
       For example, if m_gridUnit = 10, look for resource@10.png.
 
176
    */
 
177
 
 
178
    path = prefix + suffixForGridUnit(m_gridUnit) + suffix;
 
179
    if (QFile::exists(path)) {
 
180
        return QString("1") + "/" + path;
 
181
    }
 
182
 
 
183
    /* No file with expected grid unit suffix exists.
 
184
       List all the files of the form fileBaseName@[0-9]*.fileSuffix and select
 
185
       the most appropriate one privileging downscaling high resolution assets
 
186
       over upscaling low resolution assets.
 
187
 
 
188
       The most appropriate file has a grid unit suffix greater than the target
 
189
       grid unit (m_gridUnit) yet as small as possible.
 
190
       If no file with a grid unit suffix greater than the target grid unit
 
191
       exists, then select one with a grid unit suffix as close as possible to
 
192
       the target grid unit.
 
193
 
 
194
       For example, if m_gridUnit = 10 and the available files are
 
195
       resource@9.png, resource@14.png and resource@18.png, the most appropriate
 
196
       file would be resource@14.png since it is above 10 and smaller
 
197
       than resource@18.png.
 
198
    */
 
199
    QStringList nameFilters;
 
200
    nameFilters << fileInfo.baseName() + "@[0-9]*" + suffix;
 
201
    QStringList files = fileInfo.dir().entryList(nameFilters, QDir::Files);
 
202
 
 
203
    if (!files.empty()) {
 
204
        float selectedGridUnitSuffix = gridUnitSuffixFromFileName(files.first());
 
205
 
 
206
        Q_FOREACH (const QString& fileName, files) {
 
207
            float gridUnitSuffix = gridUnitSuffixFromFileName(fileName);
 
208
            if ((selectedGridUnitSuffix >= m_gridUnit && gridUnitSuffix >= m_gridUnit && gridUnitSuffix < selectedGridUnitSuffix)
 
209
                || (selectedGridUnitSuffix < m_gridUnit && gridUnitSuffix > selectedGridUnitSuffix)) {
 
210
                selectedGridUnitSuffix = gridUnitSuffix;
 
211
            }
 
212
        }
 
213
 
 
214
        path = prefix + suffixForGridUnit(selectedGridUnitSuffix) + suffix;
 
215
        float scaleFactor = m_gridUnit / selectedGridUnitSuffix;
 
216
        return QString::number(scaleFactor) + "/" + path;
 
217
    }
 
218
 
 
219
    path = prefix + suffix;
 
220
    if (QFile::exists(path)) {
 
221
        return QString("1") + "/" + path;
 
222
    }
 
223
 
 
224
    return QString();
 
225
}
 
226
 
 
227
QString UCUnits::suffixForGridUnit(float gridUnit)
 
228
{
 
229
    return "@" + QString::number(gridUnit);
 
230
}
 
231
 
 
232
float UCUnits::gridUnitSuffixFromFileName(const QString& fileName)
 
233
{
 
234
    QRegularExpression re("^.*@([0-9]*).*$");
 
235
    QRegularExpressionMatch match = re.match(fileName);
 
236
    if (match.hasMatch()) {
 
237
        return match.captured(1).toFloat();
 
238
    } else {
 
239
        return 0;
 
240
    }
 
241
}