diff options
55 files changed, 998 insertions, 418 deletions
diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp index 065e91109b..d4757bed39 100644 --- a/src/qml/compiler/qqmlirbuilder.cpp +++ b/src/qml/compiler/qqmlirbuilder.cpp @@ -236,7 +236,6 @@ void Document::collectTypeReferences() // ### FIXME: We could report the more accurate location here by using prop->location, but the old // compiler can't and the tests expect it to be the object location right now. QV4::CompiledData::TypeReference &r = typeReferences.add(prop->customTypeNameIndex, obj->location); - r.needsCreation = true; r.errorWhenNotFound = true; } } diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h index 6f0b5f9b32..8990db075d 100644 --- a/src/qml/compiler/qv4compileddata_p.h +++ b/src/qml/compiler/qv4compileddata_p.h @@ -620,8 +620,6 @@ struct Q_QML_PRIVATE_EXPORT CompilationUnit : public QQmlRefCount QV4::Function *linkToEngine(QV4::ExecutionEngine *engine); void unlink(); - virtual QV4::ExecutableAllocator::ChunkOfPages *chunkForFunction(int /*functionIndex*/) { return 0; } - void markObjects(QV4::ExecutionEngine *e); protected: diff --git a/src/qml/doc/src/javascript/functionlist.qdoc b/src/qml/doc/src/javascript/functionlist.qdoc index 8b9c33f994..b9a25a2440 100644 --- a/src/qml/doc/src/javascript/functionlist.qdoc +++ b/src/qml/doc/src/javascript/functionlist.qdoc @@ -231,6 +231,26 @@ \li \l {Number::toLocaleString}{toLocaleString(locale, format, precision)} \endlist + \section2 The Number Object + + \section3 Value Properties + + \list + \li NaN + \li NEGATIVE_INFINITY + \li POSITIVE_INFINITY + \li MAX_VALUE + \li MIN_VALUE + \li EPSILON // ECMAScript 6: Added in Qt 5.8 + \endlist + + \section3 Function Properties + + \list + \li isFinite(x) // ECMAScript 6: Added in Qt 5.8 + \li isNaN(x) // ECMAScript 6: Added in Qt 5.8 + \endlist + \section1 The Math Object \section2 Value Properties @@ -264,6 +284,7 @@ \li pow(x, y) \li random() \li round(x) + \li sign(x) // ECMAScript 6: Added in Qt 5.8 \li sin(x) \li sqrt(x) \li tan(x) diff --git a/src/qml/jit/qv4assembler.cpp b/src/qml/jit/qv4assembler.cpp index 3da1aaa010..7d0d93b63a 100644 --- a/src/qml/jit/qv4assembler.cpp +++ b/src/qml/jit/qv4assembler.cpp @@ -79,16 +79,6 @@ void CompilationUnit::linkBackendToEngine(ExecutionEngine *engine) } } -QV4::ExecutableAllocator::ChunkOfPages *CompilationUnit::chunkForFunction(int functionIndex) -{ - if (functionIndex < 0 || functionIndex >= codeRefs.count()) - return 0; - JSC::ExecutableMemoryHandle *handle = codeRefs[functionIndex].executableMemory(); - if (!handle) - return 0; - return handle->chunk(); -} - const Assembler::VoidType Assembler::Void; Assembler::Assembler(InstructionSelection *isel, IR::Function* function, QV4::ExecutableAllocator *executableAllocator) diff --git a/src/qml/jit/qv4assembler_p.h b/src/qml/jit/qv4assembler_p.h index 6c7d27b2f4..9a681bc9ba 100644 --- a/src/qml/jit/qv4assembler_p.h +++ b/src/qml/jit/qv4assembler_p.h @@ -83,8 +83,6 @@ struct CompilationUnit : public QV4::CompiledData::CompilationUnit virtual void linkBackendToEngine(QV4::ExecutionEngine *engine); - virtual QV4::ExecutableAllocator::ChunkOfPages *chunkForFunction(int functionIndex); - // Coderef + execution engine QVector<JSC::MacroAssemblerCodeRef> codeRefs; diff --git a/src/qml/jsapi/qjsengine.cpp b/src/qml/jsapi/qjsengine.cpp index 4241213c09..424d5548a1 100644 --- a/src/qml/jsapi/qjsengine.cpp +++ b/src/qml/jsapi/qjsengine.cpp @@ -255,10 +255,8 @@ QT_BEGIN_NAMESPACE \l{ECMA-262}, Section 15.1. */ QJSEngine::QJSEngine() - : QObject(*new QJSEnginePrivate, 0) - , d(new QV8Engine(this)) + : QJSEngine(nullptr) { - QJSEnginePrivate::addToDebugServer(this); } /*! diff --git a/src/qml/jsruntime/qv4globalobject_p.h b/src/qml/jsruntime/qv4globalobject_p.h index e00a3445da..ea7a3b06ce 100644 --- a/src/qml/jsruntime/qv4globalobject_p.h +++ b/src/qml/jsruntime/qv4globalobject_p.h @@ -71,7 +71,6 @@ struct Q_QML_EXPORT EvalFunction : FunctionObject ReturnedValue evalCall(CallData *callData, bool directCall) const; - using Object::construct; static ReturnedValue call(const Managed *that, CallData *callData); }; diff --git a/src/qml/jsruntime/qv4mathobject.cpp b/src/qml/jsruntime/qv4mathobject.cpp index 4a304b6138..5528409b40 100644 --- a/src/qml/jsruntime/qv4mathobject.cpp +++ b/src/qml/jsruntime/qv4mathobject.cpp @@ -80,22 +80,24 @@ Heap::MathObject::MathObject() m->defineDefaultProperty(QStringLiteral("pow"), QV4::MathObject::method_pow, 2); m->defineDefaultProperty(QStringLiteral("random"), QV4::MathObject::method_random, 0); m->defineDefaultProperty(QStringLiteral("round"), QV4::MathObject::method_round, 1); + m->defineDefaultProperty(QStringLiteral("sign"), QV4::MathObject::method_sign, 1); m->defineDefaultProperty(QStringLiteral("sin"), QV4::MathObject::method_sin, 1); m->defineDefaultProperty(QStringLiteral("sqrt"), QV4::MathObject::method_sqrt, 1); m->defineDefaultProperty(QStringLiteral("tan"), QV4::MathObject::method_tan, 1); } -/* copies the sign from y to x and returns the result */ -static double copySign(double x, double y) +#ifdef Q_OS_ANDROID +// C++11's std::copysign is missing in the std namespace, so get it from the root namespace (math.h) +static Q_ALWAYS_INLINE double copySign(double x, double y) { - uchar *xch = (uchar *)&x; - uchar *ych = (uchar *)&y; - if (QSysInfo::ByteOrder == QSysInfo::BigEndian) - xch[0] = (xch[0] & 0x7f) | (ych[0] & 0x80); - else - xch[7] = (xch[7] & 0x7f) | (ych[7] & 0x80); - return x; + return ::copysign(x, y); +} +#else // Ok, we have a proper C++11 standard library +static Q_ALWAYS_INLINE double copySign(double x, double y) +{ + return std::copysign(x, y); } +#endif ReturnedValue MathObject::method_abs(CallContext *context) { @@ -299,6 +301,19 @@ ReturnedValue MathObject::method_round(CallContext *context) return Encode(v); } +ReturnedValue MathObject::method_sign(CallContext *context) +{ + double v = context->argc() ? context->args()[0].toNumber() : qt_qnan(); + + if (std::isnan(v)) + return Encode(qt_qnan()); + + if (qIsNull(v)) + return v; + + return Encode(std::signbit(v) ? -1 : 1); +} + ReturnedValue MathObject::method_sin(CallContext *context) { double v = context->argc() ? context->args()[0].toNumber() : qt_qnan(); diff --git a/src/qml/jsruntime/qv4mathobject_p.h b/src/qml/jsruntime/qv4mathobject_p.h index 2b842a312f..01e778d9ec 100644 --- a/src/qml/jsruntime/qv4mathobject_p.h +++ b/src/qml/jsruntime/qv4mathobject_p.h @@ -84,6 +84,7 @@ struct MathObject: Object static ReturnedValue method_pow(CallContext *context); static ReturnedValue method_random(CallContext *context); static ReturnedValue method_round(CallContext *context); + static ReturnedValue method_sign(CallContext *context); static ReturnedValue method_sin(CallContext *context); static ReturnedValue method_sqrt(CallContext *context); static ReturnedValue method_tan(CallContext *context); diff --git a/src/qml/jsruntime/qv4numberobject.cpp b/src/qml/jsruntime/qv4numberobject.cpp index ab3e03b183..f6b3e9a2b3 100644 --- a/src/qml/jsruntime/qv4numberobject.cpp +++ b/src/qml/jsruntime/qv4numberobject.cpp @@ -45,6 +45,7 @@ #include <QtCore/qmath.h> #include <QtCore/QDebug> #include <cassert> +#include <limits> using namespace QV4; @@ -99,12 +100,16 @@ void NumberPrototype::init(ExecutionEngine *engine, Object *ctor) ctor->defineReadonlyProperty(QStringLiteral("NEGATIVE_INFINITY"), Primitive::fromDouble(-qInf())); ctor->defineReadonlyProperty(QStringLiteral("POSITIVE_INFINITY"), Primitive::fromDouble(qInf())); ctor->defineReadonlyProperty(QStringLiteral("MAX_VALUE"), Primitive::fromDouble(1.7976931348623158e+308)); + ctor->defineReadonlyProperty(QStringLiteral("EPSILON"), Primitive::fromDouble(std::numeric_limits<double>::epsilon())); QT_WARNING_PUSH QT_WARNING_DISABLE_INTEL(239) ctor->defineReadonlyProperty(QStringLiteral("MIN_VALUE"), Primitive::fromDouble(5e-324)); QT_WARNING_POP + ctor->defineDefaultProperty(QStringLiteral("isFinite"), method_isFinite, 1); + ctor->defineDefaultProperty(QStringLiteral("isNaN"), method_isNaN, 1); + defineDefaultProperty(QStringLiteral("constructor"), (o = ctor)); defineDefaultProperty(engine->id_toString(), method_toString); defineDefaultProperty(QStringLiteral("toLocaleString"), method_toLocaleString); @@ -134,6 +139,24 @@ inline double thisNumber(ExecutionContext *ctx) return n->value(); } +ReturnedValue NumberPrototype::method_isFinite(CallContext *ctx) +{ + if (!ctx->argc()) + return Encode(false); + + double v = ctx->args()[0].toNumber(); + return Encode(!std::isnan(v) && !qt_is_inf(v)); +} + +ReturnedValue NumberPrototype::method_isNaN(CallContext *ctx) +{ + if (!ctx->argc()) + return Encode(false); + + double v = ctx->args()[0].toNumber(); + return Encode(std::isnan(v)); +} + ReturnedValue NumberPrototype::method_toString(CallContext *ctx) { Scope scope(ctx); diff --git a/src/qml/jsruntime/qv4numberobject_p.h b/src/qml/jsruntime/qv4numberobject_p.h index ca6f686304..bbe22af4bb 100644 --- a/src/qml/jsruntime/qv4numberobject_p.h +++ b/src/qml/jsruntime/qv4numberobject_p.h @@ -87,6 +87,8 @@ struct NumberPrototype: NumberObject { void init(ExecutionEngine *engine, Object *ctor); + static ReturnedValue method_isFinite(CallContext *ctx); + static ReturnedValue method_isNaN(CallContext *ctx); static ReturnedValue method_toString(CallContext *ctx); static ReturnedValue method_toLocaleString(CallContext *ctx); static ReturnedValue method_valueOf(CallContext *ctx); diff --git a/src/qml/jsruntime/qv4runtimeapi_p.h b/src/qml/jsruntime/qv4runtimeapi_p.h index bf153223a0..ded2b541dc 100644 --- a/src/qml/jsruntime/qv4runtimeapi_p.h +++ b/src/qml/jsruntime/qv4runtimeapi_p.h @@ -39,6 +39,17 @@ #ifndef QV4RUNTIMEAPI_P_H #define QV4RUNTIMEAPI_P_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include <private/qv4global_p.h> QT_BEGIN_NAMESPACE diff --git a/src/qml/qml/qqmlapplicationengine.cpp b/src/qml/qml/qqmlapplicationengine.cpp index 57cdd3f47f..8c342e0592 100644 --- a/src/qml/qml/qqmlapplicationengine.cpp +++ b/src/qml/qml/qqmlapplicationengine.cpp @@ -211,11 +211,8 @@ QQmlApplicationEngine::QQmlApplicationEngine(QObject *parent) This is provided as a convenience, and is the same as using the empty constructor and calling load afterwards. */ QQmlApplicationEngine::QQmlApplicationEngine(const QUrl &url, QObject *parent) - : QQmlEngine(*(new QQmlApplicationEnginePrivate(this)), parent) + : QQmlApplicationEngine(parent) { - Q_D(QQmlApplicationEngine); - d->init(); - QJSEnginePrivate::addToDebugServer(this); load(url); } @@ -228,12 +225,8 @@ QQmlApplicationEngine::QQmlApplicationEngine(const QUrl &url, QObject *parent) This is provided as a convenience, and is the same as using the empty constructor and calling load afterwards. */ QQmlApplicationEngine::QQmlApplicationEngine(const QString &filePath, QObject *parent) - : QQmlEngine(*(new QQmlApplicationEnginePrivate(this)), parent) + : QQmlApplicationEngine(QUrl::fromLocalFile(filePath), parent) { - Q_D(QQmlApplicationEngine); - d->init(); - QJSEnginePrivate::addToDebugServer(this); - load(QUrl::fromLocalFile(filePath)); } /*! diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp index fbd2d13e40..61a4b701c0 100644 --- a/src/qml/qml/qqmlcomponent.cpp +++ b/src/qml/qml/qqmlcomponent.cpp @@ -511,11 +511,8 @@ QQmlComponent::QQmlComponent(QQmlEngine *engine, QObject *parent) \sa loadUrl() */ QQmlComponent::QQmlComponent(QQmlEngine *engine, const QUrl &url, QObject *parent) -: QObject(*(new QQmlComponentPrivate), parent) + : QQmlComponent(engine, url, QQmlComponent::PreferSynchronous, parent) { - Q_D(QQmlComponent); - d->engine = engine; - d->loadUrl(url); } /*! @@ -530,10 +527,9 @@ QQmlComponent::QQmlComponent(QQmlEngine *engine, const QUrl &url, QObject *paren */ QQmlComponent::QQmlComponent(QQmlEngine *engine, const QUrl &url, CompilationMode mode, QObject *parent) -: QObject(*(new QQmlComponentPrivate), parent) + : QQmlComponent(engine, parent) { Q_D(QQmlComponent); - d->engine = engine; d->loadUrl(url, mode); } @@ -545,11 +541,8 @@ QQmlComponent::QQmlComponent(QQmlEngine *engine, const QUrl &url, CompilationMod */ QQmlComponent::QQmlComponent(QQmlEngine *engine, const QString &fileName, QObject *parent) -: QObject(*(new QQmlComponentPrivate), parent) + : QQmlComponent(engine, fileName, QQmlComponent::PreferSynchronous, parent) { - Q_D(QQmlComponent); - d->engine = engine; - d->loadUrl(d->engine->baseUrl().resolved(QUrl::fromLocalFile(fileName))); } /*! @@ -561,10 +554,9 @@ QQmlComponent::QQmlComponent(QQmlEngine *engine, const QString &fileName, */ QQmlComponent::QQmlComponent(QQmlEngine *engine, const QString &fileName, CompilationMode mode, QObject *parent) -: QObject(*(new QQmlComponentPrivate), parent) + : QQmlComponent(engine, parent) { Q_D(QQmlComponent); - d->engine = engine; d->loadUrl(d->engine->baseUrl().resolved(QUrl::fromLocalFile(fileName)), mode); } @@ -572,10 +564,9 @@ QQmlComponent::QQmlComponent(QQmlEngine *engine, const QString &fileName, \internal */ QQmlComponent::QQmlComponent(QQmlEngine *engine, QQmlCompiledData *cc, int start, QObject *parent) - : QObject(*(new QQmlComponentPrivate), parent) + : QQmlComponent(engine, parent) { Q_D(QQmlComponent); - d->engine = engine; d->cc = cc; cc->addref(); d->start = start; diff --git a/src/qml/qml/qqmlcontext.cpp b/src/qml/qml/qqmlcontext.cpp index 65a337f4e5..af06405376 100644 --- a/src/qml/qml/qqmlcontext.cpp +++ b/src/qml/qml/qqmlcontext.cpp @@ -516,12 +516,7 @@ QObject *QQmlContextPrivate::context_at(QQmlListProperty<QObject> *prop, int ind QQmlContextData::QQmlContextData() -: parent(0), engine(0), isInternal(false), ownedByParent(false), isJSContext(false), - isPragmaLibraryContext(false), unresolvedNames(false), hasEmittedDestruction(false), isRootObjectInCreation(false), - publicContext(0), activeVMEData(0), - contextObject(0), imports(0), childContexts(0), nextChild(0), prevChild(0), - expressions(0), contextObjects(0), contextGuards(0), idValues(0), idValueCount(0), linkedContext(0), - componentAttached(0) + : QQmlContextData(nullptr) { } diff --git a/src/qml/qml/qqmlfile.cpp b/src/qml/qml/qqmlfile.cpp index 8ce0cc2026..7a441dd9ff 100644 --- a/src/qml/qml/qqmlfile.cpp +++ b/src/qml/qml/qqmlfile.cpp @@ -227,9 +227,8 @@ QQmlFile::QQmlFile(QQmlEngine *e, const QUrl &url) } QQmlFile::QQmlFile(QQmlEngine *e, const QString &url) -: d(new QQmlFilePrivate) + : QQmlFile(e, QUrl(url)) { - load(e, url); } QQmlFile::~QQmlFile() diff --git a/src/qml/qml/qqmlmemoryprofiler.cpp b/src/qml/qml/qqmlmemoryprofiler.cpp index d9e121bb1b..60f6d96eaf 100644 --- a/src/qml/qml/qqmlmemoryprofiler.cpp +++ b/src/qml/qml/qqmlmemoryprofiler.cpp @@ -97,12 +97,9 @@ static bool openLibrary() return state == Loaded; } -QQmlMemoryScope::QQmlMemoryScope(const QUrl &url) : pushed(false) +QQmlMemoryScope::QQmlMemoryScope(const QUrl &url) + : QQmlMemoryScope(url.path().toUtf8().constData()) { - if (openLibrary() && memprofile_is_enabled()) { - memprofile_push_location(url.path().toUtf8().constData(), 0); - pushed = true; - } } QQmlMemoryScope::QQmlMemoryScope(const char *string) : pushed(false) diff --git a/src/qml/qml/qqmlpropertycache.cpp b/src/qml/qml/qqmlpropertycache.cpp index 0522aa93ee..4ac13d1cb4 100644 --- a/src/qml/qml/qqmlpropertycache.cpp +++ b/src/qml/qml/qqmlpropertycache.cpp @@ -249,11 +249,8 @@ QQmlPropertyCache::QQmlPropertyCache(QV4::ExecutionEngine *e) Creates a new QQmlPropertyCache of \a metaObject. */ QQmlPropertyCache::QQmlPropertyCache(QV4::ExecutionEngine *e, const QMetaObject *metaObject) - : engine(e), _parent(0), propertyIndexCacheStart(0), methodIndexCacheStart(0), - signalHandlerIndexCacheStart(0), _hasPropertyOverrides(false), _ownMetaObject(false), - _metaObject(0), argumentsCache(0) + : QQmlPropertyCache(e) { - Q_ASSERT(engine); Q_ASSERT(metaObject); update(metaObject); diff --git a/src/qml/qml/qqmlpropertycache_p.h b/src/qml/qml/qqmlpropertycache_p.h index 4fb84198d9..b2171dd86b 100644 --- a/src/qml/qml/qqmlpropertycache_p.h +++ b/src/qml/qml/qqmlpropertycache_p.h @@ -496,6 +496,14 @@ int QQmlPropertyRawData::encodedIndex() const return isValueTypeVirtual()?QQmlPropertyData::encodeValueTypePropertyIndex(coreIndex, valueTypeCoreIndex):coreIndex; } +inline QQmlPropertyData *QQmlPropertyCache::ensureResolved(QQmlPropertyData *p) const +{ + if (p && p->notFullyResolved()) + resolve(p); + + return p; +} + inline QQmlPropertyData *QQmlPropertyCache::property(int index) const { if (index < 0 || index >= (propertyIndexCacheStart + propertyIndexCache.count())) @@ -556,14 +564,6 @@ int QQmlPropertyCache::signalOffset() const return signalHandlerIndexCacheStart; } -inline QQmlPropertyData *QQmlPropertyCache::ensureResolved(QQmlPropertyData *p) const -{ - if (p && p->notFullyResolved()) - resolve(p); - - return p; -} - QQmlMetaObject::QQmlMetaObject() { } diff --git a/src/qml/qml/qqmlvaluetype.cpp b/src/qml/qml/qqmlvaluetype.cpp index 28bbaf0e92..44fd47244d 100644 --- a/src/qml/qml/qqmlvaluetype.cpp +++ b/src/qml/qml/qqmlvaluetype.cpp @@ -523,7 +523,7 @@ void QQmlEasingValueType::setBezierCurve(const QVariantList &customCurveVariant) QVariantList variantList = customCurveVariant; if ((variantList.count() % 6) == 0) { bool allRealsOk = true; - QList<qreal> reals; + QVector<qreal> reals; const int variantListCount = variantList.count(); reals.reserve(variantListCount); for (int i = 0; i < variantListCount; i++) { @@ -557,9 +557,10 @@ void QQmlEasingValueType::setBezierCurve(const QVariantList &customCurveVariant) QVariantList QQmlEasingValueType::bezierCurve() const { QVariantList rv; - QVector<QPointF> points = v.toCubicSpline(); - for (int ii = 0; ii < points.count(); ++ii) - rv << QVariant(points.at(ii).x()) << QVariant(points.at(ii).y()); + const QVector<QPointF> points = v.toCubicSpline(); + rv.reserve(points.size() * 2); + for (const auto &point : points) + rv << QVariant(point.x()) << QVariant(point.y()); return rv; } diff --git a/src/qml/types/qqmldelegatemodel.cpp b/src/qml/types/qqmldelegatemodel.cpp index cd80cba855..6e5fa516db 100644 --- a/src/qml/types/qqmldelegatemodel.cpp +++ b/src/qml/types/qqmldelegatemodel.cpp @@ -235,10 +235,8 @@ void QQmlDelegateModelPrivate::init() } QQmlDelegateModel::QQmlDelegateModel() -: QQmlInstanceModel(*(new QQmlDelegateModelPrivate(0))) + : QQmlDelegateModel(nullptr, nullptr) { - Q_D(QQmlDelegateModel); - d->init(); } QQmlDelegateModel::QQmlDelegateModel(QQmlContext *ctxt, QObject *parent) @@ -2357,7 +2355,7 @@ QQmlDelegateModelGroup::QQmlDelegateModelGroup(QObject *parent) QQmlDelegateModelGroup::QQmlDelegateModelGroup( const QString &name, QQmlDelegateModel *model, int index, QObject *parent) - : QObject(*new QQmlDelegateModelGroupPrivate, parent) + : QQmlDelegateModelGroup(parent) { Q_D(QQmlDelegateModelGroup); d->name = name; diff --git a/src/quick/items/qquickborderimage.cpp b/src/quick/items/qquickborderimage.cpp index 5f8dd7b989..b3a35e6219 100644 --- a/src/quick/items/qquickborderimage.cpp +++ b/src/quick/items/qquickborderimage.cpp @@ -574,6 +574,52 @@ void QQuickBorderImage::doUpdate() update(); } +void QQuickBorderImagePrivate::calculateRects(const QQuickScaleGrid *border, + const QSize &sourceSize, + const QSizeF &targetSize, + int horizontalTileMode, + int verticalTileMode, + qreal devicePixelRatio, + QRectF *targetRect, + QRectF *innerTargetRect, + QRectF *innerSourceRect, + QRectF *subSourceRect) +{ + *innerSourceRect = QRectF(0, 0, 1, 1); + *targetRect = QRectF(0, 0, targetSize.width(), targetSize.height()); + *innerTargetRect = *targetRect; + + if (border) { + *innerSourceRect = QRectF(border->left() * devicePixelRatio / qreal(sourceSize.width()), + border->top() * devicePixelRatio / qreal(sourceSize.height()), + qMax<qreal>(0, sourceSize.width() - (border->right() + border->left()) * devicePixelRatio) / sourceSize.width(), + qMax<qreal>(0, sourceSize.height() - (border->bottom() + border->top()) * devicePixelRatio) / sourceSize.height()); + *innerTargetRect = QRectF(border->left(), + border->top(), + qMax<qreal>(0, targetSize.width() - (border->right() + border->left())), + qMax<qreal>(0, targetSize.height() - (border->bottom() + border->top()))); + } + + qreal hTiles = 1; + qreal vTiles = 1; + const QSizeF innerTargetSize = innerTargetRect->size() * devicePixelRatio; + if (innerSourceRect->width() != 0 + && horizontalTileMode != QQuickBorderImage::Stretch) { + hTiles = innerTargetSize.width() / qreal(innerSourceRect->width() * sourceSize.width()); + if (horizontalTileMode == QQuickBorderImage::Round) + hTiles = qCeil(hTiles); + } + if (innerSourceRect->height() != 0 + && verticalTileMode != QQuickBorderImage::Stretch) { + vTiles = innerTargetSize.height() / qreal(innerSourceRect->height() * sourceSize.height()); + if (verticalTileMode == QQuickBorderImage::Round) + vTiles = qCeil(vTiles); + } + + *subSourceRect = QRectF(0, 0, hTiles, vTiles); +} + + QSGNode *QQuickBorderImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *) { Q_D(QQuickBorderImage); @@ -598,45 +644,25 @@ QSGNode *QQuickBorderImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDat node->setTexture(texture); // Don't implicitly create the scalegrid in the rendering thread... - QRectF innerSourceRect(0, 0, 1, 1); - QRectF targetRect(0, 0, width(), height()); - QRectF innerTargetRect = targetRect; - if (d->border) { - const QQuickScaleGrid *border = d->getScaleGrid(); - innerSourceRect = QRectF(border->left() * d->devicePixelRatio / qreal(d->pix.width()), - border->top() * d->devicePixelRatio / qreal(d->pix.height()), - qMax<qreal>(0, d->pix.width() - (border->right() + border->left()) * d->devicePixelRatio) / d->pix.width(), - qMax<qreal>(0, d->pix.height() - (border->bottom() + border->top()) * d->devicePixelRatio) / d->pix.height()); - innerTargetRect = QRectF(border->left(), - border->top(), - qMax<qreal>(0, width() - (border->right() + border->left())), - qMax<qreal>(0, height() - (border->bottom() + border->top()))); - } - qreal hTiles = 1; - qreal vTiles = 1; - const QSizeF innerTargetSize = innerTargetRect.size() * d->devicePixelRatio; - if (innerSourceRect.width() != 0 - && d->horizontalTileMode != QQuickBorderImage::Stretch) { - hTiles = innerTargetSize.width() / qreal(innerSourceRect.width() * d->pix.width()); - if (d->horizontalTileMode == QQuickBorderImage::Round) - hTiles = qCeil(hTiles); - } - if (innerSourceRect.height() != 0 - && d->verticalTileMode != QQuickBorderImage::Stretch) { - vTiles = innerTargetSize.height() / qreal(innerSourceRect.height() * d->pix.height()); - if (d->verticalTileMode == QQuickBorderImage::Round) - vTiles = qCeil(vTiles); - } + QRectF targetRect; + QRectF innerTargetRect; + QRectF innerSourceRect; + QRectF subSourceRect; + d->calculateRects(d->border, + QSize(d->pix.width(), d->pix.height()), QSizeF(width(), height()), + d->horizontalTileMode, d->verticalTileMode, d->devicePixelRatio, + &targetRect, &innerTargetRect, + &innerSourceRect, &subSourceRect); node->setTargetRect(targetRect); node->setInnerSourceRect(innerSourceRect); node->setInnerTargetRect(innerTargetRect); - node->setSubSourceRect(QRectF(0, 0, hTiles, vTiles)); + node->setSubSourceRect(subSourceRect); node->setMirror(d->mirror); node->setMipmapFiltering(QSGTexture::None); node->setFiltering(d->smooth ? QSGTexture::Linear : QSGTexture::Nearest); - if (innerSourceRect == QRectF(0, 0, 1, 1) && (vTiles > 1 || hTiles > 1)) { + if (innerSourceRect == QRectF(0, 0, 1, 1) && (subSourceRect.width() > 1 || subSourceRect.height() > 1)) { node->setHorizontalWrapMode(QSGTexture::Repeat); node->setVerticalWrapMode(QSGTexture::Repeat); } else { diff --git a/src/quick/items/qquickborderimage_p_p.h b/src/quick/items/qquickborderimage_p_p.h index 1dc530e34e..56fbbab049 100644 --- a/src/quick/items/qquickborderimage_p_p.h +++ b/src/quick/items/qquickborderimage_p_p.h @@ -91,6 +91,17 @@ public: return border; } + static void calculateRects(const QQuickScaleGrid *border, + const QSize &sourceSize, + const QSizeF &targetSize, + int horizontalTileMode, + int verticalTileMode, + qreal devicePixelRatio, + QRectF *targetRect, + QRectF *innerTargetRect, + QRectF *innerSourceRect, + QRectF *subSourceRect); + QQuickScaleGrid *border; QUrl sciurl; QQuickBorderImage::TileMode horizontalTileMode; diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp index ea2cb5aa5f..1100b12cbc 100644 --- a/src/quick/items/qquickitem.cpp +++ b/src/quick/items/qquickitem.cpp @@ -4152,6 +4152,7 @@ QVariant QQuickItem::inputMethodQuery(Qt::InputMethodQuery query) const v = (bool)(flags() & ItemAcceptsInputMethod); break; case Qt::ImHints: + case Qt::ImAnchorRectangle: case Qt::ImCursorRectangle: case Qt::ImFont: case Qt::ImCursorPosition: diff --git a/src/quick/items/qquickitemsmodule.cpp b/src/quick/items/qquickitemsmodule.cpp index 5f5809b6f2..fb5bc3683f 100644 --- a/src/quick/items/qquickitemsmodule.cpp +++ b/src/quick/items/qquickitemsmodule.cpp @@ -297,6 +297,7 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor) qmlRegisterType<QQuickShaderEffect, 2>(uri, 2, 8, "ShaderEffect"); qmlRegisterUncreatableType<QQuickRendererInfo>(uri, 2, 8,"RendererInfo", QQuickRendererInfo::tr("RendererInfo is only available via attached properties")); + qmlRegisterType<QQuickBorderImageMesh>("QtQuick", 2, 8, "BorderImageMesh"); } static void initResources() diff --git a/src/quick/items/qquickshadereffectmesh.cpp b/src/quick/items/qquickshadereffectmesh.cpp index d7765cdc69..f5cc19c877 100644 --- a/src/quick/items/qquickshadereffectmesh.cpp +++ b/src/quick/items/qquickshadereffectmesh.cpp @@ -39,6 +39,10 @@ #include "qquickshadereffectmesh_p.h" #include <QtQuick/qsggeometry.h> +#include "qquickshadereffect_p.h" +#include "qquickscalegrid_p_p.h" +#include "qquickborderimage_p_p.h" +#include <QtQuick/private/qsgbasicimagenode_p.h> QT_BEGIN_NAMESPACE @@ -239,4 +243,197 @@ QSize QQuickGridMesh::resolution() const return m_resolution; } +/*! + \qmltype BorderImageMesh + \instantiates QQuickBorderImageMesh + \inqmlmodule QtQuick + \since 5.8 + \ingroup qtquick-effects + \brief Defines a mesh with vertices arranged like those of a BorderImage. + + BorderImageMesh provides BorderImage-like capabilities to a ShaderEffect + without the need for a potentially costly ShaderEffectSource. + + The following are functionally equivalent: + \qml + BorderImage { + id: borderImage + border { + left: 10 + right: 10 + top: 10 + bottom: 10 + } + source: "myImage.png" + visible: false + } + ShaderEffectSource { + id: effectSource + sourceItem: borderImage + visible: false + } + ShaderEffect { + property var source: effectSource + ... + } + \endqml + + \qml + Image { + id: image + source: "myImage.png" + visible: false + } + ShaderEffect { + property var source: image + mesh: BorderImageMesh { + border { + left: 10 + right: 10 + top: 10 + bottom: 10 + } + size: image.sourceSize + } + ... + } + \endqml + + But the BorderImageMesh version can typically be better optimized. +*/ +QQuickBorderImageMesh::QQuickBorderImageMesh(QObject *parent) + : QQuickShaderEffectMesh(parent), m_border(new QQuickScaleGrid(this)), + m_horizontalTileMode(QQuickBorderImageMesh::Stretch), + m_verticalTileMode(QQuickBorderImageMesh::Stretch) +{ +} + +bool QQuickBorderImageMesh::validateAttributes(const QVector<QByteArray> &attributes, int *posIndex) +{ + Q_UNUSED(attributes); + Q_UNUSED(posIndex); + return true; +} + +QSGGeometry *QQuickBorderImageMesh::updateGeometry(QSGGeometry *geometry, int attrCount, int posIndex, + const QRectF &srcRect, const QRectF &rect) +{ + Q_UNUSED(attrCount); + Q_UNUSED(posIndex); + + QRectF innerSourceRect; + QRectF targetRect; + QRectF innerTargetRect; + QRectF subSourceRect; + + QQuickBorderImagePrivate::calculateRects(m_border, m_size, rect.size(), m_horizontalTileMode, m_verticalTileMode, + 1, &targetRect, &innerTargetRect, &innerSourceRect, &subSourceRect); + + QRectF sourceRect = srcRect; + QRectF modifiedInnerSourceRect(sourceRect.x() + innerSourceRect.x() * sourceRect.width(), + sourceRect.y() + innerSourceRect.y() * sourceRect.height(), + innerSourceRect.width() * sourceRect.width(), + innerSourceRect.height() * sourceRect.height()); + + geometry = QSGBasicImageNode::updateGeometry(targetRect, innerTargetRect, sourceRect, + modifiedInnerSourceRect, subSourceRect, geometry); + + return geometry; +} + +/*! + \qmlpropertygroup QtQuick::BorderImageMesh::border + \qmlproperty int QtQuick::BorderImageMesh::border.left + \qmlproperty int QtQuick::BorderImageMesh::border.right + \qmlproperty int QtQuick::BorderImageMesh::border.top + \qmlproperty int QtQuick::BorderImageMesh::border.bottom + + The 4 border lines (2 horizontal and 2 vertical) break the image into 9 sections, + as shown below: + + \image declarative-scalegrid.png + + Each border line (left, right, top, and bottom) specifies an offset in pixels + from the respective edge of the mesh. By default, each border line has + a value of 0. + + For example, the following definition sets the bottom line 10 pixels up from + the bottom of the mesh: + + \qml + BorderImageMesh { + border.bottom: 10 + // ... + } + \endqml +*/ +QQuickScaleGrid *QQuickBorderImageMesh::border() +{ + return m_border; +} + +/*! + \qmlproperty size QtQuick::BorderImageMesh::size + + The base size of the mesh. This generally corresponds to the \l {Image::}{sourceSize} + of the image being used by the ShaderEffect. +*/ +QSize QQuickBorderImageMesh::size() const +{ + return m_size; +} + +void QQuickBorderImageMesh::setSize(const QSize &size) +{ + if (size == m_size) + return; + m_size = size; + Q_EMIT sizeChanged(); + Q_EMIT geometryChanged(); +} + +/*! + \qmlproperty enumeration QtQuick::BorderImageMesh::horizontalTileMode + \qmlproperty enumeration QtQuick::BorderImageMesh::verticalTileMode + + This property describes how to repeat or stretch the middle parts of an image. + + \list + \li BorderImage.Stretch - Scales the image to fit to the available area. + \li BorderImage.Repeat - Tile the image until there is no more space. May crop the last image. + \li BorderImage.Round - Like Repeat, but scales the images down to ensure that the last image is not cropped. + \endlist + + The default tile mode for each property is BorderImage.Stretch. +*/ + +QQuickBorderImageMesh::TileMode QQuickBorderImageMesh::horizontalTileMode() const +{ + return m_horizontalTileMode; +} + +void QQuickBorderImageMesh::setHorizontalTileMode(TileMode t) +{ + if (t == m_horizontalTileMode) + return; + m_horizontalTileMode = t; + Q_EMIT horizontalTileModeChanged(); + Q_EMIT geometryChanged(); +} + +QQuickBorderImageMesh::TileMode QQuickBorderImageMesh::verticalTileMode() const +{ + return m_verticalTileMode; +} + +void QQuickBorderImageMesh::setVerticalTileMode(TileMode t) +{ + if (t == m_verticalTileMode) + return; + + m_verticalTileMode = t; + Q_EMIT verticalTileModeChanged(); + Q_EMIT geometryChanged(); +} + QT_END_NAMESPACE diff --git a/src/quick/items/qquickshadereffectmesh_p.h b/src/quick/items/qquickshadereffectmesh_p.h index b6894dc2ec..c5f1d19866 100644 --- a/src/quick/items/qquickshadereffectmesh_p.h +++ b/src/quick/items/qquickshadereffectmesh_p.h @@ -107,6 +107,48 @@ private: QString m_log; }; +class QQuickScaleGrid; +class QQuickBorderImageMesh : public QQuickShaderEffectMesh +{ + Q_OBJECT + + Q_PROPERTY(QQuickScaleGrid *border READ border CONSTANT) + Q_PROPERTY(QSize size READ size WRITE setSize NOTIFY sizeChanged) + Q_PROPERTY(TileMode horizontalTileMode READ horizontalTileMode WRITE setHorizontalTileMode NOTIFY horizontalTileModeChanged) + Q_PROPERTY(TileMode verticalTileMode READ verticalTileMode WRITE setVerticalTileMode NOTIFY verticalTileModeChanged) +public: + QQuickBorderImageMesh(QObject *parent = 0); + + bool validateAttributes(const QVector<QByteArray> &attributes, int *posIndex) override; + QSGGeometry *updateGeometry(QSGGeometry *geometry, int attrCount, int posIndex, + const QRectF &srcRect, const QRectF &rect) override; + + QQuickScaleGrid *border(); + + enum TileMode { Stretch = Qt::StretchTile, Repeat = Qt::RepeatTile, Round = Qt::RoundTile }; + Q_ENUM(TileMode) + + QSize size() const; + void setSize(const QSize &size); + + TileMode horizontalTileMode() const; + void setHorizontalTileMode(TileMode); + + TileMode verticalTileMode() const; + void setVerticalTileMode(TileMode); + +Q_SIGNALS: + void sizeChanged(); + void horizontalTileModeChanged(); + void verticalTileModeChanged(); + +private: + QQuickScaleGrid *m_border; + QSize m_size; + TileMode m_horizontalTileMode; + TileMode m_verticalTileMode; +}; + inline QColor qt_premultiply_color(const QColor &c) { return QColor::fromRgbF(c.redF() * c.alphaF(), c.greenF() * c.alphaF(), c.blueF() * c.alphaF(), c.alphaF()); diff --git a/src/quick/items/qquickspriteengine.cpp b/src/quick/items/qquickspriteengine.cpp index 025d5b7b6e..c82966cf6b 100644 --- a/src/quick/items/qquickspriteengine.cpp +++ b/src/quick/items/qquickspriteengine.cpp @@ -111,7 +111,7 @@ QQuickSpriteEngine::QQuickSpriteEngine(QObject *parent) } QQuickSpriteEngine::QQuickSpriteEngine(QList<QQuickSprite*> sprites, QObject *parent) - : QQuickStochasticEngine(parent), m_startedImageAssembly(false), m_loaded(false) + : QQuickSpriteEngine(parent) { foreach (QQuickSprite* sprite, sprites) m_states << (QQuickStochasticState*)sprite; diff --git a/src/quick/items/qquicktextcontrol.cpp b/src/quick/items/qquicktextcontrol.cpp index 127b51948a..8b6cc221d5 100644 --- a/src/quick/items/qquicktextcontrol.cpp +++ b/src/quick/items/qquicktextcontrol.cpp @@ -1399,10 +1399,16 @@ QVariant QQuickTextControl::inputMethodQuery(Qt::InputMethodQuery property, QVar switch (property) { case Qt::ImCursorRectangle: return cursorRect(); + case Qt::ImAnchorRectangle: + return anchorRect(); case Qt::ImFont: return QVariant(d->cursor.charFormat().font()); - case Qt::ImCursorPosition: + case Qt::ImCursorPosition: { + const QPointF pt = argument.toPointF(); + if (!pt.isNull()) + return QVariant(d->doc->documentLayout()->hitTest(pt, Qt::FuzzyHit) - block.position()); return QVariant(d->cursor.position() - block.position()); + } case Qt::ImSurroundingText: return QVariant(block.text()); case Qt::ImCurrentSelection: @@ -1527,6 +1533,17 @@ void QQuickTextControl::setCursorVisible(bool visible) && (d->interactionFlags & (Qt::TextEditable | Qt::TextSelectableByKeyboard))); } +QRectF QQuickTextControl::anchorRect() const +{ + Q_D(const QQuickTextControl); + QRectF rect; + QTextCursor cursor = d->cursor; + if (!cursor.isNull()) { + rect = d->rectForPosition(cursor.anchor()); + } + return rect; +} + QRectF QQuickTextControl::cursorRect(const QTextCursor &cursor) const { Q_D(const QQuickTextControl); diff --git a/src/quick/items/qquicktextcontrol_p.h b/src/quick/items/qquicktextcontrol_p.h index cee9cff064..602e457cb8 100644 --- a/src/quick/items/qquicktextcontrol_p.h +++ b/src/quick/items/qquicktextcontrol_p.h @@ -98,6 +98,7 @@ public: void setOverwriteMode(bool overwrite); bool cursorVisible() const; void setCursorVisible(bool visible); + QRectF anchorRect() const; QRectF cursorRect(const QTextCursor &cursor) const; QRectF cursorRect() const; QRectF selectionRect(const QTextCursor &cursor) const; diff --git a/src/quick/items/qquicktextedit.cpp b/src/quick/items/qquicktextedit.cpp index a44f549b37..8bb788d008 100644 --- a/src/quick/items/qquicktextedit.cpp +++ b/src/quick/items/qquicktextedit.cpp @@ -541,7 +541,7 @@ void QQuickTextEdit::setFont(const QFont &font) updateSize(); updateWholeDocument(); #ifndef QT_NO_IM - updateInputMethod(Qt::ImCursorRectangle | Qt::ImFont); + updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorRectangle | Qt::ImFont); #endif } emit fontChanged(d->sourceFont); @@ -1729,6 +1729,7 @@ void QQuickTextEdit::select(int start, int end) // QTBUG-11100 updateSelection(); + updateInputMethod(); } /*! @@ -1901,7 +1902,11 @@ QVariant QQuickTextEdit::inputMethodQuery(Qt::InputMethodQuery property, QVarian v = (int)d->effectiveInputMethodHints(); break; default: + if (property == Qt::ImCursorPosition && !argument.isNull()) + argument = QVariant(argument.toPointF() - QPointF(d->xoff, d->yoff)); v = d->control->inputMethodQuery(property, argument); + if (property == Qt::ImCursorRectangle || property == Qt::ImAnchorRectangle) + v = QVariant(v.toRectF().translated(d->xoff, d->yoff)); break; } return v; diff --git a/src/quick/items/qquicktextinput.cpp b/src/quick/items/qquicktextinput.cpp index 8bf854aac2..f361d46424 100644 --- a/src/quick/items/qquicktextinput.cpp +++ b/src/quick/items/qquicktextinput.cpp @@ -401,7 +401,7 @@ void QQuickTextInput::setFont(const QFont &font) d->updateLayout(); updateCursorRectangle(); #ifndef QT_NO_IM - updateInputMethod(Qt::ImCursorRectangle | Qt::ImFont); + updateInputMethod(Qt::ImCursorRectangle | Qt::ImFont | Qt::ImAnchorRectangle); #endif } emit fontChanged(d->sourceFont); @@ -1044,6 +1044,36 @@ void QQuickTextInput::q_validatorChanged() } #endif // QT_NO_VALIDATOR +QRectF QQuickTextInputPrivate::anchorRectangle() const +{ + QRectF rect; + int a; + // Unfortunately we cannot use selectionStart() and selectionEnd() + // since they always assume that the selectionStart is logically before selectionEnd. + // To rely on that would cause havoc if the user was interactively moving the end selection + // handle to become before the start selection + if (m_selstart == m_selend) + // This is to handle the case when there is "no selection" while moving the handle onto the + // same position as the other handle (in which case it would hide the selection handles) + a = m_cursor; + else + a = m_selstart == m_cursor ? m_selend : m_selstart; + if (a >= 0) { +#ifndef QT_NO_IM + a += m_preeditCursor; +#endif + if (m_echoMode == QQuickTextInput::NoEcho) + a = 0; + QTextLine l = m_textLayout.lineForTextPosition(a); + if (l.isValid()) { + qreal x = l.cursorToX(a) - hscroll; + qreal y = l.y() - vscroll; + rect.setRect(x, y, 1, l.height()); + } + } + return rect; +} + void QQuickTextInputPrivate::checkIsValid() { Q_Q(QQuickTextInput); @@ -1889,10 +1919,16 @@ QVariant QQuickTextInput::inputMethodQuery(Qt::InputMethodQuery property, QVaria return QVariant((int) d->effectiveInputMethodHints()); case Qt::ImCursorRectangle: return cursorRectangle(); + case Qt::ImAnchorRectangle: + return d->anchorRectangle(); case Qt::ImFont: return font(); - case Qt::ImCursorPosition: + case Qt::ImCursorPosition: { + const QPointF pt = argument.toPointF(); + if (!pt.isNull()) + return QVariant(d->positionAt(pt)); return QVariant(d->m_cursor); + } case Qt::ImSurroundingText: if (d->m_echoMode == PasswordEchoOnEdit && !d->m_passwordEchoEditing) { return QVariant(displayText()); @@ -2689,7 +2725,7 @@ void QQuickTextInput::updateCursorRectangle(bool scroll) d->cursorItem->setHeight(r.height()); } #ifndef QT_NO_IM - updateInputMethod(Qt::ImCursorRectangle); + updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorRectangle); #endif } @@ -3223,8 +3259,8 @@ void QQuickTextInputPrivate::setSelection(int start, int length) emit q->selectionChanged(); emitCursorPositionChanged(); #ifndef QT_NO_IM - q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorPosition - | Qt::ImCursorPosition | Qt::ImCurrentSelection); + q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorRectangle | Qt::ImCursorPosition | Qt::ImAnchorPosition + | Qt::ImCurrentSelection); #endif } @@ -3422,8 +3458,8 @@ void QQuickTextInputPrivate::processInputMethodEvent(QInputMethodEvent *event) if (selectionChange) { emit q->selectionChanged(); - q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorPosition - | Qt::ImCursorPosition | Qt::ImCurrentSelection); + q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorRectangle + | Qt::ImCurrentSelection); } } #endif // QT_NO_IM diff --git a/src/quick/items/qquicktextinput_p_p.h b/src/quick/items/qquicktextinput_p_p.h index d5a138945d..e6bd29bf67 100644 --- a/src/quick/items/qquicktextinput_p_p.h +++ b/src/quick/items/qquicktextinput_p_p.h @@ -342,6 +342,8 @@ public: int selectionStart() const { return hasSelectedText() ? m_selstart : -1; } int selectionEnd() const { return hasSelectedText() ? m_selend : -1; } + QRectF anchorRectangle() const; + int positionAt(qreal x, qreal y, QTextLine::CursorPosition position) const; int positionAt(const QPointF &point, QTextLine::CursorPosition position = QTextLine::CursorBetweenCharacters) const { return positionAt(point.x(), point.y(), position); diff --git a/src/quick/items/qquickview.cpp b/src/quick/items/qquickview.cpp index 3ce96b673d..1101b88992 100644 --- a/src/quick/items/qquickview.cpp +++ b/src/quick/items/qquickview.cpp @@ -194,9 +194,8 @@ QQuickView::QQuickView(QWindow *parent) */ QQuickView::QQuickView(const QUrl &source, QWindow *parent) -: QQuickWindow(*(new QQuickViewPrivate), parent) + : QQuickView(parent) { - d_func()->init(); setSource(source); } diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index fda01a72f2..2d38314a0a 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -1148,10 +1148,8 @@ void QQuickWindowPrivate::cleanup(QSGNode *n) Constructs a window for displaying a QML scene with parent window \a parent. */ QQuickWindow::QQuickWindow(QWindow *parent) - : QWindow(*(new QQuickWindowPrivate), parent) + : QQuickWindow(*new QQuickWindowPrivate, parent) { - Q_D(QQuickWindow); - d->init(this); } diff --git a/src/quick/items/qquickwindowmodule.cpp b/src/quick/items/qquickwindowmodule.cpp index 124df8f676..c624d162a9 100644 --- a/src/quick/items/qquickwindowmodule.cpp +++ b/src/quick/items/qquickwindowmodule.cpp @@ -77,18 +77,16 @@ QQuickWindowQmlImpl::QQuickWindowQmlImpl(QWindow *parent) void QQuickWindowQmlImpl::setVisible(bool visible) { Q_D(QQuickWindowQmlImpl); - if (!d->complete) - d->visible = visible; - else if (!transientParent() || transientParent()->isVisible()) + d->visible = visible; + if (d->complete && (!transientParent() || transientParent()->isVisible())) QQuickWindow::setVisible(visible); } void QQuickWindowQmlImpl::setVisibility(Visibility visibility) { Q_D(QQuickWindowQmlImpl); - if (!d->complete) - d->visibility = visibility; - else + d->visibility = visibility; + if (d->complete) QQuickWindow::setVisibility(visibility); } diff --git a/src/quick/scenegraph/coreapi/qsgshaderrewriter.cpp b/src/quick/scenegraph/coreapi/qsgshaderrewriter.cpp index 97d7e69407..3a35632d5c 100644 --- a/src/quick/scenegraph/coreapi/qsgshaderrewriter.cpp +++ b/src/quick/scenegraph/coreapi/qsgshaderrewriter.cpp @@ -89,9 +89,6 @@ void Tokenizer::initialize(const char *input) identifier = input; } -#define foo - - Tokenizer::Token Tokenizer::next() { while (*pos != 0) { diff --git a/src/quick/scenegraph/qsgbasicimagenode.cpp b/src/quick/scenegraph/qsgbasicimagenode.cpp index 0d33e2e24a..36a43b754a 100644 --- a/src/quick/scenegraph/qsgbasicimagenode.cpp +++ b/src/quick/scenegraph/qsgbasicimagenode.cpp @@ -200,6 +200,264 @@ static inline void appendQuad(quint16 **indices, quint16 topLeft, quint16 topRig *(*indices)++ = topLeft; } +QSGGeometry *QSGBasicImageNode::updateGeometry(const QRectF &targetRect, + const QRectF &innerTargetRect, + const QRectF &sourceRect, + const QRectF &innerSourceRect, + const QRectF &subSourceRect, + QSGGeometry *geometry, + bool mirror, + bool antialiasing) +{ + int floorLeft = qFloor(subSourceRect.left()); + int ceilRight = qCeil(subSourceRect.right()); + int floorTop = qFloor(subSourceRect.top()); + int ceilBottom = qCeil(subSourceRect.bottom()); + int hTiles = ceilRight - floorLeft; + int vTiles = ceilBottom - floorTop; + + int hCells = hTiles; + int vCells = vTiles; + if (innerTargetRect.width() == 0) + hCells = 0; + if (innerTargetRect.left() != targetRect.left()) + ++hCells; + if (innerTargetRect.right() != targetRect.right()) + ++hCells; + if (innerTargetRect.height() == 0) + vCells = 0; + if (innerTargetRect.top() != targetRect.top()) + ++vCells; + if (innerTargetRect.bottom() != targetRect.bottom()) + ++vCells; + QVarLengthArray<X, 32> xData(2 * hCells); + QVarLengthArray<Y, 32> yData(2 * vCells); + X *xs = xData.data(); + Y *ys = yData.data(); + + if (innerTargetRect.left() != targetRect.left()) { + xs[0].x = targetRect.left(); + xs[0].tx = sourceRect.left(); + xs[1].x = innerTargetRect.left(); + xs[1].tx = innerSourceRect.left(); + xs += 2; + } + if (innerTargetRect.width() != 0) { + xs[0].x = innerTargetRect.left(); + xs[0].tx = innerSourceRect.x() + (subSourceRect.left() - floorLeft) * innerSourceRect.width(); + ++xs; + float b = innerTargetRect.width() / subSourceRect.width(); + float a = innerTargetRect.x() - subSourceRect.x() * b; + for (int i = floorLeft + 1; i <= ceilRight - 1; ++i) { + xs[0].x = xs[1].x = a + b * i; + xs[0].tx = innerSourceRect.right(); + xs[1].tx = innerSourceRect.left(); + xs += 2; + } + xs[0].x = innerTargetRect.right(); + xs[0].tx = innerSourceRect.x() + (subSourceRect.right() - ceilRight + 1) * innerSourceRect.width(); + ++xs; + } + if (innerTargetRect.right() != targetRect.right()) { + xs[0].x = innerTargetRect.right(); + xs[0].tx = innerSourceRect.right(); + xs[1].x = targetRect.right(); + xs[1].tx = sourceRect.right(); + xs += 2; + } + Q_ASSERT(xs == xData.data() + xData.size()); + if (mirror) { + float leftPlusRight = targetRect.left() + targetRect.right(); + int count = xData.size(); + xs = xData.data(); + for (int i = 0; i < count >> 1; ++i) + qSwap(xs[i], xs[count - 1 - i]); + for (int i = 0; i < count; ++i) + xs[i].x = leftPlusRight - xs[i].x; + } + + if (innerTargetRect.top() != targetRect.top()) { + ys[0].y = targetRect.top(); + ys[0].ty = sourceRect.top(); + ys[1].y = innerTargetRect.top(); + ys[1].ty = innerSourceRect.top(); + ys += 2; + } + if (innerTargetRect.height() != 0) { + ys[0].y = innerTargetRect.top(); + ys[0].ty = innerSourceRect.y() + (subSourceRect.top() - floorTop) * innerSourceRect.height(); + ++ys; + float b = innerTargetRect.height() / subSourceRect.height(); + float a = innerTargetRect.y() - subSourceRect.y() * b; + for (int i = floorTop + 1; i <= ceilBottom - 1; ++i) { + ys[0].y = ys[1].y = a + b * i; + ys[0].ty = innerSourceRect.bottom(); + ys[1].ty = innerSourceRect.top(); + ys += 2; + } + ys[0].y = innerTargetRect.bottom(); + ys[0].ty = innerSourceRect.y() + (subSourceRect.bottom() - ceilBottom + 1) * innerSourceRect.height(); + ++ys; + } + if (innerTargetRect.bottom() != targetRect.bottom()) { + ys[0].y = innerTargetRect.bottom(); + ys[0].ty = innerSourceRect.bottom(); + ys[1].y = targetRect.bottom(); + ys[1].ty = sourceRect.bottom(); + ys += 2; + } + Q_ASSERT(ys == yData.data() + yData.size()); + + if (antialiasing) { + QSGGeometry *g = geometry; + Q_ASSERT(g); + + g->allocate(hCells * vCells * 4 + (hCells + vCells - 1) * 4, + hCells * vCells * 6 + (hCells + vCells) * 12); + g->setDrawingMode(GL_TRIANGLES); + SmoothVertex *vertices = reinterpret_cast<SmoothVertex *>(g->vertexData()); + memset(vertices, 0, g->vertexCount() * g->sizeOfVertex()); + quint16 *indices = g->indexDataAsUShort(); + + // The deltas are how much the fuzziness can reach into the image. + // Only the border vertices are moved by the vertex shader, so the fuzziness + // can't reach further into the image than the closest interior vertices. + float leftDx = xData.at(1).x - xData.at(0).x; + float rightDx = xData.at(xData.size() - 1).x - xData.at(xData.size() - 2).x; + float topDy = yData.at(1).y - yData.at(0).y; + float bottomDy = yData.at(yData.size() - 1).y - yData.at(yData.size() - 2).y; + + float leftDu = xData.at(1).tx - xData.at(0).tx; + float rightDu = xData.at(xData.size() - 1).tx - xData.at(xData.size() - 2).tx; + float topDv = yData.at(1).ty - yData.at(0).ty; + float bottomDv = yData.at(yData.size() - 1).ty - yData.at(yData.size() - 2).ty; + + if (hCells == 1) { + leftDx = rightDx *= 0.5f; + leftDu = rightDu *= 0.5f; + } + if (vCells == 1) { + topDy = bottomDy *= 0.5f; + topDv = bottomDv *= 0.5f; + } + + // This delta is how much the fuzziness can reach out from the image. + float delta = float(qAbs(targetRect.width()) < qAbs(targetRect.height()) + ? targetRect.width() : targetRect.height()) * 0.5f; + + quint16 index = 0; + ys = yData.data(); + for (int j = 0; j < vCells; ++j, ys += 2) { + xs = xData.data(); + bool isTop = j == 0; + bool isBottom = j == vCells - 1; + for (int i = 0; i < hCells; ++i, xs += 2) { + bool isLeft = i == 0; + bool isRight = i == hCells - 1; + + SmoothVertex *v = vertices + index; + + quint16 topLeft = index; + for (int k = (isTop || isLeft ? 2 : 1); k--; ++v, ++index) { + v->x = xs[0].x; + v->u = xs[0].tx; + v->y = ys[0].y; + v->v = ys[0].ty; + } + + quint16 topRight = index; + for (int k = (isTop || isRight ? 2 : 1); k--; ++v, ++index) { + v->x = xs[1].x; + v->u = xs[1].tx; + v->y = ys[0].y; + v->v = ys[0].ty; + } + + quint16 bottomLeft = index; + for (int k = (isBottom || isLeft ? 2 : 1); k--; ++v, ++index) { + v->x = xs[0].x; + v->u = xs[0].tx; + v->y = ys[1].y; + v->v = ys[1].ty; + } + + quint16 bottomRight = index; + for (int k = (isBottom || isRight ? 2 : 1); k--; ++v, ++index) { + v->x = xs[1].x; + v->u = xs[1].tx; + v->y = ys[1].y; + v->v = ys[1].ty; + } + + appendQuad(&indices, topLeft, topRight, bottomLeft, bottomRight); + + if (isTop) { + vertices[topLeft].dy = vertices[topRight].dy = topDy; + vertices[topLeft].dv = vertices[topRight].dv = topDv; + vertices[topLeft + 1].dy = vertices[topRight + 1].dy = -delta; + appendQuad(&indices, topLeft + 1, topRight + 1, topLeft, topRight); + } + + if (isBottom) { + vertices[bottomLeft].dy = vertices[bottomRight].dy = -bottomDy; + vertices[bottomLeft].dv = vertices[bottomRight].dv = -bottomDv; + vertices[bottomLeft + 1].dy = vertices[bottomRight + 1].dy = delta; + appendQuad(&indices, bottomLeft, bottomRight, bottomLeft + 1, bottomRight + 1); + } + + if (isLeft) { + vertices[topLeft].dx = vertices[bottomLeft].dx = leftDx; + vertices[topLeft].du = vertices[bottomLeft].du = leftDu; + vertices[topLeft + 1].dx = vertices[bottomLeft + 1].dx = -delta; + appendQuad(&indices, topLeft + 1, topLeft, bottomLeft + 1, bottomLeft); + } + + if (isRight) { + vertices[topRight].dx = vertices[bottomRight].dx = -rightDx; + vertices[topRight].du = vertices[bottomRight].du = -rightDu; + vertices[topRight + 1].dx = vertices[bottomRight + 1].dx = delta; + appendQuad(&indices, topRight, topRight + 1, bottomRight, bottomRight + 1); + } + } + } + + Q_ASSERT(index == g->vertexCount()); + Q_ASSERT(indices - g->indexCount() == g->indexData()); + } else { + if (!geometry) { + geometry = new QSGGeometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), + hCells * vCells * 4, hCells * vCells * 6, + GL_UNSIGNED_SHORT); + } else { + geometry->allocate(hCells * vCells * 4, hCells * vCells * 6); + } + geometry->setDrawingMode(GL_TRIANGLES); + QSGGeometry::TexturedPoint2D *vertices = geometry->vertexDataAsTexturedPoint2D(); + ys = yData.data(); + for (int j = 0; j < vCells; ++j, ys += 2) { + xs = xData.data(); + for (int i = 0; i < hCells; ++i, xs += 2) { + vertices[0].x = vertices[2].x = xs[0].x; + vertices[0].tx = vertices[2].tx = xs[0].tx; + vertices[1].x = vertices[3].x = xs[1].x; + vertices[1].tx = vertices[3].tx = xs[1].tx; + + vertices[0].y = vertices[1].y = ys[0].y; + vertices[0].ty = vertices[1].ty = ys[0].ty; + vertices[2].y = vertices[3].y = ys[1].y; + vertices[2].ty = vertices[3].ty = ys[1].ty; + + vertices += 4; + } + } + + quint16 *indices = geometry->indexDataAsUShort(); + for (int i = 0; i < 4 * vCells * hCells; i += 4) + appendQuad(&indices, i, i + 1, i + 2, i + 3); + } + return geometry; +} + void QSGBasicImageNode::updateGeometry() { Q_ASSERT(!m_targetRect.isEmpty()); @@ -288,239 +546,10 @@ void QSGBasicImageNode::updateGeometry() QSGGeometry::updateTexturedRectGeometry(&m_geometry, m_targetRect, sr); } } else { - int hCells = hTiles; - int vCells = vTiles; - if (m_innerTargetRect.width() == 0) - hCells = 0; - if (m_innerTargetRect.left() != m_targetRect.left()) - ++hCells; - if (m_innerTargetRect.right() != m_targetRect.right()) - ++hCells; - if (m_innerTargetRect.height() == 0) - vCells = 0; - if (m_innerTargetRect.top() != m_targetRect.top()) - ++vCells; - if (m_innerTargetRect.bottom() != m_targetRect.bottom()) - ++vCells; - QVarLengthArray<X, 32> xData(2 * hCells); - QVarLengthArray<Y, 32> yData(2 * vCells); - X *xs = xData.data(); - Y *ys = yData.data(); - - if (m_innerTargetRect.left() != m_targetRect.left()) { - xs[0].x = m_targetRect.left(); - xs[0].tx = sourceRect.left(); - xs[1].x = m_innerTargetRect.left(); - xs[1].tx = innerSourceRect.left(); - xs += 2; - } - if (m_innerTargetRect.width() != 0) { - xs[0].x = m_innerTargetRect.left(); - xs[0].tx = innerSourceRect.x() + (m_subSourceRect.left() - floorLeft) * innerSourceRect.width(); - ++xs; - float b = m_innerTargetRect.width() / m_subSourceRect.width(); - float a = m_innerTargetRect.x() - m_subSourceRect.x() * b; - for (int i = floorLeft + 1; i <= ceilRight - 1; ++i) { - xs[0].x = xs[1].x = a + b * i; - xs[0].tx = innerSourceRect.right(); - xs[1].tx = innerSourceRect.left(); - xs += 2; - } - xs[0].x = m_innerTargetRect.right(); - xs[0].tx = innerSourceRect.x() + (m_subSourceRect.right() - ceilRight + 1) * innerSourceRect.width(); - ++xs; - } - if (m_innerTargetRect.right() != m_targetRect.right()) { - xs[0].x = m_innerTargetRect.right(); - xs[0].tx = innerSourceRect.right(); - xs[1].x = m_targetRect.right(); - xs[1].tx = sourceRect.right(); - xs += 2; - } - Q_ASSERT(xs == xData.data() + xData.size()); - if (m_mirror) { - float leftPlusRight = m_targetRect.left() + m_targetRect.right(); - int count = xData.size(); - xs = xData.data(); - for (int i = 0; i < count >> 1; ++i) - qSwap(xs[i], xs[count - 1 - i]); - for (int i = 0; i < count; ++i) - xs[i].x = leftPlusRight - xs[i].x; - } - - if (m_innerTargetRect.top() != m_targetRect.top()) { - ys[0].y = m_targetRect.top(); - ys[0].ty = sourceRect.top(); - ys[1].y = m_innerTargetRect.top(); - ys[1].ty = innerSourceRect.top(); - ys += 2; - } - if (m_innerTargetRect.height() != 0) { - ys[0].y = m_innerTargetRect.top(); - ys[0].ty = innerSourceRect.y() + (m_subSourceRect.top() - floorTop) * innerSourceRect.height(); - ++ys; - float b = m_innerTargetRect.height() / m_subSourceRect.height(); - float a = m_innerTargetRect.y() - m_subSourceRect.y() * b; - for (int i = floorTop + 1; i <= ceilBottom - 1; ++i) { - ys[0].y = ys[1].y = a + b * i; - ys[0].ty = innerSourceRect.bottom(); - ys[1].ty = innerSourceRect.top(); - ys += 2; - } - ys[0].y = m_innerTargetRect.bottom(); - ys[0].ty = innerSourceRect.y() + (m_subSourceRect.bottom() - ceilBottom + 1) * innerSourceRect.height(); - ++ys; - } - if (m_innerTargetRect.bottom() != m_targetRect.bottom()) { - ys[0].y = m_innerTargetRect.bottom(); - ys[0].ty = innerSourceRect.bottom(); - ys[1].y = m_targetRect.bottom(); - ys[1].ty = sourceRect.bottom(); - ys += 2; - } - Q_ASSERT(ys == yData.data() + yData.size()); - - if (m_antialiasing) { - QSGGeometry *g = geometry(); - Q_ASSERT(g != &m_geometry); - - g->allocate(hCells * vCells * 4 + (hCells + vCells - 1) * 4, - hCells * vCells * 6 + (hCells + vCells) * 12); - g->setDrawingMode(QSGGeometry::DrawTriangles); - SmoothVertex *vertices = reinterpret_cast<SmoothVertex *>(g->vertexData()); - memset(vertices, 0, g->vertexCount() * g->sizeOfVertex()); - quint16 *indices = g->indexDataAsUShort(); - - // The deltas are how much the fuzziness can reach into the image. - // Only the border vertices are moved by the vertex shader, so the fuzziness - // can't reach further into the image than the closest interior vertices. - float leftDx = xData.at(1).x - xData.at(0).x; - float rightDx = xData.at(xData.size() - 1).x - xData.at(xData.size() - 2).x; - float topDy = yData.at(1).y - yData.at(0).y; - float bottomDy = yData.at(yData.size() - 1).y - yData.at(yData.size() - 2).y; - - float leftDu = xData.at(1).tx - xData.at(0).tx; - float rightDu = xData.at(xData.size() - 1).tx - xData.at(xData.size() - 2).tx; - float topDv = yData.at(1).ty - yData.at(0).ty; - float bottomDv = yData.at(yData.size() - 1).ty - yData.at(yData.size() - 2).ty; - - if (hCells == 1) { - leftDx = rightDx *= 0.5f; - leftDu = rightDu *= 0.5f; - } - if (vCells == 1) { - topDy = bottomDy *= 0.5f; - topDv = bottomDv *= 0.5f; - } - - // This delta is how much the fuzziness can reach out from the image. - float delta = float(qAbs(m_targetRect.width()) < qAbs(m_targetRect.height()) - ? m_targetRect.width() : m_targetRect.height()) * 0.5f; - - quint16 index = 0; - ys = yData.data(); - for (int j = 0; j < vCells; ++j, ys += 2) { - xs = xData.data(); - bool isTop = j == 0; - bool isBottom = j == vCells - 1; - for (int i = 0; i < hCells; ++i, xs += 2) { - bool isLeft = i == 0; - bool isRight = i == hCells - 1; - - SmoothVertex *v = vertices + index; - - quint16 topLeft = index; - for (int k = (isTop || isLeft ? 2 : 1); k--; ++v, ++index) { - v->x = xs[0].x; - v->u = xs[0].tx; - v->y = ys[0].y; - v->v = ys[0].ty; - } - - quint16 topRight = index; - for (int k = (isTop || isRight ? 2 : 1); k--; ++v, ++index) { - v->x = xs[1].x; - v->u = xs[1].tx; - v->y = ys[0].y; - v->v = ys[0].ty; - } - - quint16 bottomLeft = index; - for (int k = (isBottom || isLeft ? 2 : 1); k--; ++v, ++index) { - v->x = xs[0].x; - v->u = xs[0].tx; - v->y = ys[1].y; - v->v = ys[1].ty; - } - - quint16 bottomRight = index; - for (int k = (isBottom || isRight ? 2 : 1); k--; ++v, ++index) { - v->x = xs[1].x; - v->u = xs[1].tx; - v->y = ys[1].y; - v->v = ys[1].ty; - } - - appendQuad(&indices, topLeft, topRight, bottomLeft, bottomRight); - - if (isTop) { - vertices[topLeft].dy = vertices[topRight].dy = topDy; - vertices[topLeft].dv = vertices[topRight].dv = topDv; - vertices[topLeft + 1].dy = vertices[topRight + 1].dy = -delta; - appendQuad(&indices, topLeft + 1, topRight + 1, topLeft, topRight); - } - - if (isBottom) { - vertices[bottomLeft].dy = vertices[bottomRight].dy = -bottomDy; - vertices[bottomLeft].dv = vertices[bottomRight].dv = -bottomDv; - vertices[bottomLeft + 1].dy = vertices[bottomRight + 1].dy = delta; - appendQuad(&indices, bottomLeft, bottomRight, bottomLeft + 1, bottomRight + 1); - } - - if (isLeft) { - vertices[topLeft].dx = vertices[bottomLeft].dx = leftDx; - vertices[topLeft].du = vertices[bottomLeft].du = leftDu; - vertices[topLeft + 1].dx = vertices[bottomLeft + 1].dx = -delta; - appendQuad(&indices, topLeft + 1, topLeft, bottomLeft + 1, bottomLeft); - } - - if (isRight) { - vertices[topRight].dx = vertices[bottomRight].dx = -rightDx; - vertices[topRight].du = vertices[bottomRight].du = -rightDu; - vertices[topRight + 1].dx = vertices[bottomRight + 1].dx = delta; - appendQuad(&indices, topRight, topRight + 1, bottomRight, bottomRight + 1); - } - } - } - - Q_ASSERT(index == g->vertexCount()); - Q_ASSERT(indices - g->indexCount() == g->indexData()); - } else { - m_geometry.allocate(hCells * vCells * 4, hCells * vCells * 6); - m_geometry.setDrawingMode(QSGGeometry::DrawTriangles); - QSGGeometry::TexturedPoint2D *vertices = m_geometry.vertexDataAsTexturedPoint2D(); - ys = yData.data(); - for (int j = 0; j < vCells; ++j, ys += 2) { - xs = xData.data(); - for (int i = 0; i < hCells; ++i, xs += 2) { - vertices[0].x = vertices[2].x = xs[0].x; - vertices[0].tx = vertices[2].tx = xs[0].tx; - vertices[1].x = vertices[3].x = xs[1].x; - vertices[1].tx = vertices[3].tx = xs[1].tx; - - vertices[0].y = vertices[1].y = ys[0].y; - vertices[0].ty = vertices[1].ty = ys[0].ty; - vertices[2].y = vertices[3].y = ys[1].y; - vertices[2].ty = vertices[3].ty = ys[1].ty; - - vertices += 4; - } - } - - quint16 *indices = m_geometry.indexDataAsUShort(); - for (int i = 0; i < 4 * vCells * hCells; i += 4) - appendQuad(&indices, i, i + 1, i + 2, i + 3); - } + QSGGeometry *g = m_antialiasing ? geometry() : &m_geometry; + updateGeometry(m_targetRect, m_innerTargetRect, + sourceRect, innerSourceRect, m_subSourceRect, + g, m_mirror, m_antialiasing); } } markDirty(DirtyGeometry); diff --git a/src/quick/scenegraph/qsgbasicimagenode_p.h b/src/quick/scenegraph/qsgbasicimagenode_p.h index 288b6c23f0..4a96e1a9f6 100644 --- a/src/quick/scenegraph/qsgbasicimagenode_p.h +++ b/src/quick/scenegraph/qsgbasicimagenode_p.h @@ -70,6 +70,15 @@ public: void update() override; void preprocess() override; + static QSGGeometry *updateGeometry(const QRectF &targetRect, + const QRectF &innerTargetRect, + const QRectF &sourceRect, + const QRectF &innerSourceRect, + const QRectF &subSourceRect, + QSGGeometry *geometry, + bool mirror = false, + bool antialiasing = false); + protected: virtual void updateMaterialAntialiasing() = 0; virtual void setMaterialTexture(QSGTexture *texture) = 0; diff --git a/src/quickwidgets/qquickwidget.cpp b/src/quickwidgets/qquickwidget.cpp index b4efe2faea..b6431666bf 100644 --- a/src/quickwidgets/qquickwidget.cpp +++ b/src/quickwidgets/qquickwidget.cpp @@ -433,11 +433,8 @@ QQuickWidget::QQuickWidget(QWidget *parent) */ QQuickWidget::QQuickWidget(const QUrl &source, QWidget *parent) -: QWidget(*(new QQuickWidgetPrivate), parent, 0) + : QQuickWidget(parent) { - setMouseTracking(true); - setFocusPolicy(Qt::StrongFocus); - d_func()->init(); setSource(source); } diff --git a/tests/auto/qml/qjsengine/tst_qjsengine.cpp b/tests/auto/qml/qjsengine/tst_qjsengine.cpp index c535258c19..adf944c7e1 100644 --- a/tests/auto/qml/qjsengine/tst_qjsengine.cpp +++ b/tests/auto/qml/qjsengine/tst_qjsengine.cpp @@ -1024,11 +1024,14 @@ void tst_QJSEngine::builtinFunctionNames_data() QTest::newRow("Math.pow") << QString("Math.pow") << QString("pow"); QTest::newRow("Math.random") << QString("Math.random") << QString("random"); QTest::newRow("Math.round") << QString("Math.round") << QString("round"); + QTest::newRow("Math.sign") << QString("Math.sign") << QString("sign"); QTest::newRow("Math.sin") << QString("Math.sin") << QString("sin"); QTest::newRow("Math.sqrt") << QString("Math.sqrt") << QString("sqrt"); QTest::newRow("Math.tan") << QString("Math.tan") << QString("tan"); QTest::newRow("Number") << QString("Number") << QString("Number"); + QTest::newRow("Number.isFinite") << QString("Number.isFinite") << QString("isFinite"); + QTest::newRow("Number.isNaN") << QString("Number.isNaN") << QString("isNaN"); QTest::newRow("Number.prototype.toString") << QString("Number.prototype.toString") << QString("toString"); QTest::newRow("Number.prototype.toLocaleString") << QString("Number.prototype.toLocaleString") << QString("toLocaleString"); QTest::newRow("Number.prototype.valueOf") << QString("Number.prototype.valueOf") << QString("valueOf"); @@ -1920,6 +1923,7 @@ void tst_QJSEngine::jsNumberClass() QVERIFY(ctor.property("NaN").isNumber()); QVERIFY(ctor.property("NEGATIVE_INFINITY").isNumber()); QVERIFY(ctor.property("POSITIVE_INFINITY").isNumber()); + QVERIFY(ctor.property("EPSILON").isNumber()); } QCOMPARE(proto.toNumber(), qreal(0)); QVERIFY(proto.property("constructor").strictlyEquals(ctor)); @@ -1958,6 +1962,50 @@ void tst_QJSEngine::jsNumberClass() QCOMPARE(ret.toNumber(), qreal(456)); } + QVERIFY(ctor.property("isFinite").isCallable()); + { + QJSValue ret = eng.evaluate("Number.isFinite()"); + QVERIFY(ret.isBool()); + QCOMPARE(ret.toBool(), false); + } + { + QJSValue ret = eng.evaluate("Number.isFinite(NaN)"); + QVERIFY(ret.isBool()); + QCOMPARE(ret.toBool(), false); + } + { + QJSValue ret = eng.evaluate("Number.isFinite(Infinity)"); + QVERIFY(ret.isBool()); + QCOMPARE(ret.toBool(), false); + } + { + QJSValue ret = eng.evaluate("Number.isFinite(-Infinity)"); + QVERIFY(ret.isBool()); + QCOMPARE(ret.toBool(), false); + } + { + QJSValue ret = eng.evaluate("Number.isFinite(123)"); + QVERIFY(ret.isBool()); + QCOMPARE(ret.toBool(), true); + } + + QVERIFY(ctor.property("isNaN").isCallable()); + { + QJSValue ret = eng.evaluate("Number.isNaN()"); + QVERIFY(ret.isBool()); + QCOMPARE(ret.toBool(), false); + } + { + QJSValue ret = eng.evaluate("Number.isNaN(NaN)"); + QVERIFY(ret.isBool()); + QCOMPARE(ret.toBool(), true); + } + { + QJSValue ret = eng.evaluate("Number.isNaN(123)"); + QVERIFY(ret.isBool()); + QCOMPARE(ret.toBool(), false); + } + QVERIFY(proto.property("toString").isCallable()); { QJSValue ret = eng.evaluate("new Number(123).toString()"); diff --git a/tests/auto/qml/qqmllanguage/data/singletonTest10.error.txt b/tests/auto/qml/qqmllanguage/data/singletonTest10.error.txt deleted file mode 100644 index 32d2ed857e..0000000000 --- a/tests/auto/qml/qqmllanguage/data/singletonTest10.error.txt +++ /dev/null @@ -1 +0,0 @@ -4:1:Composite Singleton Type SingletonType is not creatable. diff --git a/tests/auto/qml/qqmllanguage/data/uncreatableTypeAsProperty.qml b/tests/auto/qml/qqmllanguage/data/uncreatableTypeAsProperty.qml new file mode 100644 index 0000000000..8369ab1eea --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/uncreatableTypeAsProperty.qml @@ -0,0 +1,6 @@ +import QtQml 2.0 +import Test 1.0 + +QtObject { + property MyUncreateableBaseClass someProperty; +} diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp index dd7410dfd3..1ac1661ea8 100644 --- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp +++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp @@ -188,6 +188,8 @@ private slots: void subclassedUncreateableRevision_data(); void subclassedUncreateableRevision(); + void uncreatableTypesAsProperties(); + void propertyInit(); void remoteLoadCrash(); void signalWithDefaultArg(); @@ -3158,6 +3160,14 @@ void tst_qqmllanguage::subclassedUncreateableRevision() delete obj; } +void tst_qqmllanguage::uncreatableTypesAsProperties() +{ + QQmlEngine engine; + QQmlComponent component(&engine, testFileUrl("uncreatableTypeAsProperty.qml")); + QScopedPointer<QObject> object(component.create()); + QVERIFY(!object.isNull()); +} + void tst_qqmllanguage::initTestCase() { QQmlDataTest::initTestCase(); @@ -3863,12 +3873,11 @@ void tst_qqmllanguage::compositeSingletonInstantiateError() VERIFY_ERRORS("singletonTest9.error.txt"); } -// Having a composite singleton type as dynamic property type fails -// (like C++ singleton) +// Having a composite singleton type as dynamic property type is allowed void tst_qqmllanguage::compositeSingletonDynamicPropertyError() { QQmlComponent component(&engine, testFile("singletonTest10.qml")); - VERIFY_ERRORS("singletonTest10.error.txt"); + VERIFY_ERRORS(0); } // Having a composite singleton type as dynamic signal parameter succeeds diff --git a/tests/auto/qmldevtools/compile/compile.pro b/tests/auto/qmldevtools/compile/compile.pro index 186ef71e8d..71d91c107d 100644 --- a/tests/auto/qmldevtools/compile/compile.pro +++ b/tests/auto/qmldevtools/compile/compile.pro @@ -12,3 +12,4 @@ macx:CONFIG -= app_bundle SOURCES += tst_compile.cpp +load(qt_common) diff --git a/tests/auto/quick/qquickborderimage/data/mesh.qml b/tests/auto/quick/qquickborderimage/data/mesh.qml new file mode 100644 index 0000000000..203bf25867 --- /dev/null +++ b/tests/auto/quick/qquickborderimage/data/mesh.qml @@ -0,0 +1,22 @@ +import QtQuick 2.8 + +Item { + width: 300 + height: 300 + Image { + id: image + source: "colors.png" + visible: false + } + ShaderEffect { + anchors.fill: parent + property variant source: image + mesh: BorderImageMesh { + border.left: 30 + border.right: 30 + border.top: 30 + border.bottom: 30 + size: image.sourceSize + } + } +} diff --git a/tests/auto/quick/qquickborderimage/data/nonmesh.qml b/tests/auto/quick/qquickborderimage/data/nonmesh.qml new file mode 100644 index 0000000000..7a1830a942 --- /dev/null +++ b/tests/auto/quick/qquickborderimage/data/nonmesh.qml @@ -0,0 +1,11 @@ +import QtQuick 2.8 + +BorderImage { + width: 300 + height: 300 + source: "colors.png" + border.left: 30 + border.right: 30 + border.top: 30 + border.bottom: 30 +} diff --git a/tests/auto/quick/qquickborderimage/qquickborderimage.pro b/tests/auto/quick/qquickborderimage/qquickborderimage.pro index 3e16063559..ba6c01737a 100644 --- a/tests/auto/quick/qquickborderimage/qquickborderimage.pro +++ b/tests/auto/quick/qquickborderimage/qquickborderimage.pro @@ -7,6 +7,7 @@ SOURCES += tst_qquickborderimage.cpp \ ../../shared/testhttpserver.cpp include (../../shared/util.pri) +include (../shared/util.pri) TESTDATA = data/* diff --git a/tests/auto/quick/qquickborderimage/tst_qquickborderimage.cpp b/tests/auto/quick/qquickborderimage/tst_qquickborderimage.cpp index c11ae1e8c9..e1435e739f 100644 --- a/tests/auto/quick/qquickborderimage/tst_qquickborderimage.cpp +++ b/tests/auto/quick/qquickborderimage/tst_qquickborderimage.cpp @@ -44,6 +44,7 @@ #include "../../shared/testhttpserver.h" #include "../../shared/util.h" +#include "../shared/visualtestutil.h" Q_DECLARE_METATYPE(QQuickImageBase::Status) @@ -75,6 +76,7 @@ private slots: void statusChanges_data(); void sourceSizeChanges(); void progressAndStatusChanges(); + void borderImageMesh(); private: QQmlEngine engine; @@ -575,6 +577,21 @@ void tst_qquickborderimage::progressAndStatusChanges() delete obj; } +void tst_qquickborderimage::borderImageMesh() +{ + QQuickView *window = new QQuickView; + + window->setSource(testFileUrl("nonmesh.qml")); + window->show(); + QTest::qWaitForWindowExposed(window); + QImage nonmesh = window->grabWindow(); + + window->setSource(testFileUrl("mesh.qml")); + QImage mesh = window->grabWindow(); + + QVERIFY(QQuickVisualTestUtil::compareImages(mesh, nonmesh)); +} + QTEST_MAIN(tst_qquickborderimage) #include "tst_qquickborderimage.moc" diff --git a/tests/auto/quick/qquickwindow/data/changeVisibilityInCompleted.qml b/tests/auto/quick/qquickwindow/data/changeVisibilityInCompleted.qml new file mode 100644 index 0000000000..48c4d1d69f --- /dev/null +++ b/tests/auto/quick/qquickwindow/data/changeVisibilityInCompleted.qml @@ -0,0 +1,47 @@ +import QtQuick 2.0 +import QtQuick.Window 2.1 + +Window { + width: 200 + height: 200 + + property var winVisible: subwin1 + property var winVisibility: subwin2 + + Rectangle { + anchors.fill: parent + color:"green" + } + + Window { + id: subwin1 + width: 200 + height: 200 + + visible: false + + Rectangle { + anchors.fill: parent + color:"red" + } + Component.onCompleted: { + subwin1.visible = true + } + } + Window { + id: subwin2 + width: 200 + height: 200 + + visible: true + visibility: Window.Maximized + + Rectangle { + anchors.fill: parent + color:"blue" + } + Component.onCompleted: { + subwin2.visibility = Window.Windowed + } + } +} diff --git a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp index 0e4ad86260..ff996e5362 100644 --- a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp +++ b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp @@ -348,6 +348,7 @@ private slots: void crashWhenHoverItemDeleted(); void unloadSubWindow(); + void changeVisibilityInCompleted(); void qobjectEventFilter_touch(); void qobjectEventFilter_key(); @@ -1865,6 +1866,28 @@ void tst_qquickwindow::unloadSubWindow() QTRY_VERIFY(transient.isNull() || !transient->isVisible()); } +// QTBUG-52573 +void tst_qquickwindow::changeVisibilityInCompleted() +{ + QQmlEngine engine; + QQmlComponent component(&engine); + component.loadUrl(testFileUrl("changeVisibilityInCompleted.qml")); + QScopedPointer<QQuickWindow> window(qobject_cast<QQuickWindow *>(component.create())); + QVERIFY(!window.isNull()); + window->setTitle(QTest::currentTestFunction()); + window->show(); + QTest::qWaitForWindowExposed(window.data()); + QPointer<QQuickWindow> winVisible; + QTRY_VERIFY(winVisible = window->property("winVisible").value<QQuickWindow*>()); + QPointer<QQuickWindow> winVisibility; + QTRY_VERIFY(winVisibility = window->property("winVisibility").value<QQuickWindow*>()); + QTest::qWaitForWindowExposed(winVisible); + QTest::qWaitForWindowExposed(winVisibility); + + QVERIFY(winVisible->isVisible()); + QCOMPARE(winVisibility->visibility(), QWindow::Windowed); +} + // QTBUG-32004 void tst_qquickwindow::qobjectEventFilter_touch() { diff --git a/tests/auto/quick/scenegraph/scenegraph.pro b/tests/auto/quick/scenegraph/scenegraph.pro index 320228bd08..40ff7750cc 100644 --- a/tests/auto/quick/scenegraph/scenegraph.pro +++ b/tests/auto/quick/scenegraph/scenegraph.pro @@ -3,6 +3,7 @@ TARGET = tst_scenegraph SOURCES += tst_scenegraph.cpp include (../../shared/util.pri) +include (../shared/util.pri) macx:CONFIG -= app_bundle diff --git a/tests/auto/quick/scenegraph/tst_scenegraph.cpp b/tests/auto/quick/scenegraph/tst_scenegraph.cpp index 6f00d5f9f2..91c872a36a 100644 --- a/tests/auto/quick/scenegraph/tst_scenegraph.cpp +++ b/tests/auto/quick/scenegraph/tst_scenegraph.cpp @@ -44,6 +44,10 @@ #include <private/qsgcontext_p.h> #include <private/qsgrenderloop_p.h> +#include "../shared/visualtestutil.h" + +using namespace QQuickVisualTestUtil; + class PerPixelRect : public QQuickItem { Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged) @@ -194,44 +198,6 @@ bool containsSomethingOtherThanWhite(const QImage &image) return false; } -// When running on native Nvidia graphics cards on linux, the -// distance field glyph pixels have a measurable, but not visible -// pixel error. Use a custom compare function to avoid -// -// This was GT-216 with the ubuntu "nvidia-319" driver package. -// llvmpipe does not show the same issue. -// -bool compareImages(const QImage &ia, const QImage &ib) -{ - if (ia.size() != ib.size()) - qDebug() << "images are of different size" << ia.size() << ib.size(); - Q_ASSERT(ia.size() == ib.size()); - Q_ASSERT(ia.format() == ib.format()); - - int w = ia.width(); - int h = ia.height(); - const int tolerance = 5; - for (int y=0; y<h; ++y) { - const uint *as= (const uint *) ia.constScanLine(y); - const uint *bs= (const uint *) ib.constScanLine(y); - for (int x=0; x<w; ++x) { - uint a = as[x]; - uint b = bs[x]; - - // No tolerance for error in the alpha. - if ((a & 0xff000000) != (b & 0xff000000)) - return false; - if (qAbs(qRed(a) - qRed(b)) > tolerance) - return false; - if (qAbs(qRed(a) - qRed(b)) > tolerance) - return false; - if (qAbs(qRed(a) - qRed(b)) > tolerance) - return false; - } - } - return true; -} - void tst_SceneGraph::manyWindows_data() { QTest::addColumn<QString>("file"); diff --git a/tests/auto/quick/shared/visualtestutil.cpp b/tests/auto/quick/shared/visualtestutil.cpp index 3e18c83ee2..eabfe5368b 100644 --- a/tests/auto/quick/shared/visualtestutil.cpp +++ b/tests/auto/quick/shared/visualtestutil.cpp @@ -61,3 +61,38 @@ void QQuickVisualTestUtil::dumpTree(QQuickItem *parent, int depth) } } +// A custom compare function to avoid issues such as: +// When running on native Nvidia graphics cards on linux, the +// distance field glyph pixels have a measurable, but not visible +// pixel error. This was GT-216 with the ubuntu "nvidia-319" driver package. +// llvmpipe does not show the same issue. +bool QQuickVisualTestUtil::compareImages(const QImage &ia, const QImage &ib) +{ + if (ia.size() != ib.size()) + qDebug() << "images are of different size" << ia.size() << ib.size(); + Q_ASSERT(ia.size() == ib.size()); + Q_ASSERT(ia.format() == ib.format()); + + int w = ia.width(); + int h = ia.height(); + const int tolerance = 5; + for (int y=0; y<h; ++y) { + const uint *as= (const uint *) ia.constScanLine(y); + const uint *bs= (const uint *) ib.constScanLine(y); + for (int x=0; x<w; ++x) { + uint a = as[x]; + uint b = bs[x]; + + // No tolerance for error in the alpha. + if ((a & 0xff000000) != (b & 0xff000000)) + return false; + if (qAbs(qRed(a) - qRed(b)) > tolerance) + return false; + if (qAbs(qRed(a) - qRed(b)) > tolerance) + return false; + if (qAbs(qRed(a) - qRed(b)) > tolerance) + return false; + } + } + return true; +} diff --git a/tests/auto/quick/shared/visualtestutil.h b/tests/auto/quick/shared/visualtestutil.h index 2b377a4bab..2daf86cd83 100644 --- a/tests/auto/quick/shared/visualtestutil.h +++ b/tests/auto/quick/shared/visualtestutil.h @@ -96,6 +96,8 @@ namespace QQuickVisualTestUtil items << qobject_cast<QQuickItem*>(findItem<T>(parent, objectName, indexes[i])); return items; } + + bool compareImages(const QImage &ia, const QImage &ib); } #define QQUICK_VERIFY_POLISH(item) \ |