aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTarja Sundqvist <tarja.sundqvist@qt.io>2025-11-19 22:21:07 +0200
committerTarja Sundqvist <tarja.sundqvist@qt.io>2025-11-19 22:21:07 +0200
commitdbb2e3b6bc9b51f76f241c7d108c466d78ef5695 (patch)
tree1fa3393e75dfda78114c2f225422f6348b45df27
parent2d723c3626fed493b203924260dbc0757a8ec7e7 (diff)
parentbeebdbf5ef482d9253709158aac099a1247df24a (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.conf2
-rw-r--r--src/qml/jsruntime/qv4engine.cpp4
-rw-r--r--src/qml/jsruntime/qv4enginebase_p.h3
-rw-r--r--src/qml/jsruntime/qv4lookup.cpp33
-rw-r--r--src/qml/jsruntime/qv4object.cpp10
-rw-r--r--src/qml/jsruntime/qv4vme_moth.cpp4
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwareinternalimagenode.cpp36
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwareinternalimagenode_p.h2
-rw-r--r--src/quick/util/qquicksvgparser.cpp12
-rw-r--r--tests/auto/quick/qquickshape/data/changeElementsImperatively.qml21
-rw-r--r--tests/auto/quick/qquickshape/tst_qquickshape.cpp10
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"