Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Toggle main menu visibility
Loading...
Searching...
No Matches
qbackingstore.cpp
Go to the documentation of this file.
1
// Copyright (C) 2016 The Qt Company Ltd.
2
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
// Qt-Security score:significant reason:default
4
5
#
include
<
qbackingstore
.
h
>
6
#
include
<
qwindow
.
h
>
7
#
include
<
qpixmap
.
h
>
8
#
include
<
qpa
/
qplatformbackingstore
.
h
>
9
#
include
<
qpa
/
qplatformintegration
.
h
>
10
#
include
<
qscreen
.
h
>
11
#
include
<
qdebug
.
h
>
12
#
include
<
qscopedpointer
.
h
>
13
14
#
include
<
private
/
qguiapplication_p
.
h
>
15
#
include
<
private
/
qwindow_p
.
h
>
16
17
#
include
<
private
/
qhighdpiscaling_p
.
h
>
18
19
QT_BEGIN_NAMESPACE
20
21
class
QBackingStorePrivate
22
{
23
public
:
24
QBackingStorePrivate
(QWindow *w)
25
:
window
(w)
26
{
27
}
28
29
// Returns the DPR for the backing store. This is the DPR for the QWindow,
30
// possibly rounded up to the nearest integer.
31
qreal
backingStoreDevicePixelRatio
()
const
32
{
33
// Note: keep in sync with QWidget::metric()!
34
qreal windowDpr =
window
->devicePixelRatio();
35
return
downscale ? std::ceil(windowDpr) : windowDpr;
36
}
37
38
// Returns the factor used for converting from device independent to native
39
// backing store sizes. Normally this is just the gui scale factor, however
40
// if the backing store rounds the DPR up to the nearest integer then we also
41
// need to account for the factor introduced by that rounding.
42
qreal
deviceIndependentToNativeFactor
()
const
43
{
44
const
qreal roundingFactor = backingStoreDevicePixelRatio() / window->devicePixelRatio();
45
const
qreal guiFactor = QHighDpiScaling::factor(window);
46
return
roundingFactor * guiFactor;
47
}
48
49
QWindow *
window
;
50
QPlatformBackingStore *
platformBackingStore
=
nullptr
;
51
QScopedPointer
<
QImage
>
highDpiBackingstore
;
52
QRegion
staticContents
;
53
QSize
size
;
54
QSize
nativeSize
;
55
bool
downscale
= qEnvironmentVariableIntValue(
"QT_WIDGETS_HIGHDPI_DOWNSCALE"
) > 0;
56
};
57
58
/*!
59
\class QBackingStore
60
\since 5.0
61
\inmodule QtGui
62
63
\brief The QBackingStore class provides a drawing area for QWindow.
64
65
QBackingStore enables the use of QPainter to paint on a QWindow with type
66
RasterSurface. The other way of rendering to a QWindow is through the use
67
of OpenGL with QOpenGLContext.
68
69
A QBackingStore contains a buffered representation of the window contents,
70
and thus supports partial updates by using QPainter to only update a sub
71
region of the window contents.
72
73
QBackingStore might be used by an application that wants to use QPainter
74
without OpenGL acceleration and without the extra overhead of using the
75
QWidget or QGraphicsView UI stacks. For an example of how to use
76
QBackingStore see the \l{Raster Window Example}.
77
*/
78
79
/*!
80
Constructs an empty surface for the given top-level \a window.
81
*/
82
QBackingStore::QBackingStore(QWindow *window)
83
: d_ptr(
new
QBackingStorePrivate(window))
84
{
85
if
(window->handle()) {
86
// Create platform backingstore up front if we have a platform window,
87
// otherwise delay the creation until absolutely necessary.
88
handle();
89
}
90
}
91
92
/*!
93
Destroys this surface.
94
*/
95
QBackingStore::~QBackingStore()
96
{
97
delete
d_ptr->platformBackingStore;
98
}
99
100
/*!
101
Returns a pointer to the top-level window associated with this
102
surface.
103
*/
104
QWindow* QBackingStore::window()
const
105
{
106
return
d_ptr->window;
107
}
108
109
/*!
110
Begins painting on the backing store surface in the given \a region.
111
112
You should call this function before using the paintDevice() to
113
paint.
114
115
\sa endPaint(), paintDevice()
116
*/
117
118
void
QBackingStore::beginPaint(
const
QRegion ®ion)
119
{
120
const
qreal toNativeFactor = d_ptr->deviceIndependentToNativeFactor();
121
122
if
(d_ptr->nativeSize != QHighDpi::scale(size(), toNativeFactor))
123
resize(size());
124
125
QPlatformBackingStore *platformBackingStore = handle();
126
platformBackingStore->beginPaint(QHighDpi::scale(region, toNativeFactor));
127
128
// When QtGui is applying a high-dpi scale factor the backing store
129
// creates a "large" backing store image. This image needs to be
130
// painted on as a high-dpi image, which is done by setting
131
// devicePixelRatio. Do this on a separate image instance that shares
132
// the image data to avoid having the new devicePixelRatio be propagated
133
// back to the platform plugin.
134
QPaintDevice *device = platformBackingStore->paintDevice();
135
if
(!qFuzzyCompare(toNativeFactor, qreal(1)) && device->devType() == QInternal::Image) {
136
QImage *source =
static_cast
<QImage *>(device);
137
const
bool
needsNewImage = d_ptr->highDpiBackingstore.isNull()
138
|| source->constBits() != d_ptr->highDpiBackingstore->constBits()
139
|| source->size() != d_ptr->highDpiBackingstore->size()
140
|| source->bytesPerLine() != d_ptr->highDpiBackingstore->bytesPerLine()
141
|| source->format() != d_ptr->highDpiBackingstore->format();
142
if
(needsNewImage)
143
d_ptr->highDpiBackingstore.reset(
144
new
QImage(source->bits(), source->width(), source->height(), source->bytesPerLine(), source->format()));
145
146
d_ptr->highDpiBackingstore->setDevicePixelRatio(d_ptr->backingStoreDevicePixelRatio());
147
}
else
{
148
d_ptr->highDpiBackingstore.reset();
149
}
150
}
151
152
/*!
153
Returns the paint device for this surface.
154
155
\warning The device is only valid between calls to beginPaint() and
156
endPaint(). You should not cache the returned value.
157
*/
158
QPaintDevice *QBackingStore::paintDevice()
159
{
160
QPaintDevice *device = handle()->paintDevice();
161
162
if
(!qFuzzyCompare(d_ptr->deviceIndependentToNativeFactor(), qreal(1)) && device->devType() == QInternal::Image)
163
return
d_ptr->highDpiBackingstore.data();
164
165
return
device;
166
}
167
168
/*!
169
Ends painting.
170
171
You should call this function after painting with the paintDevice()
172
has ended.
173
174
\sa beginPaint(), paintDevice()
175
*/
176
void
QBackingStore::endPaint()
177
{
178
if
(paintDevice()->paintingActive())
179
qWarning(
"QBackingStore::endPaint() called with active painter; did you forget to destroy it or call QPainter::end() on it?"
);
180
181
handle()->endPaint();
182
}
183
184
/*!
185
Flushes the given \a region from the specified \a window onto the
186
screen.
187
188
The \a window must either be the top level window represented by
189
this backingstore, or a non-transient child of that window. Passing
190
\nullptr falls back to using the backingstore's top level window.
191
192
If the \a window is a child window, the \a region should be in child window
193
coordinates, and the \a offset should be the child window's offset in relation
194
to the backingstore's top level window.
195
196
You should call this function after ending painting with endPaint().
197
*/
198
void
QBackingStore::flush(
const
QRegion ®ion, QWindow *window,
const
QPoint &offset)
199
{
200
QWindow *topLevelWindow =
this
->window();
201
202
if
(!window)
203
window = topLevelWindow;
204
if
(!window->handle()) {
205
qWarning() <<
"QBackingStore::flush() called for "
206
<< window <<
" which does not have a handle."
;
207
return
;
208
}
209
210
Q_ASSERT(window == topLevelWindow || topLevelWindow->isAncestorOf(window, QWindow::ExcludeTransients));
211
212
const
qreal toNativeFactor = d_ptr->deviceIndependentToNativeFactor();
213
214
QRegion nativeRegion = QHighDpi::scale(region, toNativeFactor);
215
QPoint nativeOffset;
216
if
(!offset.isNull()) {
217
nativeOffset = QHighDpi::scale(offset, toNativeFactor);
218
// Under fractional DPR, rounding of region and offset may accumulate to an off-by-one
219
QPoint topLeft = region.boundingRect().topLeft() + offset;
220
QPoint nativeTopLeft = QHighDpi::scale(topLeft, toNativeFactor);
221
QPoint diff = nativeTopLeft - (nativeRegion.boundingRect().topLeft() + nativeOffset);
222
Q_ASSERT(qMax(qAbs(diff.x()), qAbs(diff.y())) <= 1);
223
nativeRegion.translate(diff);
224
}
225
handle()->flush(window, nativeRegion, nativeOffset);
226
}
227
228
/*!
229
Sets the size of the window surface to \a size.
230
231
\sa size()
232
*/
233
void
QBackingStore::resize(
const
QSize &size)
234
{
235
const
qreal factor = d_ptr->deviceIndependentToNativeFactor();
236
d_ptr->size = size;
237
d_ptr->nativeSize = QHighDpi::scale(size, factor);
238
handle()->resize(d_ptr->nativeSize, QHighDpi::scale(d_ptr->staticContents, factor));
239
}
240
241
/*!
242
Returns the current size of the window surface.
243
*/
244
QSize QBackingStore::size()
const
245
{
246
return
d_ptr->size;
247
}
248
249
/*!
250
Scrolls the given \a area \a dx pixels to the right and \a dy
251
downward; both \a dx and \a dy may be negative.
252
253
Returns \c true if the area was scrolled successfully; false otherwise.
254
*/
255
bool
QBackingStore::scroll(
const
QRegion &area,
int
dx,
int
dy)
256
{
257
// Disable scrolling for non-integer scroll deltas. For this case
258
// the existing rendered pixels can't be re-used, and we return
259
// false to signal that a repaint is needed.
260
const
qreal toNativeFactor = d_ptr->deviceIndependentToNativeFactor();
261
const
qreal nativeDx = QHighDpi::scale(qreal(dx), toNativeFactor);
262
const
qreal nativeDy = QHighDpi::scale(qreal(dy), toNativeFactor);
263
const
int
roundedDx = qRound(nativeDx);
264
const
int
roundedDy = qRound(nativeDy);
265
266
if
(!qFuzzyCompare(nativeDx, qreal(roundedDx)) ||
267
!qFuzzyCompare(nativeDy, qreal(roundedDy)))
268
return
false
;
269
270
return
handle()->scroll(QHighDpi::scale(area, toNativeFactor), roundedDx, roundedDy);
271
}
272
273
/*!
274
Set \a region as the static contents of this window.
275
*/
276
void
QBackingStore::setStaticContents(
const
QRegion ®ion)
277
{
278
[[maybe_unused]]
static
const
bool
didCheckPlatformSupport = []{
279
const
auto
*integration = QGuiApplicationPrivate::platformIntegration();
280
if
(!integration->hasCapability(QPlatformIntegration::BackingStoreStaticContents))
281
qWarning(
"QBackingStore::setStaticContents(): Platform does not support static contents"
);
282
return
true
;
283
}();
284
285
d_ptr->staticContents = region;
286
}
287
288
/*!
289
Returns a QRegion representing the area of the window that
290
has static contents.
291
*/
292
QRegion QBackingStore::staticContents()
const
293
{
294
return
d_ptr->staticContents;
295
}
296
297
/*!
298
Returns a boolean indicating if this window has static contents or not.
299
*/
300
bool
QBackingStore::hasStaticContents()
const
301
{
302
return
!d_ptr->staticContents.isEmpty();
303
}
304
305
void
Q_GUI_EXPORT
qt_scrollRectInImage(QImage &img,
const
QRect &rect,
const
QPoint &offset)
306
{
307
// make sure we don't detach
308
uchar *mem =
const_cast
<uchar*>(img.constBits());
309
310
qsizetype lineskip = img.bytesPerLine();
311
int
depth = img.depth() >> 3;
312
313
const
QRect imageRect(0, 0, img.width(), img.height());
314
const
QRect sourceRect = rect.intersected(imageRect).intersected(imageRect.translated(-offset));
315
if
(sourceRect.isEmpty())
316
return
;
317
318
const
QRect destRect = sourceRect.translated(offset);
319
Q_ASSERT_X(imageRect.contains(destRect),
"qt_scrollRectInImage"
,
320
"The sourceRect should already account for clipping, both pre and post scroll"
);
321
322
const
uchar *src;
323
uchar *dest;
324
325
if
(sourceRect.top() < destRect.top()) {
326
src = mem + sourceRect.bottom() * lineskip + sourceRect.left() * depth;
327
dest = mem + (destRect.top() + sourceRect.height() - 1) * lineskip + destRect.left() * depth;
328
lineskip = -lineskip;
329
}
else
{
330
src = mem + sourceRect.top() * lineskip + sourceRect.left() * depth;
331
dest = mem + destRect.top() * lineskip + destRect.left() * depth;
332
}
333
334
const
int
w = sourceRect.width();
335
int
h = sourceRect.height();
336
const
int
bytes = w * depth;
337
338
// overlapping segments?
339
if
(offset.y() == 0 && qAbs(offset.x()) < w) {
340
do
{
341
::memmove(dest, src, bytes);
342
dest += lineskip;
343
src += lineskip;
344
}
while
(--h);
345
}
else
{
346
do
{
347
::memcpy(dest, src, bytes);
348
dest += lineskip;
349
src += lineskip;
350
}
while
(--h);
351
}
352
}
353
354
/*!
355
Returns a pointer to the QPlatformBackingStore implementation
356
*/
357
QPlatformBackingStore *QBackingStore::handle()
const
358
{
359
if
(!d_ptr->platformBackingStore) {
360
d_ptr->platformBackingStore = QGuiApplicationPrivate::platformIntegration()->createPlatformBackingStore(d_ptr->window);
361
d_ptr->platformBackingStore->setBackingStore(
const_cast
<QBackingStore*>(
this
));
362
}
363
return
d_ptr->platformBackingStore;
364
}
365
366
QT_END_NAMESPACE
QBackingStorePrivate
Definition
qbackingstore.cpp:22
QBackingStorePrivate::downscale
bool downscale
Definition
qbackingstore.cpp:55
QBackingStorePrivate::deviceIndependentToNativeFactor
qreal deviceIndependentToNativeFactor() const
Definition
qbackingstore.cpp:42
QBackingStorePrivate::backingStoreDevicePixelRatio
qreal backingStoreDevicePixelRatio() const
Definition
qbackingstore.cpp:31
QBackingStorePrivate::size
QSize size
Definition
qbackingstore.cpp:53
QBackingStorePrivate::QBackingStorePrivate
QBackingStorePrivate(QWindow *w)
Definition
qbackingstore.cpp:24
QBackingStorePrivate::window
QWindow * window
Definition
qbackingstore.cpp:49
QBackingStorePrivate::staticContents
QRegion staticContents
Definition
qbackingstore.cpp:52
QBackingStorePrivate::nativeSize
QSize nativeSize
Definition
qbackingstore.cpp:54
QBackingStorePrivate::platformBackingStore
QPlatformBackingStore * platformBackingStore
Definition
qbackingstore.cpp:50
QBackingStorePrivate::highDpiBackingstore
QScopedPointer< QImage > highDpiBackingstore
Definition
qbackingstore.cpp:51
QT_BEGIN_NAMESPACE
Combined button and popup list for selecting options.
Definition
qsequentialanimationgroup.cpp:47
operator<<
QDebug Q_GUI_EXPORT & operator<<(QDebug &s, const QVectorPath &path)
Definition
qpaintengineex.cpp:100
qtbase
src
gui
painting
qbackingstore.cpp
Generated on
for Qt by
1.18.0