Merge remote-tracking branch 'origin/5.14' into 5.15

Conflicts:
	src/corelib/serialization/qcborvalue.cpp

Change-Id: I539d8cae5fd413b8a6c9c5d8a6364c79c8133a0a
This commit is contained in:
Qt Forward Merge Bot 2020-03-27 01:00:18 +01:00 committed by Edward Welbourne
commit 4752bd7718
7 changed files with 217 additions and 72 deletions

View File

@ -845,7 +845,7 @@ EGLint SwapChain11::copyOffscreenToBackbuffer(const gl::Context *context,
stateManager->setRenderTarget(mBackBufferRTView.get(), nullptr);
// Set the viewport
stateManager->setSimpleViewport(mWidth, mHeight);
stateManager->setSimpleViewport(width, height);
// Apply textures
stateManager->setSimplePixelTextureAndSampler(mOffscreenSRView, mPassThroughSampler);

View File

@ -0,0 +1,27 @@
From 029d42d1049dcde7950c11fb9adf07c07a8c4c02 Mon Sep 17 00:00:00 2001
From: Oliver Wolff <oliver.wolff@qt.io>
Date: Wed, 18 Mar 2020 10:56:53 +0100
Subject: [PATCH] ANGLE: Fix resizing of windows (Take 2)
Task-number: QTBUG-62475
Change-Id: I0ea17e7875906508941ae64bb396a4236928b0f9
---
.../angle/src/libANGLE/renderer/d3d/d3d11/SwapChain11.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/SwapChain11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/SwapChain11.cpp
index e8f13b388f..9ece77ecbc 100644
--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/SwapChain11.cpp
+++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/SwapChain11.cpp
@@ -845,7 +845,7 @@ EGLint SwapChain11::copyOffscreenToBackbuffer(const gl::Context *context,
stateManager->setRenderTarget(mBackBufferRTView.get(), nullptr);
// Set the viewport
- stateManager->setSimpleViewport(mWidth, mHeight);
+ stateManager->setSimpleViewport(width, height);
// Apply textures
stateManager->setSimplePixelTextureAndSampler(mOffscreenSRView, mPassThroughSampler);
--
2.20.1.windows.1

View File

@ -844,11 +844,6 @@ static QCborValue::Type convertToExtendedType(QCborContainerPrivate *d)
return QCborValue::Tag;
}
#if QT_CONFIG(cborstreamreader)
// in qcborstream.cpp
extern void qt_cbor_stream_set_error(QCborStreamReaderPrivate *d, QCborError error);
#endif
#if QT_CONFIG(cborstreamwriter)
static void writeDoubleToCbor(QCborStreamWriter &writer, double d, QCborValue::EncodingOptions opt)
{
@ -1462,23 +1457,59 @@ static Element decodeBasicValueFromCbor(QCborStreamReader &reader)
return e;
}
static inline QCborContainerPrivate *createContainerFromCbor(QCborStreamReader &reader)
static inline QCborContainerPrivate *createContainerFromCbor(QCborStreamReader &reader, int remainingRecursionDepth)
{
auto d = new QCborContainerPrivate;
d->ref.storeRelaxed(1);
d->decodeFromCbor(reader);
if (Q_UNLIKELY(remainingRecursionDepth == 0)) {
QCborContainerPrivate::setErrorInReader(reader, { QCborError::NestingTooDeep });
return nullptr;
}
QCborContainerPrivate *d = nullptr;
int mapShift = reader.isMap() ? 1 : 0;
if (reader.isLengthKnown()) {
quint64 len = reader.length();
// Clamp allocation to 1M elements (avoids crashing due to corrupt
// stream or loss of precision when converting from quint64 to
// QVector::size_type).
len = qMin(len, quint64(1024 * 1024 - 1));
if (len) {
d = new QCborContainerPrivate;
d->ref.storeRelaxed(1);
d->elements.reserve(qsizetype(len) << mapShift);
}
} else {
d = new QCborContainerPrivate;
d->ref.storeRelaxed(1);
}
reader.enterContainer();
if (reader.lastError() != QCborError::NoError)
return d;
while (reader.hasNext() && reader.lastError() == QCborError::NoError)
d->decodeValueFromCbor(reader, remainingRecursionDepth - 1);
if (reader.lastError() == QCborError::NoError)
reader.leaveContainer();
return d;
}
static QCborValue taggedValueFromCbor(QCborStreamReader &reader)
static QCborValue taggedValueFromCbor(QCborStreamReader &reader, int remainingRecursionDepth)
{
if (Q_UNLIKELY(remainingRecursionDepth == 0)) {
QCborContainerPrivate::setErrorInReader(reader, { QCborError::NestingTooDeep });
return QCborValue::Invalid;
}
auto d = new QCborContainerPrivate;
d->append(reader.toTag());
reader.next();
if (reader.lastError() == QCborError::NoError) {
// decode tagged value
d->decodeValueFromCbor(reader);
d->decodeValueFromCbor(reader, remainingRecursionDepth - 1);
}
QCborValue::Type type;
@ -1494,6 +1525,13 @@ static QCborValue taggedValueFromCbor(QCborStreamReader &reader)
return QCborContainerPrivate::makeValue(type, -1, d);
}
// in qcborstream.cpp
extern void qt_cbor_stream_set_error(QCborStreamReaderPrivate *d, QCborError error);
inline void QCborContainerPrivate::setErrorInReader(QCborStreamReader &reader, QCborError error)
{
qt_cbor_stream_set_error(reader.d.data(), error);
}
void QCborContainerPrivate::decodeStringFromCbor(QCborStreamReader &reader)
{
auto addByteData_local = [this](QByteArray::size_type len) -> qint64 {
@ -1538,7 +1576,7 @@ void QCborContainerPrivate::decodeStringFromCbor(QCborStreamReader &reader)
return; // error
if (len != rawlen) {
// truncation
qt_cbor_stream_set_error(reader.d.data(), { QCborError::DataTooLarge });
setErrorInReader(reader, { QCborError::DataTooLarge });
return;
}
@ -1548,7 +1586,7 @@ void QCborContainerPrivate::decodeStringFromCbor(QCborStreamReader &reader)
e.value = addByteData_local(len);
if (e.value < 0) {
// overflow
qt_cbor_stream_set_error(reader.d.data(), { QCborError::DataTooLarge });
setErrorInReader(reader, { QCborError::DataTooLarge });
return;
}
}
@ -1562,7 +1600,7 @@ void QCborContainerPrivate::decodeStringFromCbor(QCborStreamReader &reader)
auto utf8result = QUtf8::isValidUtf8(dataPtr() + data.size() - len, len);
if (!utf8result.isValidUtf8) {
r.status = QCborStreamReader::Error;
qt_cbor_stream_set_error(reader.d.data(), { QCborError::InvalidUtf8String });
setErrorInReader(reader, { QCborError::InvalidUtf8String });
break;
}
isAscii = isAscii && utf8result.isValidAscii;
@ -1586,7 +1624,7 @@ void QCborContainerPrivate::decodeStringFromCbor(QCborStreamReader &reader)
// error
r.status = QCborStreamReader::Error;
qt_cbor_stream_set_error(reader.d.data(), { QCborError::DataTooLarge });
setErrorInReader(reader, { QCborError::DataTooLarge });
}
if (r.status == QCborStreamReader::Error) {
@ -1612,9 +1650,10 @@ void QCborContainerPrivate::decodeStringFromCbor(QCborStreamReader &reader)
elements.append(e);
}
void QCborContainerPrivate::decodeValueFromCbor(QCborStreamReader &reader)
void QCborContainerPrivate::decodeValueFromCbor(QCborStreamReader &reader, int remainingRecursionDepth)
{
switch (reader.type()) {
QCborStreamReader::Type t = reader.type();
switch (t) {
case QCborStreamReader::UnsignedInteger:
case QCborStreamReader::NegativeInteger:
case QCborStreamReader::SimpleType:
@ -1631,37 +1670,17 @@ void QCborContainerPrivate::decodeValueFromCbor(QCborStreamReader &reader)
case QCborStreamReader::Array:
case QCborStreamReader::Map:
return append(makeValue(t == QCborStreamReader::Array ? QCborValue::Array : QCborValue::Map, -1,
createContainerFromCbor(reader, remainingRecursionDepth),
MoveContainer));
case QCborStreamReader::Tag:
return append(QCborValue::fromCbor(reader));
return append(taggedValueFromCbor(reader, remainingRecursionDepth));
case QCborStreamReader::Invalid:
return; // probably a decode error
}
}
void QCborContainerPrivate::decodeFromCbor(QCborStreamReader &reader)
{
int mapShift = reader.isMap() ? 1 : 0;
if (reader.isLengthKnown()) {
quint64 len = reader.length();
// Clamp allocation to 1M elements (avoids crashing due to corrupt
// stream or loss of precision when converting from quint64 to
// QVector::size_type).
len = qMin(len, quint64(1024 * 1024 - 1));
elements.reserve(qsizetype(len) << mapShift);
}
reader.enterContainer();
if (reader.lastError() != QCborError::NoError)
return;
while (reader.hasNext() && reader.lastError() == QCborError::NoError)
decodeValueFromCbor(reader);
if (reader.lastError() == QCborError::NoError)
reader.leaveContainer();
}
#endif // QT_CONFIG(cborstreamreader)
/*!
@ -2363,6 +2382,8 @@ QCborValueRef QCborValue::operator[](qint64 key)
}
#if QT_CONFIG(cborstreamreader)
enum { MaximumRecursionDepth = 1024 };
/*!
Decodes one item from the CBOR stream found in \a reader and returns the
equivalent representation. This function is recursive: if the item is a map
@ -2423,12 +2444,12 @@ QCborValue QCborValue::fromCbor(QCborStreamReader &reader)
case QCborStreamReader::Map:
result.n = -1;
result.t = reader.isArray() ? Array : Map;
result.container = createContainerFromCbor(reader);
result.container = createContainerFromCbor(reader, MaximumRecursionDepth);
break;
// tag
case QCborStreamReader::Tag:
result = taggedValueFromCbor(reader);
result = taggedValueFromCbor(reader, MaximumRecursionDepth);
break;
}

View File

@ -405,9 +405,9 @@ public:
elements.remove(idx);
}
void decodeValueFromCbor(QCborStreamReader &reader);
void decodeFromCbor(QCborStreamReader &reader);
void decodeValueFromCbor(QCborStreamReader &reader, int remainiingStackDepth);
void decodeStringFromCbor(QCborStreamReader &reader);
static inline void setErrorInReader(QCborStreamReader &reader, QCborError error);
};
QT_END_NAMESPACE

View File

@ -47,6 +47,8 @@
#include <QScopedPointer>
#include "qiosurfacegraphicsbuffer.h"
#include <unordered_map>
QT_BEGIN_NAMESPACE
class QCocoaBackingStore : public QRasterBackingStore
@ -71,8 +73,9 @@ private:
void redrawRoundedBottomCorners(CGRect) const;
};
class QCALayerBackingStore : public QCocoaBackingStore
class QCALayerBackingStore : public QObject, public QCocoaBackingStore
{
Q_OBJECT
public:
QCALayerBackingStore(QWindow *window);
~QCALayerBackingStore();
@ -119,6 +122,11 @@ private:
QMacNotificationObserver m_backingPropertiesObserver;
std::list<std::unique_ptr<GraphicsBuffer>> m_buffers;
void flushSubWindow(QWindow *window);
std::unordered_map<QWindow*, std::unique_ptr<QCALayerBackingStore>> m_subWindowBackingstores;
void windowDestroyed(QObject *object);
bool m_clearSurfaceOnPaint = true;
};
QT_END_NAMESPACE

View File

@ -382,7 +382,7 @@ void QCALayerBackingStore::beginPaint(const QRegion &region)
// Although undocumented, QBackingStore::beginPaint expects the painted region
// to be cleared before use if the window has a surface format with an alpha.
// Fresh IOSurfaces are already cleared, so we don't need to clear those.
if (!bufferWasRecreated && window()->format().hasAlpha()) {
if (m_clearSurfaceOnPaint && !bufferWasRecreated && window()->format().hasAlpha()) {
qCDebug(lcQpaBackingStore) << "Clearing" << region << "before use";
QPainter painter(m_buffers.back()->asImage());
painter.setCompositionMode(QPainter::CompositionMode_Source);
@ -511,9 +511,13 @@ void QCALayerBackingStore::flush(QWindow *flushedWindow, const QRegion &region,
if (!prepareForFlush())
return;
if (flushedWindow != window()) {
flushSubWindow(flushedWindow);
return;
}
QMacAutoReleasePool pool;
NSView *backingStoreView = static_cast<QCocoaWindow *>(window()->handle())->view();
NSView *flushedView = static_cast<QCocoaWindow *>(flushedWindow->handle())->view();
// If the backingstore is just flushed, without being painted to first, then we may
@ -548,7 +552,7 @@ void QCALayerBackingStore::flush(QWindow *flushedWindow, const QRegion &region,
// are committed as part of a display-cycle instead of on the next runloop pass. This
// means CA won't try to throttle us if we flush too fast, and we'll coalesce our flush
// with other pending view and layer updates.
backingStoreView.window.viewsNeedDisplay = YES;
flushedView.window.viewsNeedDisplay = YES;
if (window()->format().swapBehavior() == QSurfaceFormat::SingleBuffer) {
// The private API [CALayer reloadValueForKeyPath:@"contents"] would be preferable,
@ -556,28 +560,10 @@ void QCALayerBackingStore::flush(QWindow *flushedWindow, const QRegion &region,
flushedView.layer.contents = nil;
}
if (flushedView == backingStoreView) {
qCInfo(lcQpaBackingStore) << "Flushing" << backBufferSurface
<< "to" << flushedView.layer << "of" << flushedView;
flushedView.layer.contents = backBufferSurface;
} else {
auto subviewRect = [flushedView convertRect:flushedView.bounds toView:backingStoreView];
auto scale = flushedView.layer.contentsScale;
subviewRect = CGRectApplyAffineTransform(subviewRect, CGAffineTransformMakeScale(scale, scale));
qCInfo(lcQpaBackingStore) << "Flushing" << backBufferSurface
<< "to" << flushedView.layer << "of" << flushedView;
// We make a copy of the image data up front, which means we don't
// need to mark the IOSurface as being in use. FIXME: Investigate
// if there's a cheaper way to get sub-image data to a layer.
m_buffers.back()->lock(QPlatformGraphicsBuffer::SWReadAccess);
QImage subImage = m_buffers.back()->asImage()->copy(QRectF::fromCGRect(subviewRect).toRect());
m_buffers.back()->unlock();
qCInfo(lcQpaBackingStore) << "Flushing" << subImage
<< "to" << flushedView.layer << "of subview" << flushedView;
QCFType<CGImageRef> cgImage = CGImageCreateCopyWithColorSpace(
QCFType<CGImageRef>(subImage.toCGImage()), colorSpace());
flushedView.layer.contents = (__bridge id)static_cast<CGImageRef>(cgImage);
}
flushedView.layer.contents = backBufferSurface;
// Since we may receive multiple flushes before a new frame is started, we do not
// swap any buffers just yet. Instead we check in the next beginPaint if the layer's
@ -589,6 +575,53 @@ void QCALayerBackingStore::flush(QWindow *flushedWindow, const QRegion &region,
// the window server.
}
void QCALayerBackingStore::flushSubWindow(QWindow *subWindow)
{
qCInfo(lcQpaBackingStore) << "Flushing sub-window" << subWindow
<< "via its own backingstore";
auto &subWindowBackingStore = m_subWindowBackingstores[subWindow];
if (!subWindowBackingStore) {
subWindowBackingStore.reset(new QCALayerBackingStore(subWindow));
QObject::connect(subWindow, &QObject::destroyed, this, &QCALayerBackingStore::windowDestroyed);
subWindowBackingStore->m_clearSurfaceOnPaint = false;
}
auto subWindowSize = subWindow->size();
static const auto kNoStaticContents = QRegion();
subWindowBackingStore->resize(subWindowSize, kNoStaticContents);
auto subWindowLocalRect = QRect(QPoint(), subWindowSize);
subWindowBackingStore->beginPaint(subWindowLocalRect);
QPainter painter(subWindowBackingStore->m_buffers.back()->asImage());
painter.setCompositionMode(QPainter::CompositionMode_Source);
NSView *backingStoreView = static_cast<QCocoaWindow *>(window()->handle())->view();
NSView *flushedView = static_cast<QCocoaWindow *>(subWindow->handle())->view();
auto subviewRect = [flushedView convertRect:flushedView.bounds toView:backingStoreView];
auto scale = flushedView.layer.contentsScale;
subviewRect = CGRectApplyAffineTransform(subviewRect, CGAffineTransformMakeScale(scale, scale));
m_buffers.back()->lock(QPlatformGraphicsBuffer::SWReadAccess);
const QImage *backingStoreImage = m_buffers.back()->asImage();
painter.drawImage(subWindowLocalRect, *backingStoreImage, QRectF::fromCGRect(subviewRect));
m_buffers.back()->unlock();
painter.end();
subWindowBackingStore->endPaint();
subWindowBackingStore->flush(subWindow, subWindowLocalRect, QPoint());
qCInfo(lcQpaBackingStore) << "Done flushing sub-window" << subWindow;
}
void QCALayerBackingStore::windowDestroyed(QObject *object)
{
auto *window = static_cast<QWindow*>(object);
qCInfo(lcQpaBackingStore) << "Removing backingstore for sub-window" << window;
m_subWindowBackingstores.erase(window);
}
#ifndef QT_NO_OPENGL
void QCALayerBackingStore::composeAndFlush(QWindow *window, const QRegion &region, const QPoint &offset,
QPlatformTextureList *textures, bool translucentBackground)
@ -722,4 +755,6 @@ QImage *QCALayerBackingStore::GraphicsBuffer::asImage()
return &m_image;
}
#include "moc_qcocoabackingstore.cpp"
QT_END_NAMESPACE

View File

@ -102,6 +102,8 @@ private slots:
void fromCborStreamReaderIODevice();
void validation_data();
void validation();
void recursionLimit_data();
void recursionLimit();
void toDiagnosticNotation_data();
void toDiagnosticNotation();
@ -1720,6 +1722,58 @@ void tst_QCborValue::validation()
}
}
void tst_QCborValue::recursionLimit_data()
{
constexpr int RecursionAttempts = 4096;
QTest::addColumn<QByteArray>("data");
QByteArray arrays(RecursionAttempts, char(0x81));
QByteArray _arrays(RecursionAttempts, char(0x9f));
QByteArray maps(RecursionAttempts, char(0xa1));
QByteArray _maps(RecursionAttempts, char(0xbf));
QByteArray tags(RecursionAttempts, char(0xc0));
QTest::newRow("array-nesting-too-deep") << arrays;
QTest::newRow("_array-nesting-too-deep") << _arrays;
QTest::newRow("map-nesting-too-deep") << maps;
QTest::newRow("_map-nesting-too-deep") << _maps;
QTest::newRow("tag-nesting-too-deep") << tags;
QByteArray mixed(5 * RecursionAttempts, Qt::Uninitialized);
char *ptr = mixed.data();
for (int i = 0; i < RecursionAttempts; ++i) {
quint8 type = qBound(quint8(QCborStreamReader::Array), quint8(i & 0x80), quint8(QCborStreamReader::Tag));
quint8 additional_info = i & 0x1f;
if (additional_info == 0x1f)
(void)additional_info; // leave it
else if (additional_info > 0x1a)
additional_info = 0x1a;
else if (additional_info < 1)
additional_info = 1;
*ptr++ = type | additional_info;
if (additional_info == 0x18) {
*ptr++ = uchar(i);
} else if (additional_info == 0x19) {
qToBigEndian(ushort(i), ptr);
ptr += 2;
} else if (additional_info == 0x1a) {
qToBigEndian(uint(i), ptr);
ptr += 4;
}
}
QTest::newRow("mixed-nesting-too-deep") << mixed;
}
void tst_QCborValue::recursionLimit()
{
QFETCH(QByteArray, data);
QCborParserError error;
QCborValue decoded = QCborValue::fromCbor(data, &error);
QCOMPARE(error.error, QCborError::NestingTooDeep);
}
void tst_QCborValue::toDiagnosticNotation_data()
{
QTest::addColumn<QCborValue>("v");