diff options
| author | Tarja Sundqvist <tarja.sundqvist@qt.io> | 2025-11-19 22:21:07 +0200 |
|---|---|---|
| committer | Tarja Sundqvist <tarja.sundqvist@qt.io> | 2025-11-19 22:21:07 +0200 |
| commit | dbb2e3b6bc9b51f76f241c7d108c466d78ef5695 (patch) | |
| tree | 1fa3393e75dfda78114c2f225422f6348b45df27 | |
| parent | 2d723c3626fed493b203924260dbc0757a8ec7e7 (diff) | |
| parent | beebdbf5ef482d9253709158aac099a1247df24a (diff) | |
Merge tag 'v5.15.19-lts' into tqtc/lts-5.15-opensourcev5.15.19-lts-lgpl5.15
Qt 5.15.19-lts release
Change-Id: I94e8187ca3dbe222dc129d1f4eaae754a0d1df46
| -rw-r--r-- | .qmake.conf | 2 | ||||
| -rw-r--r-- | src/qml/jsruntime/qv4engine.cpp | 4 | ||||
| -rw-r--r-- | src/qml/jsruntime/qv4enginebase_p.h | 3 | ||||
| -rw-r--r-- | src/qml/jsruntime/qv4lookup.cpp | 33 | ||||
| -rw-r--r-- | src/qml/jsruntime/qv4object.cpp | 10 | ||||
| -rw-r--r-- | src/qml/jsruntime/qv4vme_moth.cpp | 4 | ||||
| -rw-r--r-- | src/quick/scenegraph/adaptations/software/qsgsoftwareinternalimagenode.cpp | 36 | ||||
| -rw-r--r-- | src/quick/scenegraph/adaptations/software/qsgsoftwareinternalimagenode_p.h | 2 | ||||
| -rw-r--r-- | src/quick/util/qquicksvgparser.cpp | 12 | ||||
| -rw-r--r-- | tests/auto/quick/qquickshape/data/changeElementsImperatively.qml | 21 | ||||
| -rw-r--r-- | tests/auto/quick/qquickshape/tst_qquickshape.cpp | 10 |
11 files changed, 116 insertions, 21 deletions
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 diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index 0a564fc6d5..1b78838b5c 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<QString> &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 5e62c5bd50..556d177fd3 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 db6fb39695..7d349b88bb 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<Heap::Object *>(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<Heap::Object *>(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<Heap::Object *>(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<Heap::Object *>(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 *>(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 ac90a7fdb9..3787d9a9e0 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]); diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp index d05f48d340..644c2387d8 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(); diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalimagenode.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwareinternalimagenode.cpp index 214f7d790b..3ae70da8de 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 af912e1a3f..da46a3a140 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; diff --git a/src/quick/util/qquicksvgparser.cpp b/src/quick/util/qquicksvgparser.cpp index 0687913565..56df53114e 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<QPolygonF> m_lowPolyLogo; @@ -707,6 +708,15 @@ void tst_QQuickShape::multilineStronglyTyped() } } +void tst_QQuickShape::changeElementsImperatively() +{ + // Shouldn't crash. + QScopedPointer<QQuickView> window(createView()); + window->setSource(testFileUrl("changeElementsImperatively.qml")); + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window.data())); +} + QTEST_MAIN(tst_QQuickShape) #include "tst_qquickshape.moc" |
