Qt 6.x
The Qt SDK
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
4#include <qbackingstore.h>
5#include <qwindow.h>
6#include <qpixmap.h>
7#include <qpa/qplatformbackingstore.h>
8#include <qpa/qplatformintegration.h>
9#include <qscreen.h>
10#include <qdebug.h>
11#include <qscopedpointer.h>
12
13#include <private/qguiapplication_p.h>
14#include <private/qwindow_p.h>
15
16#include <private/qhighdpiscaling_p.h>
17
19
21{
22public:
24 : window(w)
25 {
26 }
27
28 // Returns the DPR for the backing store. This is the DPR for the QWindow,
29 // possibly rounded up to the nearest integer.
31 {
32 // Note: keep in sync with QWidget::metric()!
33 qreal windowDpr = window->devicePixelRatio();
34 return downscale ? std::ceil(windowDpr) : windowDpr;
35 }
36
37 // Returns the factor used for converting from device independent to native
38 // backing store sizes. Normally this is just the gui scale factor, however
39 // if the backing store rounds the DPR up to the nearest integer then we also
40 // need to account for the factor introduced by that rounding.
42 {
43 const qreal roundingFactor = backingStoreDevicePixelRatio() / window->devicePixelRatio();
44 const qreal guiFactor = QHighDpiScaling::factor(window);
45 return roundingFactor * guiFactor;
46 }
47
53 bool downscale = qEnvironmentVariableIntValue("QT_WIDGETS_HIGHDPI_DOWNSCALE") > 0;
54};
55
81 : d_ptr(new QBackingStorePrivate(window))
82{
83 if (window->handle()) {
84 // Create platform backingstore up front if we have a platform window,
85 // otherwise delay the creation until absolutely necessary.
86 handle();
87 }
88}
89
94{
95 delete d_ptr->platformBackingStore;
96}
97
103{
104 return d_ptr->window;
105}
106
117{
118 const qreal dpr = d_ptr->backingStoreDevicePixelRatio();
119
120 if (d_ptr->highDpiBackingstore &&
122 resize(size());
123
124 QPlatformBackingStore *platformBackingStore = handle();
125 platformBackingStore->beginPaint(QHighDpi::scale(region, d_ptr->deviceIndependentToNativeFactor()));
126
127 // When QtGui is applying a high-dpi scale factor the backing store
128 // creates a "large" backing store image. This image needs to be
129 // painted on as a high-dpi image, which is done by setting
130 // devicePixelRatio. Do this on a separate image instance that shares
131 // the image data to avoid having the new devicePixelRatio be propagated
132 // back to the platform plugin.
133 QPaintDevice *device = platformBackingStore->paintDevice();
134 if (QHighDpiScaling::isActive() && device->devType() == QInternal::Image) {
135 QImage *source = static_cast<QImage *>(device);
136 const bool needsNewImage = d_ptr->highDpiBackingstore.isNull()
137 || source->data_ptr() != d_ptr->highDpiBackingstore->data_ptr()
138 || source->size() != d_ptr->highDpiBackingstore->size()
139 || source->devicePixelRatio() != d_ptr->highDpiBackingstore->devicePixelRatio();
140 if (needsNewImage) {
142 new QImage(source->bits(), source->width(), source->height(), source->bytesPerLine(), source->format()));
143
145 }
146 }
147}
148
156{
158
160 return d_ptr->highDpiBackingstore.data();
161
162 return device;
163}
164
174{
175 if (paintDevice()->paintingActive())
176 qWarning("QBackingStore::endPaint() called with active painter; did you forget to destroy it or call QPainter::end() on it?");
177
178 handle()->endPaint();
179}
180
196{
197 QWindow *topLevelWindow = this->window();
198
199 if (!window)
200 window = topLevelWindow;
201 if (!window->handle()) {
202 qWarning() << "QBackingStore::flush() called for "
203 << window << " which does not have a handle.";
204 return;
205 }
206
207 Q_ASSERT(window == topLevelWindow || topLevelWindow->isAncestorOf(window, QWindow::ExcludeTransients));
208
209 const qreal toNativeFactor = d_ptr->deviceIndependentToNativeFactor();
210
211 QRegion nativeRegion = QHighDpi::scale(region, toNativeFactor);
212 QPoint nativeOffset;
213 if (!offset.isNull()) {
214 nativeOffset = QHighDpi::scale(offset, toNativeFactor);
215 // Under fractional DPR, rounding of region and offset may accumulate to an off-by-one
216 QPoint topLeft = region.boundingRect().topLeft() + offset;
217 QPoint nativeTopLeft = QHighDpi::scale(topLeft, toNativeFactor);
218 QPoint diff = nativeTopLeft - (nativeRegion.boundingRect().topLeft() + nativeOffset);
219 Q_ASSERT(qMax(qAbs(diff.x()), qAbs(diff.y())) <= 1);
220 nativeRegion.translate(diff);
221 }
222 handle()->flush(window, nativeRegion, nativeOffset);
223}
224
231{
232 d_ptr->size = size;
234}
235
240{
241 return d_ptr->size;
242}
243
250bool QBackingStore::scroll(const QRegion &area, int dx, int dy)
251{
252 // Disable scrolling for non-integer scroll deltas. For this case
253 // the existing rendered pixels can't be re-used, and we return
254 // false to signal that a repaint is needed.
255 const qreal toNativeFactor = d_ptr->deviceIndependentToNativeFactor();
256 const qreal nativeDx = QHighDpi::scale(qreal(dx), toNativeFactor);
257 const qreal nativeDy = QHighDpi::scale(qreal(dy), toNativeFactor);
258 if (qFloor(nativeDx) != nativeDx || qFloor(nativeDy) != nativeDy)
259 return false;
260
261 return handle()->scroll(QHighDpi::scale(area, toNativeFactor), nativeDx, nativeDy);
262}
263
268{
269 d_ptr->staticContents = region;
270}
271
277{
278 return d_ptr->staticContents;
279}
280
285{
286 return !d_ptr->staticContents.isEmpty();
287}
288
289void Q_GUI_EXPORT qt_scrollRectInImage(QImage &img, const QRect &rect, const QPoint &offset)
290{
291 // make sure we don't detach
292 uchar *mem = const_cast<uchar*>(img.constBits());
293
294 qsizetype lineskip = img.bytesPerLine();
295 int depth = img.depth() >> 3;
296
297 const QRect imageRect(0, 0, img.width(), img.height());
298 const QRect sourceRect = rect.intersected(imageRect).intersected(imageRect.translated(-offset));
299 if (sourceRect.isEmpty())
300 return;
301
302 const QRect destRect = sourceRect.translated(offset);
303 Q_ASSERT_X(imageRect.contains(destRect), "qt_scrollRectInImage",
304 "The sourceRect should already account for clipping, both pre and post scroll");
305
306 const uchar *src;
307 uchar *dest;
308
309 if (sourceRect.top() < destRect.top()) {
310 src = mem + sourceRect.bottom() * lineskip + sourceRect.left() * depth;
311 dest = mem + (destRect.top() + sourceRect.height() - 1) * lineskip + destRect.left() * depth;
312 lineskip = -lineskip;
313 } else {
314 src = mem + sourceRect.top() * lineskip + sourceRect.left() * depth;
315 dest = mem + destRect.top() * lineskip + destRect.left() * depth;
316 }
317
318 const int w = sourceRect.width();
319 int h = sourceRect.height();
320 const int bytes = w * depth;
321
322 // overlapping segments?
323 if (offset.y() == 0 && qAbs(offset.x()) < w) {
324 do {
325 ::memmove(dest, src, bytes);
326 dest += lineskip;
327 src += lineskip;
328 } while (--h);
329 } else {
330 do {
331 ::memcpy(dest, src, bytes);
332 dest += lineskip;
333 src += lineskip;
334 } while (--h);
335 }
336}
337
342{
343 if (!d_ptr->platformBackingStore) {
345 d_ptr->platformBackingStore->setBackingStore(const_cast<QBackingStore*>(this));
346 }
347 return d_ptr->platformBackingStore;
348}
349
IOBluetoothDevice * device
qreal deviceIndependentToNativeFactor() const
qreal backingStoreDevicePixelRatio() const
QPlatformBackingStore * platformBackingStore
QBackingStorePrivate(QWindow *w)
QScopedPointer< QImage > highDpiBackingstore
The QBackingStore class provides a drawing area for QWindow.
QPlatformBackingStore * handle() const
Returns a pointer to the QPlatformBackingStore implementation.
QPaintDevice * paintDevice()
Returns the paint device for this surface.
QWindow * window() const
Returns a pointer to the top-level window associated with this surface.
QRegion staticContents() const
Returns a QRegion representing the area of the window that has static contents.
void beginPaint(const QRegion &)
Begins painting on the backing store surface in the given region.
void flush(const QRegion &region, QWindow *window=nullptr, const QPoint &offset=QPoint())
Flushes the given region from the specified window onto the screen.
void setStaticContents(const QRegion &region)
Set region as the static contents of this window.
void resize(const QSize &size)
Sets the size of the window surface to size.
QBackingStore(QWindow *window)
Constructs an empty surface for the given top-level window.
QSize size() const
Returns the current size of the window surface.
bool hasStaticContents() const
Returns a boolean indicating if this window has static contents or not.
bool scroll(const QRegion &area, int dx, int dy)
Scrolls the given area dx pixels to the right and dy downward; both dx and dy may be negative.
~QBackingStore()
Destroys this surface.
void endPaint()
Ends painting.
static QPlatformIntegration * platformIntegration()
static bool isActive()
static qreal factor(C *context)
\inmodule QtGui
Definition qimage.h:37
DataPtr & data_ptr()
Definition qimage.h:309
QSize size() const
Returns the size of the image, i.e.
void setDevicePixelRatio(qreal scaleFactor)
Sets the device pixel ratio for the image.
Definition qimage.cpp:1488
qreal devicePixelRatio() const
Returns the device pixel ratio for the image.
Definition qimage.cpp:1460
The QPlatformBackingStore class provides the drawing area for top-level windows.
virtual void endPaint()
This function is called after painting onto the surface has ended.
virtual QPaintDevice * paintDevice()=0
Implement this function to return the appropriate paint device.
virtual void beginPaint(const QRegion &)
This function is called before painting onto the surface begins, with the region in which the paintin...
virtual void flush(QWindow *window, const QRegion &region, const QPoint &offset)
Flushes the given region from the specified window.
virtual bool scroll(const QRegion &area, int dx, int dy)
Scrolls the given area dx pixels to the right and dy downward; both dx and dy may be negative.
virtual void resize(const QSize &size, const QRegion &staticContents)=0
virtual QPlatformBackingStore * createPlatformBackingStore(QWindow *window) const =0
Factory function for QPlatformBackingStore.
\inmodule QtCore\reentrant
Definition qpoint.h:23
constexpr int x() const noexcept
Returns the x coordinate of this point.
Definition qpoint.h:127
constexpr int y() const noexcept
Returns the y coordinate of this point.
Definition qpoint.h:132
\inmodule QtCore\reentrant
Definition qrect.h:30
constexpr bool isEmpty() const noexcept
Returns true if the rectangle is empty, otherwise returns false.
Definition qrect.h:166
constexpr int height() const noexcept
Returns the height of the rectangle.
Definition qrect.h:238
constexpr int bottom() const noexcept
Returns the y-coordinate of the rectangle's bottom edge.
Definition qrect.h:181
constexpr QPoint topLeft() const noexcept
Returns the position of the rectangle's top-left corner.
Definition qrect.h:220
constexpr int top() const noexcept
Returns the y-coordinate of the rectangle's top edge.
Definition qrect.h:175
bool contains(const QRect &r, bool proper=false) const noexcept
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qrect.cpp:851
constexpr int left() const noexcept
Returns the x-coordinate of the rectangle's left edge.
Definition qrect.h:172
constexpr int width() const noexcept
Returns the width of the rectangle.
Definition qrect.h:235
constexpr QRect translated(int dx, int dy) const noexcept
Returns a copy of the rectangle that is translated dx along the x axis and dy along the y axis,...
Definition qrect.h:260
The QRegion class specifies a clip region for a painter.
Definition qregion.h:27
QRect boundingRect() const noexcept
Returns the bounding rectangle of this region.
void translate(int dx, int dy)
Translates (moves) the region dx along the X axis and dy along the Y axis.
bool isEmpty() const
Returns true if the region is empty; otherwise returns false.
\inmodule QtCore
T * data() const noexcept
Returns the value of the pointer referenced by this object.
bool isNull() const noexcept
Returns true if this object refers to \nullptr.
void reset(T *other=nullptr) noexcept(noexcept(Cleanup::cleanup(std::declval< T * >())))
Deletes the existing object it is pointing to (if any), and sets its pointer to other.
\inmodule QtCore
Definition qsize.h:25
\inmodule QtGui
Definition qwindow.h:63
rect
[4]
qreal scale(qreal value, qreal scaleFactor, QPointF=QPointF(0, 0))
Combined button and popup list for selecting options.
void Q_GUI_EXPORT qt_scrollRectInImage(QImage &img, const QRect &rect, const QPoint &offset)
static int area(const QSize &s)
Definition qicon.cpp:152
#define qWarning
Definition qlogging.h:162
int qFloor(T v)
Definition qmath.h:42
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
constexpr T qAbs(const T &t)
Definition qnumeric.h:328
GLint GLenum GLsizei GLsizei GLsizei depth
GLfloat GLfloat GLfloat w
[0]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLenum src
GLenum GLuint GLintptr offset
GLfloat GLfloat GLfloat GLfloat h
GLsizei GLsizei GLchar * source
GLint void * img
Definition qopenglext.h:233
static QT_BEGIN_NAMESPACE qreal dpr(const QWindow *w)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define Q_ASSERT_X(cond, x, msg)
Definition qrandom.cpp:48
Q_CORE_EXPORT int qEnvironmentVariableIntValue(const char *varName, bool *ok=nullptr) noexcept
unsigned char uchar
Definition qtypes.h:27
ptrdiff_t qsizetype
Definition qtypes.h:70
double qreal
Definition qtypes.h:92
aWidget window() -> setWindowTitle("New Window Title")
[2]