From 6a3b5059a994ebeee14c3624269c1362a4c3dc98 Mon Sep 17 00:00:00 2001 From: Tarja Sundqvist Date: Mon, 11 Nov 2024 21:37:35 +0200 Subject: Bump version to 5.15.19 Change-Id: Ic5825370abe84eef6636538087fd79e7425c4dcf --- .qmake.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.qmake.conf b/.qmake.conf index 4c3efa2fa2..5317f45206 100644 --- a/.qmake.conf +++ b/.qmake.conf @@ -4,4 +4,4 @@ CONFIG += warning_clean DEFINES += QT_NO_LINKED_LIST DEFINES += QT_NO_JAVA_STYLE_ITERATORS -MODULE_VERSION = 5.15.18 +MODULE_VERSION = 5.15.19 -- cgit v1.2.3 From d2f39184c1dddb67af596accebd732095dfb27e1 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Mon, 29 Aug 2022 19:11:42 +0200 Subject: V4: Do not update proto usage before engine is fully initialized MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Updating the prototype usage is very expensive. We only need to do it once there are lookups. Before the engine is fully initialized there are no lookups. Change-Id: Ic919a1f8955718d417e7747ea72e009d443c42fd Reviewed-by: Fabian Kosmale (cherry picked from commit 4c3098ab106fae8f2ee256950cdbc8b8da29aa1b) Reviewed-by: Olivier De Cannière (cherry picked from commit 52bac40c08e7b18ed91e77af54547bc51ef62062) Reviewed-by: Qt Cherry-pick Bot --- src/qml/jsruntime/qv4engine.cpp | 4 ++++ src/qml/jsruntime/qv4enginebase_p.h | 3 ++- src/qml/jsruntime/qv4lookup.cpp | 33 +++++++++++++++++++++++++++++++++ src/qml/jsruntime/qv4object.cpp | 10 +++++++++- 4 files changed, 48 insertions(+), 2 deletions(-) diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index da683da952..c2309833fb 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -813,6 +813,7 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine) QV4::QObjectWrapper::initializeBindings(this); m_delayedCallQueue.init(this); + isInitialized = true; } ExecutionEngine::~ExecutionEngine() @@ -2046,8 +2047,11 @@ const QSet &ExecutionEngine::illegalNames() const void ExecutionEngine::setQmlEngine(QQmlEngine *engine) { + // Second stage of initialization. We're updating some more prototypes here. + isInitialized = false; m_qmlEngine = engine; initQmlGlobalObject(); + isInitialized = true; } static void freeze_recursive(QV4::ExecutionEngine *v4, QV4::Object *object) diff --git a/src/qml/jsruntime/qv4enginebase_p.h b/src/qml/jsruntime/qv4enginebase_p.h index dd43d91ccf..19c1085406 100644 --- a/src/qml/jsruntime/qv4enginebase_p.h +++ b/src/qml/jsruntime/qv4enginebase_p.h @@ -84,7 +84,8 @@ struct Q_QML_EXPORT EngineBase { #endif quint8 isExecutingInRegExpJIT = false; - quint8 padding[3]; + quint8 isInitialized = false; + quint8 padding[2]; MemoryManager *memoryManager = nullptr; qint32 callDepth = 0; diff --git a/src/qml/jsruntime/qv4lookup.cpp b/src/qml/jsruntime/qv4lookup.cpp index 604a6002c8..1ab0117be9 100644 --- a/src/qml/jsruntime/qv4lookup.cpp +++ b/src/qml/jsruntime/qv4lookup.cpp @@ -75,6 +75,9 @@ ReturnedValue Lookup::resolveGetter(ExecutionEngine *engine, const Object *objec ReturnedValue Lookup::resolvePrimitiveGetter(ExecutionEngine *engine, const Value &object) { + // Otherwise we cannot trust the protoIds + Q_ASSERT(engine->isInitialized); + primitiveLookup.type = object.type(); switch (primitiveLookup.type) { case Value::Undefined_Type: @@ -120,6 +123,9 @@ ReturnedValue Lookup::resolvePrimitiveGetter(ExecutionEngine *engine, const Valu ReturnedValue Lookup::resolveGlobalGetter(ExecutionEngine *engine) { + // Otherwise we cannot trust the protoIds + Q_ASSERT(engine->isInitialized); + Object *o = engine->globalObject; PropertyKey name = engine->identifierTable->asPropertyKey(engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]); protoLookup.protoId = o->internalClass()->protoId; @@ -257,6 +263,9 @@ ReturnedValue Lookup::getter0Inline(Lookup *l, ExecutionEngine *engine, const Va ReturnedValue Lookup::getterProto(Lookup *l, ExecutionEngine *engine, const Value &object) { + // Otherwise we cannot trust the protoIds + Q_ASSERT(engine->isInitialized); + // we can safely cast to a QV4::Object here. If object is actually a string, // the internal class won't match Heap::Object *o = static_cast(object.heapObject()); @@ -314,6 +323,9 @@ ReturnedValue Lookup::getter0MemberDatagetter0MemberData(Lookup *l, ExecutionEng ReturnedValue Lookup::getterProtoTwoClasses(Lookup *l, ExecutionEngine *engine, const Value &object) { + // Otherwise we cannot trust the protoIds + Q_ASSERT(engine->isInitialized); + // we can safely cast to a QV4::Object here. If object is actually a string, // the internal class won't match Heap::Object *o = static_cast(object.heapObject()); @@ -349,6 +361,9 @@ ReturnedValue Lookup::getterAccessor(Lookup *l, ExecutionEngine *engine, const V ReturnedValue Lookup::getterProtoAccessor(Lookup *l, ExecutionEngine *engine, const Value &object) { + // Otherwise we cannot trust the protoIds + Q_ASSERT(engine->isInitialized); + // we can safely cast to a QV4::Object here. If object is actually a string, // the internal class won't match Heap::Object *o = static_cast(object.heapObject()); @@ -365,6 +380,9 @@ ReturnedValue Lookup::getterProtoAccessor(Lookup *l, ExecutionEngine *engine, co ReturnedValue Lookup::getterProtoAccessorTwoClasses(Lookup *l, ExecutionEngine *engine, const Value &object) { + // Otherwise we cannot trust the protoIds + Q_ASSERT(engine->isInitialized); + // we can safely cast to a QV4::Object here. If object is actually a string, // the internal class won't match Heap::Object *o = static_cast(object.heapObject()); @@ -418,6 +436,9 @@ ReturnedValue Lookup::getterQObject(Lookup *lookup, ExecutionEngine *engine, con ReturnedValue Lookup::primitiveGetterProto(Lookup *l, ExecutionEngine *engine, const Value &object) { + // Otherwise we cannot trust the protoIds + Q_ASSERT(engine->isInitialized); + if (object.type() == l->primitiveLookup.type && !object.isObject()) { Heap::Object *o = l->primitiveLookup.proto; if (l->primitiveLookup.protoId == o->internalClass->protoId) @@ -429,6 +450,9 @@ ReturnedValue Lookup::primitiveGetterProto(Lookup *l, ExecutionEngine *engine, c ReturnedValue Lookup::primitiveGetterAccessor(Lookup *l, ExecutionEngine *engine, const Value &object) { + // Otherwise we cannot trust the protoIds + Q_ASSERT(engine->isInitialized); + if (object.type() == l->primitiveLookup.type && !object.isObject()) { Heap::Object *o = l->primitiveLookup.proto; if (l->primitiveLookup.protoId == o->internalClass->protoId) { @@ -460,6 +484,9 @@ ReturnedValue Lookup::globalGetterGeneric(Lookup *l, ExecutionEngine *engine) ReturnedValue Lookup::globalGetterProto(Lookup *l, ExecutionEngine *engine) { + // Otherwise we cannot trust the protoIds + Q_ASSERT(engine->isInitialized); + Heap::Object *o = engine->globalObject->d(); if (l->protoLookup.protoId == o->internalClass->protoId) return l->protoLookup.data->asReturnedValue(); @@ -469,6 +496,9 @@ ReturnedValue Lookup::globalGetterProto(Lookup *l, ExecutionEngine *engine) ReturnedValue Lookup::globalGetterProtoAccessor(Lookup *l, ExecutionEngine *engine) { + // Otherwise we cannot trust the protoIds + Q_ASSERT(engine->isInitialized); + Heap::Object *o = engine->globalObject->d(); if (l->protoLookup.protoId == o->internalClass->protoId) { const Value *getter = l->protoLookup.data; @@ -588,6 +618,9 @@ bool Lookup::setter0setter0(Lookup *l, ExecutionEngine *engine, Value &object, c bool Lookup::setterInsert(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value) { + // Otherwise we cannot trust the protoIds + Q_ASSERT(engine->isInitialized); + Object *o = static_cast(object.managed()); if (o && o->internalClass()->protoId == l->insertionLookup.protoId) { o->setInternalClass(l->insertionLookup.newClass); diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp index 4674b750ed..4714deed43 100644 --- a/src/qml/jsruntime/qv4object.cpp +++ b/src/qml/jsruntime/qv4object.cpp @@ -104,7 +104,9 @@ void Object::setInternalClass(Heap::InternalClass *ic) } } - if (ic->isUsedAsProto()) + // Before the engine is done initializing, we cannot have any lookups. + // Therefore, there is no point in updating the proto IDs. + if (ic->engine->isInitialized && ic->isUsedAsProto()) ic->updateProtoUsage(p); } @@ -770,6 +772,9 @@ ReturnedValue Object::virtualInstanceOf(const Object *typeObject, const Value &v ReturnedValue Object::virtualResolveLookupGetter(const Object *object, ExecutionEngine *engine, Lookup *lookup) { + // Otherwise we cannot trust the protoIds + Q_ASSERT(engine->isInitialized); + Heap::Object *obj = object->d(); PropertyKey name = engine->identifierTable->asPropertyKey(engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[lookup->nameIndex]); if (name.isArrayIndex()) { @@ -805,6 +810,9 @@ ReturnedValue Object::virtualResolveLookupGetter(const Object *object, Execution bool Object::virtualResolveLookupSetter(Object *object, ExecutionEngine *engine, Lookup *lookup, const Value &value) { + // Otherwise we cannot trust the protoIds + Q_ASSERT(engine->isInitialized); + Scope scope(engine); ScopedString name(scope, scope.engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[lookup->nameIndex]); -- cgit v1.2.3 From b870d5cbe5540ba0fb9ca315504af95b4b23dd24 Mon Sep 17 00:00:00 2001 From: Andy Nichols Date: Mon, 19 Aug 2024 15:25:43 +0200 Subject: 2D Renderer: Make sure cachedMirroredPixmap is never dirty when painting When using the software context for Qt Quick scene graph rendering, it was possible that Items using "layer.enabled: = true" would not be up to date if these sub-passes were updated while the tree using them was not visible (Due to update()/updatePaintNode() not being called). If the cachedMirrorPixmap doesn't get updated, then the previous image will be used when the item is painted, which is incorrect, and the update() method will not be called again until the next time the item is dirty. This change makes it where if the cache is still dirty when we start painting, we update it then, because spending a bit more time renderer is still better than rendering the wrong thing. Fixes: QTBUG-114984 Change-Id: I70f9f6d1dfd46d6870a2bee2ae72294e8982b776 Reviewed-by: Laszlo Agocs (cherry picked from commit 29a52df82397fd8a00308f7e34b08059d6affc91) Reviewed-by: Qt Cherry-pick Bot (cherry picked from commit 57cdb43db40569faefef9e42d3ad42f3fc2bc4cd) (cherry picked from commit c996d0fa2364d1a83cdf39927254fe787e2ad14e) (cherry picked from commit 43bb92c4596499741e1b2a9f3f724e7b53058529) Reviewed-by: Andy Nichols --- .../software/qsgsoftwareinternalimagenode.cpp | 36 +++++++++++++--------- .../software/qsgsoftwareinternalimagenode_p.h | 2 +- 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalimagenode.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalimagenode.cpp index 2640e3c944..31a8a4d0ea 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalimagenode.cpp +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalimagenode.cpp @@ -409,21 +409,7 @@ void QSGSoftwareInternalImageNode::setVerticalWrapMode(QSGTexture::WrapMode wrap void QSGSoftwareInternalImageNode::update() { - if (m_cachedMirroredPixmapIsDirty) { - if (m_mirror || m_textureIsLayer) { - QTransform transform( - (m_mirror ? -1 : 1), 0, - 0 , (m_textureIsLayer ? -1 :1), - 0 , 0 - ); - m_cachedMirroredPixmap = pixmap().transformed(transform); - } else { - //Cleanup cached pixmap if necessary - if (!m_cachedMirroredPixmap.isNull()) - m_cachedMirroredPixmap = QPixmap(); - } - m_cachedMirroredPixmapIsDirty = false; - } + updateCachedMirroredPixmap(); } void QSGSoftwareInternalImageNode::preprocess() @@ -457,6 +443,7 @@ void QSGSoftwareInternalImageNode::paint(QPainter *painter) // Disable antialiased clipping. It causes transformed tiles to have gaps. painter->setRenderHint(QPainter::Antialiasing, false); + updateCachedMirroredPixmap(); const QPixmap &pm = m_mirror || m_textureIsLayer ? m_cachedMirroredPixmap : pixmap(); if (m_innerTargetRect != m_targetRect) { @@ -502,4 +489,23 @@ const QPixmap &QSGSoftwareInternalImageNode::pixmap() const return nullPixmap; } +void QSGSoftwareInternalImageNode::updateCachedMirroredPixmap() +{ + if (m_cachedMirroredPixmapIsDirty) { + if (m_mirror || m_textureIsLayer) { + QTransform transform( + (m_mirror ? -1 : 1), 0, + 0 , (m_textureIsLayer ? -1 :1), + 0 , 0 + ); + m_cachedMirroredPixmap = pixmap().transformed(transform); + } else { + //Cleanup cached pixmap if necessary + if (!m_cachedMirroredPixmap.isNull()) + m_cachedMirroredPixmap = QPixmap(); + } + m_cachedMirroredPixmapIsDirty = false; + } +} + QT_END_NAMESPACE diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalimagenode_p.h b/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalimagenode_p.h index 8fe4b5916a..14330eda7a 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalimagenode_p.h +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalimagenode_p.h @@ -128,7 +128,7 @@ public: const QPixmap &pixmap() const; private: - + void updateCachedMirroredPixmap(); QRectF m_targetRect; QRectF m_innerTargetRect; QRectF m_innerSourceRect; -- cgit v1.2.3 From a2b9557832ce5ee5a05f4e088fd7c8bf0dcd1c1b Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Thu, 13 Mar 2025 08:06:11 +0100 Subject: Fix divide by zero when processing invalid arcs If the start point and end point are equal, we will end up with a divide by zero later. df97b6b2de6282bd6422f1e531a42475dadc980d in Qt Base added an assert which detected this. Fixes: QTBUG-134664 Change-Id: Ifc00d988713b8495942a1445e69d35c44605dcbc Reviewed-by: Eirik Aavitsland (cherry picked from commit 7ca1222296a9650f24979df57cc2c974a7e571ed) Reviewed-by: Qt Cherry-pick Bot (cherry picked from commit 3e8837472e5fc9649f8eb8b21f48bac6bbb7d4e4) (cherry picked from commit 1d61b3c063dedbbf05ee25de27c9ddda6793cf23) (cherry picked from commit ef739f6046c66d0682f5250a4301ca8aca88655b) --- src/quick/util/qquickpath.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/quick/util/qquickpath.cpp b/src/quick/util/qquickpath.cpp index 71331c0a4a..292d777036 100644 --- a/src/quick/util/qquickpath.cpp +++ b/src/quick/util/qquickpath.cpp @@ -2031,6 +2031,8 @@ void QQuickPathArc::addToPath(QPainterPath &path, const QQuickPathData &data) { const QPointF &startPoint = path.currentPosition(); const QPointF &endPoint = positionForCurve(data, startPoint); + if (startPoint == endPoint) + return; QQuickSvgParser::pathArc(path, _radiusX, _radiusY, -- cgit v1.2.3 From fdcdacf5c5473fb62eac60bd185feafe7f2ddcef Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Thu, 9 Jun 2022 21:23:04 +0200 Subject: Fix the build with tracing enabled line() and column() are functions to be called, not variables. Task-number: QTBUG-102862 Change-Id: I0d447f1b3723efbcac7180c5253fd1ac2bd295ad Reviewed-by: Fabian Kosmale (cherry picked from commit 2b64cb61ba4993049efe7b6c2608c90a05fcc22c) Reviewed-by: Qt Cherry-pick Bot (cherry picked from commit 3d722f3a85f617423270aa98629d9bc62bc6587a) --- src/qml/jsruntime/qv4vme_moth.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp index 3c428ef953..f0c2ff227e 100644 --- a/src/qml/jsruntime/qv4vme_moth.cpp +++ b/src/qml/jsruntime/qv4vme_moth.cpp @@ -435,8 +435,8 @@ ReturnedValue VME::exec(CppStackFrame *frame, ExecutionEngine *engine) Function *function = frame->v4Function; Q_TRACE_SCOPE(QQmlV4_function_call, engine, function->name()->toQString(), function->executableCompilationUnit()->fileName(), - function->compiledFunction->location.line, - function->compiledFunction->location.column); + function->compiledFunction->location.line(), + function->compiledFunction->location.column()); Profiling::FunctionCallProfiler profiler(engine, function); // start execution profiling QV4::Debugging::Debugger *debugger = engine->debugger(); -- cgit v1.2.3 From beebdbf5ef482d9253709158aac099a1247df24a Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Tue, 1 Apr 2025 13:25:37 +0800 Subject: Fix division by zero in QQuickSvgParser df97b6b2de6282bd6422f1e531a42475dadc980d in Qt Base added an assert which detected this. This patch adds an early return if we're about to divide by zero, similar to 7ca1222296a9650f24979df57cc2c974a7e571ed. It also amends that patch to move the start point == end point check to pathArc(), since it's called from more places. Fixes: QTBUG-135387 Change-Id: If9c5655d5e736825e98d3e93201bf889a1785e49 Reviewed-by: Eskil Abrahamsen Blomfeldt (cherry picked from commit 8d597bea22728268beff583a79e2005b1df423bf) Reviewed-by: Eirik Aavitsland (cherry picked from commit 503cbb4ad07a06941761607f46964c9540595225) Reviewed-by: Volker Hilsheimer (cherry picked from commit 5482f67da7705ede34c987c61ee45e3221d7b2b7) (cherry picked from commit 98edc631a960bca758dde79ec5e63496eaed1b55) --- src/quick/util/qquickpath.cpp | 2 -- src/quick/util/qquicksvgparser.cpp | 12 ++++++++++++ .../qquickshape/data/changeElementsImperatively.qml | 21 +++++++++++++++++++++ tests/auto/quick/qquickshape/tst_qquickshape.cpp | 10 ++++++++++ 4 files changed, 43 insertions(+), 2 deletions(-) create mode 100644 tests/auto/quick/qquickshape/data/changeElementsImperatively.qml diff --git a/src/quick/util/qquickpath.cpp b/src/quick/util/qquickpath.cpp index 292d777036..71331c0a4a 100644 --- a/src/quick/util/qquickpath.cpp +++ b/src/quick/util/qquickpath.cpp @@ -2031,8 +2031,6 @@ void QQuickPathArc::addToPath(QPainterPath &path, const QQuickPathData &data) { const QPointF &startPoint = path.currentPosition(); const QPointF &endPoint = positionForCurve(data, startPoint); - if (startPoint == endPoint) - return; QQuickSvgParser::pathArc(path, _radiusX, _radiusY, diff --git a/src/quick/util/qquicksvgparser.cpp b/src/quick/util/qquicksvgparser.cpp index 3215753027..c1607be86a 100644 --- a/src/quick/util/qquicksvgparser.cpp +++ b/src/quick/util/qquicksvgparser.cpp @@ -195,6 +195,10 @@ void QQuickSvgParser::pathArc(QPainterPath &path, qreal y, qreal curx, qreal cury) { + // Check if the start point is equal to the end point. + if (QPointF(curx, cury) == QPointF(x, y)) + return; + qreal sin_th, cos_th; qreal a00, a01, a10, a11; qreal x0, y0, x1, y1, xc, yc; @@ -205,6 +209,14 @@ void QQuickSvgParser::pathArc(QPainterPath &path, rx = qAbs(rx); ry = qAbs(ry); + // Avoid nans and division by zero. + if (qFuzzyIsNull(rx) || qFuzzyIsNull(ry)) { + // https://www.w3.org/TR/SVG/paths.html#ArcOutOfRangeParameters says: + // "If either rx or ry is 0, then this arc is treated as a straight line + // segment (a "lineto") joining the endpoints." + path.lineTo(x, y); + return; + } sin_th = qSin(qDegreesToRadians(x_axis_rotation)); cos_th = qCos(qDegreesToRadians(x_axis_rotation)); diff --git a/tests/auto/quick/qquickshape/data/changeElementsImperatively.qml b/tests/auto/quick/qquickshape/data/changeElementsImperatively.qml new file mode 100644 index 0000000000..129be7222a --- /dev/null +++ b/tests/auto/quick/qquickshape/data/changeElementsImperatively.qml @@ -0,0 +1,21 @@ +import QtQuick +import QtQuick.Shapes + +Shape { + width: 640 + height: 480 + + Component.onCompleted: { + bottomPathLine.x = 20 + } + + ShapePath { + PathLine {} + PathLine { + id: bottomPathLine + } + PathArc {} + PathLine {} + PathArc {} + } +} diff --git a/tests/auto/quick/qquickshape/tst_qquickshape.cpp b/tests/auto/quick/qquickshape/tst_qquickshape.cpp index 578d8d4e3a..0e20cec9ab 100644 --- a/tests/auto/quick/qquickshape/tst_qquickshape.cpp +++ b/tests/auto/quick/qquickshape/tst_qquickshape.cpp @@ -87,6 +87,7 @@ private slots: void multilineDataTypes_data(); void multilineDataTypes(); void multilineStronglyTyped(); + void changeElementsImperatively(); private: QVector m_lowPolyLogo; @@ -707,6 +708,15 @@ void tst_QQuickShape::multilineStronglyTyped() } } +void tst_QQuickShape::changeElementsImperatively() +{ + // Shouldn't crash. + QScopedPointer window(createView()); + window->setSource(testFileUrl("changeElementsImperatively.qml")); + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window.data())); +} + QTEST_MAIN(tst_QQuickShape) #include "tst_qquickshape.moc" -- cgit v1.2.3