Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
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:
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
50 QScopedPointer<QImage> highDpiBackingstore;
54 bool downscale = qEnvironmentVariableIntValue("QT_WIDGETS_HIGHDPI_DOWNSCALE") > 0;
55};
56
82 : d_ptr(new QBackingStorePrivate(window))
83{
84 if (window->handle()) {
85 // Create platform backingstore up front if we have a platform window,
86 // otherwise delay the creation until absolutely necessary.
87 handle();
88 }
89}
90
98
104{
105 return d_ptr->window;
106}
107
118{
119 const qreal toNativeFactor = d_ptr->deviceIndependentToNativeFactor();
120
121 if (d_ptr->nativeSize != QHighDpi::scale(size(), toNativeFactor))
122 resize(size());
123
124 QPlatformBackingStore *platformBackingStore = handle();
125 platformBackingStore->beginPaint(QHighDpi::scale(region, toNativeFactor));
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 (!qFuzzyCompare(toNativeFactor, qreal(1)) && device->devType() == QInternal::Image) {
135 QImage *source = static_cast<QImage *>(device);
136 const bool needsNewImage = d_ptr->highDpiBackingstore.isNull()
137 || source->constBits() != d_ptr->highDpiBackingstore->constBits()
138 || source->size() != d_ptr->highDpiBackingstore->size()
139 || source->bytesPerLine() != d_ptr->highDpiBackingstore->bytesPerLine()
140 || source->format() != d_ptr->highDpiBackingstore->format();
141 if (needsNewImage)
143 new QImage(source->bits(), source->width(), source->height(), source->bytesPerLine(), source->format()));
144
146 } else {
147 d_ptr->highDpiBackingstore.reset();
148 }
149}
150
158{
160
162 return d_ptr->highDpiBackingstore.data();
163
164 return device;
165}
166
176{
177 if (paintDevice()->paintingActive())
178 qWarning("QBackingStore::endPaint() called with active painter; did you forget to destroy it or call QPainter::end() on it?");
179
180 handle()->endPaint();
181}
182
198{
199 QWindow *topLevelWindow = this->window();
200
201 if (!window)
202 window = topLevelWindow;
203 if (!window->handle()) {
204 qWarning() << "QBackingStore::flush() called for "
205 << window << " which does not have a handle.";
206 return;
207 }
208
209 Q_ASSERT(window == topLevelWindow || topLevelWindow->isAncestorOf(window, QWindow::ExcludeTransients));
210
211 const qreal toNativeFactor = d_ptr->deviceIndependentToNativeFactor();
212
213 QRegion nativeRegion = QHighDpi::scale(region, toNativeFactor);
214 QPoint nativeOffset;
215 if (!offset.isNull()) {
216 nativeOffset = QHighDpi::scale(offset, toNativeFactor);
217 // Under fractional DPR, rounding of region and offset may accumulate to an off-by-one
218 QPoint topLeft = region.boundingRect().topLeft() + offset;
219 QPoint nativeTopLeft = QHighDpi::scale(topLeft, toNativeFactor);
220 QPoint diff = nativeTopLeft - (nativeRegion.boundingRect().topLeft() + nativeOffset);
221 Q_ASSERT(qMax(qAbs(diff.x()), qAbs(diff.y())) <= 1);
222 nativeRegion.translate(diff);
223 }
224 handle()->flush(window, nativeRegion, nativeOffset);
225}
226
233{
234 const qreal factor = d_ptr->deviceIndependentToNativeFactor();
235 d_ptr->size = size;
236 d_ptr->nativeSize = QHighDpi::scale(size, factor);
237 handle()->resize(d_ptr->nativeSize, QHighDpi::scale(d_ptr->staticContents, factor));
238}
239
244{
245 return d_ptr->size;
246}
247
254bool QBackingStore::scroll(const QRegion &area, int dx, int dy)
255{
256 // Disable scrolling for non-integer scroll deltas. For this case
257 // the existing rendered pixels can't be re-used, and we return
258 // false to signal that a repaint is needed.
259 const qreal toNativeFactor = d_ptr->deviceIndependentToNativeFactor();
260 const qreal nativeDx = QHighDpi::scale(qreal(dx), toNativeFactor);
261 const qreal nativeDy = QHighDpi::scale(qreal(dy), toNativeFactor);
262 if (qFloor(nativeDx) != nativeDx || qFloor(nativeDy) != nativeDy)
263 return false;
264
265 return handle()->scroll(QHighDpi::scale(area, toNativeFactor), nativeDx, nativeDy);
266}
267
272{
273 [[maybe_unused]] static const bool didCheckPlatformSupport = []{
274 const auto *integration = QGuiApplicationPrivate::platformIntegration();
275 if (!integration->hasCapability(QPlatformIntegration::BackingStoreStaticContents))
276 qWarning("QBackingStore::setStaticContents(): Platform does not support static contents");
277 return true;
278 }();
279
280 d_ptr->staticContents = region;
281}
282
288{
289 return d_ptr->staticContents;
290}
291
296{
297 return !d_ptr->staticContents.isEmpty();
298}
299
300void Q_GUI_EXPORT qt_scrollRectInImage(QImage &img, const QRect &rect, const QPoint &offset)
301{
302 // make sure we don't detach
303 uchar *mem = const_cast<uchar*>(img.constBits());
304
305 qsizetype lineskip = img.bytesPerLine();
306 int depth = img.depth() >> 3;
307
308 const QRect imageRect(0, 0, img.width(), img.height());
309 const QRect sourceRect = rect.intersected(imageRect).intersected(imageRect.translated(-offset));
310 if (sourceRect.isEmpty())
311 return;
312
313 const QRect destRect = sourceRect.translated(offset);
314 Q_ASSERT_X(imageRect.contains(destRect), "qt_scrollRectInImage",
315 "The sourceRect should already account for clipping, both pre and post scroll");
316
317 const uchar *src;
318 uchar *dest;
319
320 if (sourceRect.top() < destRect.top()) {
321 src = mem + sourceRect.bottom() * lineskip + sourceRect.left() * depth;
322 dest = mem + (destRect.top() + sourceRect.height() - 1) * lineskip + destRect.left() * depth;
323 lineskip = -lineskip;
324 } else {
325 src = mem + sourceRect.top() * lineskip + sourceRect.left() * depth;
326 dest = mem + destRect.top() * lineskip + destRect.left() * depth;
327 }
328
329 const int w = sourceRect.width();
330 int h = sourceRect.height();
331 const int bytes = w * depth;
332
333 // overlapping segments?
334 if (offset.y() == 0 && qAbs(offset.x()) < w) {
335 do {
336 ::memmove(dest, src, bytes);
337 dest += lineskip;
338 src += lineskip;
339 } while (--h);
340 } else {
341 do {
342 ::memcpy(dest, src, bytes);
343 dest += lineskip;
344 src += lineskip;
345 } while (--h);
346 }
347}
348
353{
354 if (!d_ptr->platformBackingStore) {
355 d_ptr->platformBackingStore = QGuiApplicationPrivate::platformIntegration()->createPlatformBackingStore(d_ptr->window);
356 d_ptr->platformBackingStore->setBackingStore(const_cast<QBackingStore*>(this));
357 }
358 return d_ptr->platformBackingStore;
359}
360
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 qreal factor(C *context)
\inmodule QtGui
Definition qimage.h:37
qsizetype bytesPerLine() const
Returns the number of bytes per image scanline.
Definition qimage.cpp:1560
QSize size() const
Returns the size of the image, i.e.
Format format() const
Returns the format of the image.
Definition qimage.cpp:2162
void setDevicePixelRatio(qreal scaleFactor)
Sets the device pixel ratio for the image.
Definition qimage.cpp:1510
const uchar * constBits() const
Returns a pointer to the first pixel data.
Definition qimage.cpp:1733
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
\inmodule QtCore\reentrant
Definition qpoint.h:25
constexpr int x() const noexcept
Returns the x coordinate of this point.
Definition qpoint.h:130
constexpr int y() const noexcept
Returns the y coordinate of this point.
Definition qpoint.h:135
\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:167
constexpr int height() const noexcept
Returns the height of the rectangle.
Definition qrect.h:239
QRect intersected(const QRect &other) const noexcept
Definition qrect.h:415
constexpr int bottom() const noexcept
Returns the y-coordinate of the rectangle's bottom edge.
Definition qrect.h:182
constexpr QPoint topLeft() const noexcept
Returns the position of the rectangle's top-left corner.
Definition qrect.h:221
constexpr int top() const noexcept
Returns the y-coordinate of the rectangle's top edge.
Definition qrect.h:176
constexpr int left() const noexcept
Returns the x-coordinate of the rectangle's left edge.
Definition qrect.h:173
constexpr int width() const noexcept
Returns the width of the rectangle.
Definition qrect.h:236
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:261
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.
bool isEmpty() const
Returns true if the region is empty; otherwise returns false.
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)
bool qFuzzyCompare(qfloat16 p1, qfloat16 p2) noexcept
Definition qfloat16.h:333
static int area(const QSize &s)
Definition qicon.cpp:153
#define qWarning
Definition qlogging.h:166
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
#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:32
ptrdiff_t qsizetype
Definition qtypes.h:165
double qreal
Definition qtypes.h:187
aWidget window() -> setWindowTitle("New Window Title")
[2]