summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorQt Forward Merge Bot <qt_forward_merge_bot@qt-project.org>2020-04-14 12:27:02 +0200
committerQt Forward Merge Bot <qt_forward_merge_bot@qt-project.org>2020-04-14 12:27:02 +0200
commit6bd24577658c1e2fde21b14147b4ba964890afe1 (patch)
tree2002796555a0fda4069f44b1a0b33282e4be4a94 /src
parent2161414cdf2790d39eeb25fc35e26c966708d4b8 (diff)
parent08d6cb7673aa51bc0532d71db4134f4912e14769 (diff)
Merge remote-tracking branch 'origin/5.12.8' into 5.12
Diffstat (limited to 'src')
-rw-r--r--src/android/jar/src/org/qtproject/qt5/android/QtNative.java128
-rw-r--r--src/corelib/serialization/qxmlstream.g14
-rw-r--r--src/corelib/serialization/qxmlstream_p.h14
-rw-r--r--src/plugins/platforms/cocoa/qcocoabackingstore.h10
-rw-r--r--src/plugins/platforms/cocoa/qcocoabackingstore.mm83
-rw-r--r--src/plugins/platforms/ios/qioscontext.mm7
6 files changed, 174 insertions, 82 deletions
diff --git a/src/android/jar/src/org/qtproject/qt5/android/QtNative.java b/src/android/jar/src/org/qtproject/qt5/android/QtNative.java
index 1d2b70ab5f..a13c233712 100644
--- a/src/android/jar/src/org/qtproject/qt5/android/QtNative.java
+++ b/src/android/jar/src/org/qtproject/qt5/android/QtNative.java
@@ -724,54 +724,66 @@ public class QtNative
public static boolean hasClipboardText()
{
- if (m_clipboardManager != null && m_clipboardManager.hasPrimaryClip()) {
- ClipData primaryClip = m_clipboardManager.getPrimaryClip();
- for (int i = 0; i < primaryClip.getItemCount(); ++i)
- if (primaryClip.getItemAt(i).getText() != null)
- return true;
+ try {
+ if (m_clipboardManager != null && m_clipboardManager.hasPrimaryClip()) {
+ ClipData primaryClip = m_clipboardManager.getPrimaryClip();
+ for (int i = 0; i < primaryClip.getItemCount(); ++i)
+ if (primaryClip.getItemAt(i).getText() != null)
+ return true;
+ }
+ } catch (Exception e) {
+ Log.e(QtTAG, "Failed to get clipboard data", e);
}
return false;
}
private static String getClipboardText()
{
- if (m_clipboardManager != null && m_clipboardManager.hasPrimaryClip()) {
- ClipData primaryClip = m_clipboardManager.getPrimaryClip();
- for (int i = 0; i < primaryClip.getItemCount(); ++i)
- if (primaryClip.getItemAt(i).getText() != null)
- return primaryClip.getItemAt(i).getText().toString();
+ try {
+ if (m_clipboardManager != null && m_clipboardManager.hasPrimaryClip()) {
+ ClipData primaryClip = m_clipboardManager.getPrimaryClip();
+ for (int i = 0; i < primaryClip.getItemCount(); ++i)
+ if (primaryClip.getItemAt(i).getText() != null)
+ return primaryClip.getItemAt(i).getText().toString();
+ }
+ } catch (Exception e) {
+ Log.e(QtTAG, "Failed to get clipboard data", e);
}
return "";
}
private static void updatePrimaryClip(ClipData clipData)
{
- if (m_usePrimaryClip) {
- ClipData clip = m_clipboardManager.getPrimaryClip();
- if (Build.VERSION.SDK_INT >= 26) {
- if (m_addItemMethod == null) {
- Class[] cArg = new Class[2];
- cArg[0] = ContentResolver.class;
- cArg[1] = ClipData.Item.class;
+ try {
+ if (m_usePrimaryClip) {
+ ClipData clip = m_clipboardManager.getPrimaryClip();
+ if (Build.VERSION.SDK_INT >= 26) {
+ if (m_addItemMethod == null) {
+ Class[] cArg = new Class[2];
+ cArg[0] = ContentResolver.class;
+ cArg[1] = ClipData.Item.class;
+ try {
+ m_addItemMethod = m_clipboardManager.getClass().getMethod("addItem", cArg);
+ } catch (Exception e) {
+ }
+ }
+ }
+ if (m_addItemMethod != null) {
try {
- m_addItemMethod = m_clipboardManager.getClass().getMethod("addItem", cArg);
+ m_addItemMethod.invoke(m_activity.getContentResolver(), clipData.getItemAt(0));
} catch (Exception e) {
+ e.printStackTrace();
}
+ } else {
+ clip.addItem(clipData.getItemAt(0));
}
- }
- if (m_addItemMethod != null) {
- try {
- m_addItemMethod.invoke(m_activity.getContentResolver(), clipData.getItemAt(0));
- } catch (Exception e) {
- e.printStackTrace();
- }
+ m_clipboardManager.setPrimaryClip(clip);
} else {
- clip.addItem(clipData.getItemAt(0));
+ m_clipboardManager.setPrimaryClip(clipData);
+ m_usePrimaryClip = true;
}
- m_clipboardManager.setPrimaryClip(clip);
- } else {
- m_clipboardManager.setPrimaryClip(clipData);
- m_usePrimaryClip = true;
+ } catch (Exception e) {
+ Log.e(QtTAG, "Failed to set clipboard data", e);
}
}
@@ -785,22 +797,30 @@ public class QtNative
public static boolean hasClipboardHtml()
{
- if (m_clipboardManager != null && m_clipboardManager.hasPrimaryClip()) {
- ClipData primaryClip = m_clipboardManager.getPrimaryClip();
- for (int i = 0; i < primaryClip.getItemCount(); ++i)
- if (primaryClip.getItemAt(i).getHtmlText() != null)
- return true;
+ try {
+ if (m_clipboardManager != null && m_clipboardManager.hasPrimaryClip()) {
+ ClipData primaryClip = m_clipboardManager.getPrimaryClip();
+ for (int i = 0; i < primaryClip.getItemCount(); ++i)
+ if (primaryClip.getItemAt(i).getHtmlText() != null)
+ return true;
+ }
+ } catch (Exception e) {
+ Log.e(QtTAG, "Failed to get clipboard data", e);
}
return false;
}
private static String getClipboardHtml()
{
- if (m_clipboardManager != null && m_clipboardManager.hasPrimaryClip()) {
- ClipData primaryClip = m_clipboardManager.getPrimaryClip();
- for (int i = 0; i < primaryClip.getItemCount(); ++i)
- if (primaryClip.getItemAt(i).getHtmlText() != null)
- return primaryClip.getItemAt(i).getHtmlText().toString();
+ try {
+ if (m_clipboardManager != null && m_clipboardManager.hasPrimaryClip()) {
+ ClipData primaryClip = m_clipboardManager.getPrimaryClip();
+ for (int i = 0; i < primaryClip.getItemCount(); ++i)
+ if (primaryClip.getItemAt(i).getHtmlText() != null)
+ return primaryClip.getItemAt(i).getHtmlText().toString();
+ }
+ } catch (Exception e) {
+ Log.e(QtTAG, "Failed to get clipboard data", e);
}
return "";
}
@@ -816,11 +836,15 @@ public class QtNative
public static boolean hasClipboardUri()
{
- if (m_clipboardManager != null && m_clipboardManager.hasPrimaryClip()) {
- ClipData primaryClip = m_clipboardManager.getPrimaryClip();
- for (int i = 0; i < primaryClip.getItemCount(); ++i)
- if (primaryClip.getItemAt(i).getUri() != null)
- return true;
+ try {
+ if (m_clipboardManager != null && m_clipboardManager.hasPrimaryClip()) {
+ ClipData primaryClip = m_clipboardManager.getPrimaryClip();
+ for (int i = 0; i < primaryClip.getItemCount(); ++i)
+ if (primaryClip.getItemAt(i).getUri() != null)
+ return true;
+ }
+ } catch (Exception e) {
+ Log.e(QtTAG, "Failed to get clipboard data", e);
}
return false;
}
@@ -828,11 +852,15 @@ public class QtNative
private static String[] getClipboardUris()
{
ArrayList<String> uris = new ArrayList<String>();
- if (m_clipboardManager != null && m_clipboardManager.hasPrimaryClip()) {
- ClipData primaryClip = m_clipboardManager.getPrimaryClip();
- for (int i = 0; i < primaryClip.getItemCount(); ++i)
- if (primaryClip.getItemAt(i).getUri() != null)
- uris.add(primaryClip.getItemAt(i).getUri().toString());
+ try {
+ if (m_clipboardManager != null && m_clipboardManager.hasPrimaryClip()) {
+ ClipData primaryClip = m_clipboardManager.getPrimaryClip();
+ for (int i = 0; i < primaryClip.getItemCount(); ++i)
+ if (primaryClip.getItemAt(i).getUri() != null)
+ uris.add(primaryClip.getItemAt(i).getUri().toString());
+ }
+ } catch (Exception e) {
+ Log.e(QtTAG, "Failed to get clipboard data", e);
}
String[] strings = new String[uris.size()];
strings = uris.toArray(strings);
diff --git a/src/corelib/serialization/qxmlstream.g b/src/corelib/serialization/qxmlstream.g
index 10bfcd491c..5726bafb26 100644
--- a/src/corelib/serialization/qxmlstream.g
+++ b/src/corelib/serialization/qxmlstream.g
@@ -277,9 +277,19 @@ public:
QHash<QStringView, Entity> entityHash;
QHash<QStringView, Entity> parameterEntityHash;
QXmlStreamSimpleStack<Entity *>entityReferenceStack;
+ int entityExpansionLimit = 4096;
+ int entityLength = 0;
inline bool referenceEntity(Entity &entity) {
if (entity.isCurrentlyReferenced) {
- raiseWellFormedError(QXmlStream::tr("Recursive entity detected."));
+ raiseWellFormedError(QXmlStream::tr("Self-referencing entity detected."));
+ return false;
+ }
+ // entityLength represents the amount of additional characters the
+ // entity expands into (can be negative for e.g. &amp;). It's used to
+ // avoid DoS attacks through recursive entity expansions
+ entityLength += entity.value.size() - entity.name.size() - 2;
+ if (entityLength > entityExpansionLimit) {
+ raiseWellFormedError(QXmlStream::tr("Entity expands to more characters than the entity expansion limit."));
return false;
}
entity.isCurrentlyReferenced = true;
@@ -830,6 +840,8 @@ entity_done ::= ENTITY_DONE;
/.
case $rule_number:
entityReferenceStack.pop()->isCurrentlyReferenced = false;
+ if (entityReferenceStack.isEmpty())
+ entityLength = 0;
clearSym();
break;
./
diff --git a/src/corelib/serialization/qxmlstream_p.h b/src/corelib/serialization/qxmlstream_p.h
index 61f501f81b..31053f8e0b 100644
--- a/src/corelib/serialization/qxmlstream_p.h
+++ b/src/corelib/serialization/qxmlstream_p.h
@@ -774,9 +774,19 @@ public:
QHash<QStringView, Entity> entityHash;
QHash<QStringView, Entity> parameterEntityHash;
QXmlStreamSimpleStack<Entity *>entityReferenceStack;
+ int entityExpansionLimit = 4096;
+ int entityLength = 0;
inline bool referenceEntity(Entity &entity) {
if (entity.isCurrentlyReferenced) {
- raiseWellFormedError(QXmlStream::tr("Recursive entity detected."));
+ raiseWellFormedError(QXmlStream::tr("Self-referencing entity detected."));
+ return false;
+ }
+ // entityLength represents the amount of additional characters the
+ // entity expands into (can be negative for e.g. &amp;). It's used to
+ // avoid DoS attacks through recursive entity expansions
+ entityLength += entity.value.size() - entity.name.size() - 2;
+ if (entityLength > entityExpansionLimit) {
+ raiseWellFormedError(QXmlStream::tr("Entity expands to more characters than the entity expansion limit."));
return false;
}
entity.isCurrentlyReferenced = true;
@@ -1308,6 +1318,8 @@ bool QXmlStreamReaderPrivate::parse()
case 10:
entityReferenceStack.pop()->isCurrentlyReferenced = false;
+ if (entityReferenceStack.isEmpty())
+ entityLength = 0;
clearSym();
break;
diff --git a/src/plugins/platforms/cocoa/qcocoabackingstore.h b/src/plugins/platforms/cocoa/qcocoabackingstore.h
index b57deacb57..3d9dfd8359 100644
--- a/src/plugins/platforms/cocoa/qcocoabackingstore.h
+++ b/src/plugins/platforms/cocoa/qcocoabackingstore.h
@@ -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
diff --git a/src/plugins/platforms/cocoa/qcocoabackingstore.mm b/src/plugins/platforms/cocoa/qcocoabackingstore.mm
index 94eb471f5d..6aa0c0182f 100644
--- a/src/plugins/platforms/cocoa/qcocoabackingstore.mm
+++ b/src/plugins/platforms/cocoa/qcocoabackingstore.mm
@@ -394,7 +394,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);
@@ -523,9 +523,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
@@ -560,7 +564,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,
@@ -568,28 +572,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));
-
- // 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" << backBufferSurface
+ << "to" << flushedView.layer << "of" << flushedView;
- 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
@@ -601,6 +587,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)
@@ -734,4 +767,6 @@ QImage *QCALayerBackingStore::GraphicsBuffer::asImage()
return &m_image;
}
+#include "moc_qcocoabackingstore.cpp"
+
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/ios/qioscontext.mm b/src/plugins/platforms/ios/qioscontext.mm
index 535e7d7aa6..cecbb17039 100644
--- a/src/plugins/platforms/ios/qioscontext.mm
+++ b/src/plugins/platforms/ios/qioscontext.mm
@@ -332,11 +332,8 @@ bool QIOSContext::verifyGraphicsHardwareAvailability()
);
});
- if (applicationBackgrounded) {
- static const char warning[] = "OpenGL ES calls are not allowed while an application is backgrounded";
- Q_ASSERT_X(!applicationBackgrounded, "QIOSContext", warning);
- qCWarning(lcQpaGLContext, warning);
- }
+ if (applicationBackgrounded)
+ qCWarning(lcQpaGLContext, "OpenGL ES calls are not allowed while an application is backgrounded");
return !applicationBackgrounded;
}