diff options
38 files changed, 325 insertions, 64 deletions
diff --git a/examples/qml/doc/src/qml-extending.qdoc b/examples/qml/doc/src/qml-extending.qdoc index 8f44e4f506..f25b75ed29 100644 --- a/examples/qml/doc/src/qml-extending.qdoc +++ b/examples/qml/doc/src/qml-extending.qdoc @@ -63,6 +63,25 @@ loads and runs the QML snippet shown at the beginning of this page. */ /*! +\example referenceexamples/extended +\title Extending QML - Extension Objects Example +\brief Extension Objects +\ingroup qmlextendingexamples + +This example builds on: +\list +\li \l {Extending QML - Adding Types Example} +\endlist + +Shows how to use \l qmlRegisterExtendedType() to provide an \l {Registering +Extension Objects}{extension object} to a \l QLineEdit without modifying or +subclassing. The QML engine instantiates a \l QLineEdit and sets a property that +only exists on the extension type. The extension type performs calls on the \l +QLineEdit that otherwise will not be accessible to the QML engine. + +*/ + +/*! \example referenceexamples/properties \title Extending QML - Object and List Property Types Example \brief Exporting C++ Properties diff --git a/examples/quick/scenegraph/sgengine/window.cpp b/examples/quick/scenegraph/sgengine/window.cpp index 9af4029165..bc371a38f6 100644 --- a/examples/quick/scenegraph/sgengine/window.cpp +++ b/examples/quick/scenegraph/sgengine/window.cpp @@ -47,6 +47,7 @@ #include <QSGTransformNode> #include <QScreen> #include <QVariantAnimation> +#include <QOpenGLFunctions> class Item { public: @@ -213,13 +214,14 @@ void Window::initialize() m_sgRenderer->setClearColor(QColor(32, 32, 32)); // With QSGEngine::createTextureFromId + QOpenGLFunctions glFuncs(m_context.data()); GLuint glTexture; - glGenTextures(1, &glTexture); - glBindTexture(GL_TEXTURE_2D, glTexture); + glFuncs.glGenTextures(1, &glTexture); + glFuncs.glBindTexture(GL_TEXTURE_2D, glTexture); QImage smile = QImage(":/scenegraph/sgengine/face-smile.png").scaled(48, 48, Qt::KeepAspectRatio, Qt::SmoothTransformation); smile = smile.convertToFormat(QImage::Format_RGBA8888_Premultiplied); Q_ASSERT(!smile.isNull()); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, smile.width(), smile.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, smile.constBits()); + glFuncs.glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, smile.width(), smile.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, smile.constBits()); m_smileTexture.reset(m_sgEngine->createTextureFromId(glTexture, smile.size(), QFlag(QSGEngine::TextureOwnsGLTexture | QSGEngine::TextureHasAlphaChannel))); // With QSGEngine::createTextureFromImage diff --git a/src/3rdparty/masm/wtf/PrintStream.cpp b/src/3rdparty/masm/wtf/PrintStream.cpp index 3bf362e281..02dfb11b4f 100644 --- a/src/3rdparty/masm/wtf/PrintStream.cpp +++ b/src/3rdparty/masm/wtf/PrintStream.cpp @@ -82,12 +82,20 @@ void printInternal(PrintStream& out, unsigned long value) void printInternal(PrintStream& out, long long value) { +#if OS(WINDOWS) + out.printf("%I64d", value); +#else out.printf("%lld", value); +#endif } void printInternal(PrintStream& out, unsigned long long value) { +#if OS(WINDOWS) + out.printf("%I64u", value); +#else out.printf("%llu", value); +#endif } void printInternal(PrintStream& out, float value) diff --git a/src/imports/folderlistmodel/qquickfolderlistmodel.cpp b/src/imports/folderlistmodel/qquickfolderlistmodel.cpp index 2026cb83d8..3f7b0fc072 100644 --- a/src/imports/folderlistmodel/qquickfolderlistmodel.cpp +++ b/src/imports/folderlistmodel/qquickfolderlistmodel.cpp @@ -541,7 +541,7 @@ void QQuickFolderListModel::componentComplete() \list \li Unsorted - no sorting is applied. \li Name - sort by filename - \li LastModified - sort by time modified + \li Time - sort by time modified \li Size - sort by file size \li Type - sort by file type (extension) \endlist diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp index c2d123c96f..84e6c76cc4 100644 --- a/src/qml/compiler/qqmltypecompiler.cpp +++ b/src/qml/compiler/qqmltypecompiler.cpp @@ -1138,7 +1138,7 @@ bool QQmlEnumTypeResolver::tryQualifiedEnumAssignment(const QmlIR::Object *obj, if (!prop->isWritable() && !(binding->flags & QV4::CompiledData::Binding::InitializerForReadOnlyDeclaration)) COMPILE_EXCEPTION(binding, tr("Invalid property assignment: \"%1\" is a read-only property").arg(stringAt(binding->propertyNameIndex))); - Q_ASSERT(binding->type = QV4::CompiledData::Binding::Type_Script); + Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Script); const QString string = compiler->bindingAsString(obj, binding->value.compiledScriptIndex); if (!string.constData()->isUpper()) return true; diff --git a/src/qml/compiler/qv4ssa.cpp b/src/qml/compiler/qv4ssa.cpp index d89ea07087..c0a14a5c80 100644 --- a/src/qml/compiler/qv4ssa.cpp +++ b/src/qml/compiler/qv4ssa.cpp @@ -2543,17 +2543,21 @@ public: } else if (m->source->asConvert()) { break; } else if (Binop *b = m->source->asBinop()) { + bool iterateOnOperands = true; + switch (b->op) { + case OpSub: + case OpMul: case OpAdd: - if (b->left->type & NumberType || b->right->type & NumberType) + if (b->left->type == SInt32Type && b->right->type == SInt32Type) { + iterateOnOperands = false; break; - else + } else { continue; + } case OpBitAnd: case OpBitOr: case OpBitXor: - case OpSub: - case OpMul: case OpLShift: case OpRShift: case OpURShift: @@ -2561,10 +2565,13 @@ public: default: continue; } - if (Temp *lt = b->left->asTemp()) - candidates.append(*lt); - if (Temp *rt = b->right->asTemp()) - candidates.append(*rt); + + if (iterateOnOperands) { + if (Temp *lt = b->left->asTemp()) + candidates.append(*lt); + if (Temp *rt = b->right->asTemp()) + candidates.append(*rt); + } } else if (Unop *u = m->source->asUnop()) { if (u->op == OpCompl || u->op == OpUPlus) { if (Temp *t = u->expr->asTemp()) @@ -4033,8 +4040,7 @@ void optimizeSSA(StatementWorklist &W, DefUses &defUses, DominatorTree &df) default: break; } - if (casted) { - Q_ASSERT(casted->type == SInt32Type); + if (casted && casted->type == SInt32Type) { m->source = casted; W += m; continue; diff --git a/src/qml/doc/snippets/qml/statemachine/statemachine-button-history.qml b/src/qml/doc/snippets/qml/statemachine/statemachine-button-history.qml index 8f628232c1..c161a10610 100644 --- a/src/qml/doc/snippets/qml/statemachine/statemachine-button-history.qml +++ b/src/qml/doc/snippets/qml/statemachine/statemachine-button-history.qml @@ -58,7 +58,6 @@ Rectangle { } Button { id: quitButton - // change the button label to the active state id text: "quit" } } diff --git a/src/qml/doc/snippets/qml/statemachine/statemachine-button-nested-ignore-quit.qml b/src/qml/doc/snippets/qml/statemachine/statemachine-button-nested-ignore-quit.qml index bf84b4cc90..5bbd9ca9df 100644 --- a/src/qml/doc/snippets/qml/statemachine/statemachine-button-nested-ignore-quit.qml +++ b/src/qml/doc/snippets/qml/statemachine/statemachine-button-nested-ignore-quit.qml @@ -53,7 +53,6 @@ Rectangle { } Button { id: quitButton - // change the button label to the active state id text: "quit" } } diff --git a/src/qml/doc/snippets/qml/statemachine/statemachine-button-nested.qml b/src/qml/doc/snippets/qml/statemachine/statemachine-button-nested.qml index dfa093716f..932a9249d3 100644 --- a/src/qml/doc/snippets/qml/statemachine/statemachine-button-nested.qml +++ b/src/qml/doc/snippets/qml/statemachine/statemachine-button-nested.qml @@ -54,7 +54,6 @@ Rectangle { } Button { id: quitButton - // change the button label to the active state id text: "quit" } } diff --git a/src/qml/doc/src/cppintegration/definetypes.qdoc b/src/qml/doc/src/cppintegration/definetypes.qdoc index 03607df2e5..2f780503b2 100644 --- a/src/qml/doc/src/cppintegration/definetypes.qdoc +++ b/src/qml/doc/src/cppintegration/definetypes.qdoc @@ -294,6 +294,52 @@ This is useful when deriving from base classes provided by other authors, e.g. when extending classes from the Qt Quick module. +\section2 Registering Extension Objects + +When integrating existing classes and technology into QML, APIs will +often need tweaking to fit better into the declarative environment. +Although the best results are usually obtained by modifying the original +classes directly, if this is either not possible or is complicated by some +other concerns, extension objects allow limited extension possibilities +without direct modifications. + +\e{Extension objects} add additional properties to an existing type. Extension +objects can only add properties, not signals or methods. An extended type +definition allows the programmer to supply an additional type, known as the +\e{extension type}, when registering the class. The properties are transparently +merged with the original target class when used from within QML. For example: + +\snippet referenceexamples/extended/example.qml 0 + +The \c leftMargin property is a new property added to an existing C++ type, \l +QLineEdit, without modifying its source code. + +The \l qmlRegisterExtendedType() function is for registering extended types. +Note that it has two forms. + +\code +template<typename T, typename ExtendedT> +int qmlRegisterExtendedType(const char *uri, int versionMajor, int versionMinor, const char *qmlName) + +template<typename T, typename ExtendedT> +int qmlRegisterExtendedType() +\endcode + +This functions should be used instead of the regular \c qmlRegisterType() +variations. The arguments are identical to the corresponding non-extension +registration functions, except for the ExtendedT parameter which is the type of +the extension object. + +An extension class is a regular QObject, with a constructor that takes a QObject +pointer. However, the extension class creation is delayed until the first +extended property is accessed. The extension class is created and the target +object is passed in as the parent. When the property on the original is +accessed, the corresponding property on the extension object is used instead. + +The \l{Extending QML - Extension Objects Example}{Extension Objects Example} +demonstrates a usage of extension objects. + + \section1 Defining QML-Specific Types and Attributes diff --git a/src/qml/doc/src/qmlfunctions.qdoc b/src/qml/doc/src/qmlfunctions.qdoc index e95784dc5c..108b99277f 100644 --- a/src/qml/doc/src/qmlfunctions.qdoc +++ b/src/qml/doc/src/qmlfunctions.qdoc @@ -157,8 +157,25 @@ */ /*! - \fn int qmlRegisterExtendedUncreatableType(const char *uri, int versionMajor, int versionMinor, const char *qmlName, const QString& message) - \relates QQmlEgine + \fn int qmlRegisterExtendedType(const char *uri, int versionMajor, int versionMinor, const char *qmlName) + \relates QQmlEngine + + This template function registers the C++ type and its extension object in the + QML system with the name \a qmlName in the library imported from \a uri having + version number composed from \a versionMajor and \a versionMinor. Properties + not available in the main type will be searched for in the extension object. + + Returns the QML type id. + + #include <QtQml> to use this function. + + \sa qmlRegisterType(), {Registering Extension Objects} +*/ + + +/*! + \fn int qmlRegisterExtendedUncreatableType(const char *uri, int versionMajor, int versionMinor, const char *qmlName, const QString& reason) + \relates QQmlEngine This template function registers the C++ type and its extension in the QML system with the name \a qmlName in the library imported @@ -180,7 +197,8 @@ /*! \fn int qmlRegisterCustomExtendedType(const char *uri, int versionMajor, int versionMinor, const char *qmlName, QQmlCustomParser *parser) - \relates QQmlEgine + \relates QQmlEngine + \internal This template function registers the C++ type and its extension in the QML system with the name \a qmlName in the library imported diff --git a/src/qml/jsruntime/qv4context.cpp b/src/qml/jsruntime/qv4context.cpp index 85bcadd8d2..40c02ef4ee 100644 --- a/src/qml/jsruntime/qv4context.cpp +++ b/src/qml/jsruntime/qv4context.cpp @@ -475,3 +475,19 @@ ReturnedValue ExecutionContext::getPropertyAndBase(String *name, Heap::Object ** ScopedValue n(scope, name); return engine()->throwReferenceError(n); } + +Heap::FunctionObject *ExecutionContext::getFunctionObject() const +{ + Scope scope(d()->engine); + ScopedContext it(scope, this->d()); + for (; it; it = it->d()->parent) { + if (const CallContext *callCtx = it->asCallContext()) + return callCtx->d()->function; + else if (it->asCatchContext() || it->asWithContext()) + continue; // look in the parent context for a FunctionObject + else + break; + } + + return 0; +} diff --git a/src/qml/jsruntime/qv4context_p.h b/src/qml/jsruntime/qv4context_p.h index ea2d266146..48319c7444 100644 --- a/src/qml/jsruntime/qv4context_p.h +++ b/src/qml/jsruntime/qv4context_p.h @@ -154,6 +154,10 @@ struct Q_QML_EXPORT ExecutionContext : public Managed inline CallContext *asCallContext(); inline const CallContext *asCallContext() const; + inline const CatchContext *asCatchContext() const; + inline const WithContext *asWithContext() const; + + Heap::FunctionObject *getFunctionObject() const; static void markObjects(Heap::Base *m, ExecutionEngine *e); }; @@ -202,6 +206,16 @@ inline const CallContext *ExecutionContext::asCallContext() const return d()->type >= Heap::ExecutionContext::Type_SimpleCallContext ? static_cast<const CallContext *>(this) : 0; } +inline const CatchContext *ExecutionContext::asCatchContext() const +{ + return d()->type == Heap::ExecutionContext::Type_CatchContext ? static_cast<const CatchContext *>(this) : 0; +} + +inline const WithContext *ExecutionContext::asWithContext() const +{ + return d()->type == Heap::ExecutionContext::Type_WithContext ? static_cast<const WithContext *>(this) : 0; +} + /* Function *f, int argc */ #define requiredMemoryForExecutionContect(f, argc) \ ((sizeof(CallContext::Data) + 7) & ~7) + sizeof(Value) * (f->varCount() + qMax((uint)argc, f->formalParameterCount())) + sizeof(CallData) diff --git a/src/qml/jsruntime/qv4dateobject.cpp b/src/qml/jsruntime/qv4dateobject.cpp index 7f79de3035..4379e3ff94 100644 --- a/src/qml/jsruntime/qv4dateobject.cpp +++ b/src/qml/jsruntime/qv4dateobject.cpp @@ -482,6 +482,8 @@ static inline double ParseString(const QString &s) QDateTime dt = QDateTime::fromString(s, Qt::TextDate); if (!dt.isValid()) dt = QDateTime::fromString(s, Qt::ISODate); + if (!dt.isValid()) + dt = QDateTime::fromString(s, Qt::RFC2822Date); if (!dt.isValid()) { QStringList formats; formats << QStringLiteral("M/d/yyyy") diff --git a/src/qml/jsruntime/qv4debugging.cpp b/src/qml/jsruntime/qv4debugging.cpp index 9361fa1a23..01ee9585c3 100644 --- a/src/qml/jsruntime/qv4debugging.cpp +++ b/src/qml/jsruntime/qv4debugging.cpp @@ -523,7 +523,6 @@ void Debugger::maybeBreakAtInstruction() return; QMutexLocker locker(&m_lock); - int lineNumber = engine()->currentContext()->lineNumber; if (m_gatherSources) { m_gatherSources->run(); @@ -547,8 +546,12 @@ void Debugger::maybeBreakAtInstruction() if (m_pauseRequested) { // Serve debugging requests from the agent m_pauseRequested = false; pauseAndWait(PauseRequest); - } else if (m_haveBreakPoints && reallyHitTheBreakPoint(getFunction()->sourceFile(), lineNumber)) { - pauseAndWait(BreakPoint); + } else if (m_haveBreakPoints) { + if (Function *f = getFunction()) { + const int lineNumber = engine()->currentContext()->lineNumber; + if (reallyHitTheBreakPoint(f->sourceFile(), lineNumber)) + pauseAndWait(BreakPoint); + } } } @@ -594,12 +597,11 @@ Function *Debugger::getFunction() const { Scope scope(m_engine); ScopedContext context(scope, m_engine->currentContext()); - if (CallContext *callCtx = context->asCallContext()) - return callCtx->d()->function->function; - else { - Q_ASSERT(context->d()->type == QV4::Heap::ExecutionContext::Type_GlobalContext); + ScopedFunctionObject function(scope, context->getFunctionObject()); + if (function) + return function->function(); + else return context->d()->engine->globalCode; - } } void Debugger::pauseAndWait(PauseReason reason) diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index 4f8f329e2b..a51ea36351 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -762,21 +762,21 @@ QVector<StackFrame> ExecutionEngine::stackTrace(int frameLimit) const QVector<StackFrame> stack; ScopedContext c(scope, currentContext()); + ScopedFunctionObject function(scope); while (c && frameLimit) { - CallContext *callCtx = c->asCallContext(); - if (callCtx && callCtx->d()->function) { + function = c->getFunctionObject(); + if (function) { StackFrame frame; - ScopedFunctionObject function(scope, callCtx->d()->function); - if (function->function()) - frame.source = function->function()->sourceFile(); + if (const Function *f = function->function()) + frame.source = f->sourceFile(); name = function->name(); frame.function = name->toQString(); frame.line = -1; frame.column = -1; - if (callCtx->d()->function->function) + if (function->function()) // line numbers can be negative for places where you can't set a real breakpoint - frame.line = qAbs(callCtx->d()->lineNumber); + frame.line = qAbs(c->d()->lineNumber); stack.append(frame); --frameLimit; @@ -791,7 +791,6 @@ QVector<StackFrame> ExecutionEngine::stackTrace(int frameLimit) const frame.line = rootContext()->lineNumber; frame.column = -1; - stack.append(frame); } return stack; diff --git a/src/qml/jsruntime/qv4global_p.h b/src/qml/jsruntime/qv4global_p.h index 61cd53cd61..687ff19be4 100644 --- a/src/qml/jsruntime/qv4global_p.h +++ b/src/qml/jsruntime/qv4global_p.h @@ -69,9 +69,9 @@ inline double trunc(double d) { return d > 0 ? floor(d) : ceil(d); } // // NOTE: This should match the logic in qv4targetplatform_p.h! -#if defined(Q_PROCESSOR_X86) && (defined(Q_OS_WINDOWS) || defined(Q_OS_LINUX) || defined(Q_OS_QNX) || defined(Q_OS_FREEBSD)) +#if defined(Q_PROCESSOR_X86) && (defined(Q_OS_WIN) || defined(Q_OS_LINUX) || defined(Q_OS_QNX) || defined(Q_OS_FREEBSD)) #define V4_ENABLE_JIT -#elif defined(Q_PROCESSOR_X86_64) && (defined(Q_OS_WINDOWS) || defined(Q_OS_LINUX) || defined(Q_OS_MAC) || defined(Q_OS_FREEBSD)) +#elif defined(Q_PROCESSOR_X86_64) && (defined(Q_OS_WIN) || defined(Q_OS_LINUX) || defined(Q_OS_MAC) || defined(Q_OS_FREEBSD)) #define V4_ENABLE_JIT #elif defined(Q_PROCESSOR_ARM_32) diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp index 7ec66dd0e5..1248991789 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper.cpp +++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp @@ -814,13 +814,17 @@ struct QObjectSlotDispatcher : public QtPrivate::QSlotObjectBase f->call(callData); if (scope.hasException()) { + QQmlError error = v4->catchExceptionAsQmlError(); + if (error.description().isEmpty()) { + QV4::ScopedString name(scope, f->name()); + error.setDescription(QString::fromLatin1("Unknown exception occurred during evaluation of connected function: %1").arg(name->toQString())); + } if (QQmlEngine *qmlEngine = v4->qmlEngine()) { - QQmlError error = v4->catchExceptionAsQmlError(); - if (error.description().isEmpty()) { - QV4::ScopedString name(scope, f->name()); - error.setDescription(QString(QLatin1String("Unknown exception occurred during evaluation of connected function: %1")).arg(name->toQString())); - } QQmlEnginePrivate::get(qmlEngine)->warning(error); + } else { + QMessageLogger(error.url().toString().toLatin1().constData(), + error.line(), 0).warning().noquote() + << error.toString(); } } } diff --git a/src/quick/doc/snippets/qml/itemGrab.qml b/src/quick/doc/snippets/qml/itemGrab.qml index 4ceaea6133..c8ffd30edc 100644 --- a/src/quick/doc/snippets/qml/itemGrab.qml +++ b/src/quick/doc/snippets/qml/itemGrab.qml @@ -70,7 +70,7 @@ Image { // ... source.grabToImage(function(result) { - result.save("something.png"); + result.saveToFile("something.png"); }); //! [grab-to-file] diff --git a/src/quick/items/context2d/qquickcontext2d.cpp b/src/quick/items/context2d/qquickcontext2d.cpp index da4212e5b1..bc5fd8504f 100644 --- a/src/quick/items/context2d/qquickcontext2d.cpp +++ b/src/quick/items/context2d/qquickcontext2d.cpp @@ -4170,13 +4170,35 @@ QQuickContext2DTexture *QQuickContext2D::texture() const QImage QQuickContext2D::toImage(const QRectF& bounds) { - flush(); - if (m_texture->thread() == QThread::currentThread()) - m_texture->grabImage(bounds); - else if (m_renderStrategy == QQuickCanvasItem::Cooperative) { + if (m_texture->thread() == QThread::currentThread()) { + // if we're either not rendering to an fbo or we have a separate opengl context we can just + // flush. Otherwise we have to make sure the shared opengl context is current before we do + // so. It may or may not be current already, depending on how this method is called. + if (m_renderTarget != QQuickCanvasItem::FramebufferObject || m_glContext) { + flush(); + m_texture->grabImage(bounds); + } else { + QQuickWindow *window = m_canvas->window(); + QOpenGLContext *ctx = window ? window->openglContext() : 0; + if (ctx && ctx->isValid()) { + if (ctx == QOpenGLContext::currentContext()) { + flush(); + } else { + ctx->makeCurrent(window); + flush(); + ctx->doneCurrent(); + } + m_texture->grabImage(bounds); + } else { + qWarning() << "Cannot read pixels from canvas before opengl context is valid"; + return QImage(); + } + } + } else if (m_renderStrategy == QQuickCanvasItem::Cooperative) { qWarning() << "Pixel readback is not supported in Cooperative mode, please try Threaded or Immediate mode"; return QImage(); } else { + flush(); QCoreApplication::postEvent(m_texture, new QEvent(QEvent::Type(QEvent::User + 10))); QMetaObject::invokeMethod(m_texture, "grabImage", diff --git a/src/quick/items/qquickanimatedimage.cpp b/src/quick/items/qquickanimatedimage.cpp index 342394a74c..2fc00ad1d7 100644 --- a/src/quick/items/qquickanimatedimage.cpp +++ b/src/quick/items/qquickanimatedimage.cpp @@ -36,6 +36,7 @@ #ifndef QT_NO_MOVIE +#include <QtGui/qguiapplication.h> #include <QtQml/qqmlinfo.h> #include <QtQml/qqmlfile.h> #include <QtQml/qqmlengine.h> @@ -293,7 +294,13 @@ void QQuickAnimatedImage::load() if (isPlaying() != d->oldPlaying) emit playingChanged(); } else { - QString lf = QQmlFile::urlToLocalFileOrQrc(d->url); + const qreal targetDevicePixelRatio = (window() ? window()->effectiveDevicePixelRatio() : qApp->devicePixelRatio()); + d->devicePixelRatio = 1.0; + + QUrl loadUrl = d->url; + resolve2xLocalFile(d->url, targetDevicePixelRatio, &loadUrl, &d->devicePixelRatio); + QString lf = QQmlFile::urlToLocalFileOrQrc(loadUrl); + if (!lf.isEmpty()) { d->_movie = new QMovie(lf); movieRequestFinished(); diff --git a/src/quick/items/qquicktext.cpp b/src/quick/items/qquicktext.cpp index 87255f4bd9..be86b2976b 100644 --- a/src/quick/items/qquicktext.cpp +++ b/src/quick/items/qquicktext.cpp @@ -1166,6 +1166,17 @@ void QQuickTextPrivate::setLineGeometry(QTextLine &line, qreal lineWidth, qreal } /*! + Returns the y offset when aligning text with a non-1.0 lineHeight +*/ +int QQuickTextPrivate::lineHeightOffset() const +{ + QFontMetricsF fm(font); + qreal fontHeight = qCeil(fm.height()); // QScriptLine and therefore QTextLine rounds up + return lineHeightMode() == QQuickText::FixedHeight ? fontHeight - lineHeight() + : (1.0 - lineHeight()) * fontHeight; +} + +/*! Ensures the QQuickTextPrivate::doc variable is set to a valid text document */ void QQuickTextPrivate::ensureDoc() @@ -2090,7 +2101,7 @@ QRectF QQuickText::boundingRect() const QRectF rect = d->layedOutTextRect; rect.moveLeft(QQuickTextUtil::alignedX(rect.width(), width(), effectiveHAlign())); - rect.moveTop(QQuickTextUtil::alignedY(rect.height(), height(), d->vAlign)); + rect.moveTop(QQuickTextUtil::alignedY(rect.height() + d->lineHeightOffset(), height(), d->vAlign)); if (d->style != Normal) rect.adjust(-1, 0, 1, 2); @@ -2209,7 +2220,7 @@ QSGNode *QQuickText::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data d->updateType = QQuickTextPrivate::UpdateNone; - const qreal dy = QQuickTextUtil::alignedY(d->layedOutTextRect.height(), height(), d->vAlign); + const qreal dy = QQuickTextUtil::alignedY(d->layedOutTextRect.height() + d->lineHeightOffset(), height(), d->vAlign); QQuickTextNode *node = 0; if (!oldNode) @@ -2513,7 +2524,7 @@ QString QQuickTextPrivate::anchorAt(const QPointF &mousePos) const { Q_Q(const QQuickText); QPointF translatedMousePos = mousePos; - translatedMousePos.ry() -= QQuickTextUtil::alignedY(layedOutTextRect.height(), q->height(), vAlign); + translatedMousePos.ry() -= QQuickTextUtil::alignedY(layedOutTextRect.height() + lineHeightOffset(), q->height(), vAlign); if (styledText) { QString link = anchorAt(&layout, translatedMousePos); if (link.isEmpty() && elideLayout) @@ -2597,7 +2608,7 @@ bool QQuickTextPrivate::isLinkHoveredConnected() \qmlproperty string QtQuick::Text::hoveredLink \since 5.2 - This property contains the link string when user hovers a link + This property contains the link string when the user hovers a link embedded in the text. The link must be in rich text or HTML format and the \a hoveredLink string provides access to the particular link. diff --git a/src/quick/items/qquicktext_p_p.h b/src/quick/items/qquicktext_p_p.h index 3b83d37899..0acd77aab8 100644 --- a/src/quick/items/qquicktext_p_p.h +++ b/src/quick/items/qquicktext_p_p.h @@ -76,6 +76,7 @@ public: bool isLineLaidOutConnected(); void setLineGeometry(QTextLine &line, qreal lineWidth, qreal &height); + int lineHeightOffset() const; QString elidedText(qreal lineWidth, const QTextLine &line, QTextLine *nextLine = 0) const; void elideFormats(int start, int length, int offset, QList<QTextLayout::FormatRange> *elidedFormats); diff --git a/src/quick/items/qquicktextedit.cpp b/src/quick/items/qquicktextedit.cpp index c46df8f1b0..3446f65c19 100644 --- a/src/quick/items/qquicktextedit.cpp +++ b/src/quick/items/qquicktextedit.cpp @@ -175,7 +175,7 @@ QQuickTextEdit::QQuickTextEdit(QQuickItem *parent) QString QQuickTextEdit::text() const { Q_D(const QQuickTextEdit); - if (!d->textCached) { + if (!d->textCached && isComponentComplete()) { QQuickTextEditPrivate *d = const_cast<QQuickTextEditPrivate *>(d_func()); #ifndef QT_NO_TEXTHTMLPARSER if (d->richText) @@ -2578,7 +2578,7 @@ bool QQuickTextEditPrivate::isLinkHoveredConnected() \qmlproperty string QtQuick::TextEdit::hoveredLink \since 5.2 - This property contains the link string when user hovers a link + This property contains the link string when the user hovers a link embedded in the text. The link must be in rich text or HTML format and the link string provides access to the particular link. diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp index aef5b4ee79..fd9b2a4480 100644 --- a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp +++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp @@ -2828,7 +2828,10 @@ void Renderer::visualizeBatch(Batch *b) g = gn->geometry(); shader->setUniformValue(shader->matrix, matrix * *gn->matrix()); glVertexAttribPointer(a.position, a.tupleSize, a.type, false, g->sizeOfVertex(), (void *) (qintptr) offset); - glDrawElements(g->drawingMode(), g->indexCount(), g->indexType(), g->indexData()); + if (g->indexCount()) + glDrawElements(g->drawingMode(), g->indexCount(), g->indexType(), g->indexData()); + else + glDrawArrays(g->drawingMode(), 0, g->vertexCount()); offset += g->sizeOfVertex() * g->vertexCount(); e = e->nextInBatch; } diff --git a/src/quick/scenegraph/qsgwindowsrenderloop.cpp b/src/quick/scenegraph/qsgwindowsrenderloop.cpp index 58d618a049..9f74e259e3 100644 --- a/src/quick/scenegraph/qsgwindowsrenderloop.cpp +++ b/src/quick/scenegraph/qsgwindowsrenderloop.cpp @@ -437,7 +437,7 @@ void QSGWindowsRenderLoop::renderWindow(QQuickWindow *window) d->fireFrameSwapped(); qCDebug(QSG_LOG_TIME_RENDERLOOP()).nospace() - << "Frame rendered with 'windows' renderloop in: " << time_swapped << "ms" + << "Frame rendered with 'windows' renderloop in: " << (time_swapped - time_start) / 1000000 << "ms" << ", polish=" << (time_polished - time_start) / 1000000 << ", sync=" << (time_synced - time_polished) / 1000000 << ", render=" << (time_rendered - time_synced) / 1000000 diff --git a/src/quick/scenegraph/shaders/visualization.frag b/src/quick/scenegraph/shaders/visualization.frag index 6cfeac1985..458d9dde14 100644 --- a/src/quick/scenegraph/shaders/visualization.frag +++ b/src/quick/scenegraph/shaders/visualization.frag @@ -6,6 +6,6 @@ varying mediump vec2 pos; void main(void) { lowp vec4 c = color; - c.xyz += pow(max(sin(pos.x + pos.y), 0.0), 2.0) * pattern * 0.1; + c.xyz += pow(max(sin(pos.x + pos.y), 0.0), 2.0) * pattern * 0.25; gl_FragColor = c; } diff --git a/src/quickwidgets/qquickwidget.cpp b/src/quickwidgets/qquickwidget.cpp index 83fe586cb8..6143e4ef0d 100644 --- a/src/quickwidgets/qquickwidget.cpp +++ b/src/quickwidgets/qquickwidget.cpp @@ -246,6 +246,11 @@ QImage QQuickWidgetPrivate::grabFramebuffer() return renderControl->grab(); } +QObject *QQuickWidgetPrivate::focusObject() +{ + return offscreenWindow ? offscreenWindow->focusObject() : 0; +} + /*! \module QtQuickWidgets \title Qt Quick Widgets C++ Classes @@ -1086,6 +1091,9 @@ bool QQuickWidget::event(QEvent *e) e->accept(); return true; #endif + case QEvent::InputMethod: + case QEvent::InputMethodQuery: + case QEvent::TouchBegin: case QEvent::TouchEnd: case QEvent::TouchUpdate: diff --git a/src/quickwidgets/qquickwidget_p.h b/src/quickwidgets/qquickwidget_p.h index 2ff9601f77..57782a6492 100644 --- a/src/quickwidgets/qquickwidget_p.h +++ b/src/quickwidgets/qquickwidget_p.h @@ -81,6 +81,8 @@ public: void destroyContext(); void handleContextCreationFailure(const QSurfaceFormat &format, bool isEs); + QObject *focusObject() Q_DECL_OVERRIDE; + GLuint textureId() const Q_DECL_OVERRIDE; QImage grabFramebuffer() Q_DECL_OVERRIDE; diff --git a/tests/auto/qml/qjsengine/tst_qjsengine.cpp b/tests/auto/qml/qjsengine/tst_qjsengine.cpp index 13e60fefd9..9f86c8e4e1 100644 --- a/tests/auto/qml/qjsengine/tst_qjsengine.cpp +++ b/tests/auto/qml/qjsengine/tst_qjsengine.cpp @@ -175,6 +175,7 @@ private slots: void privateMethods(); void engineForObject(); + void intConversion_QTBUG43309(); signals: void testSignal(); @@ -3639,6 +3640,16 @@ void tst_QJSEngine::engineForObject() QVERIFY(!qjsEngine(&object)); } +void tst_QJSEngine::intConversion_QTBUG43309() +{ + // This failed in the interpreter: + QJSEngine engine; + QString jsCode = "var n = 0.1; var m = (n*255) | 0; m"; + QJSValue result = engine.evaluate( jsCode ); + QVERIFY(result.isNumber()); + QCOMPARE(result.toNumber(), 25.0); +} + QTEST_MAIN(tst_QJSEngine) #include "tst_qjsengine.moc" diff --git a/tests/auto/qml/qqmlecmascript/data/date.qml b/tests/auto/qml/qqmlecmascript/data/date.qml index 0dcba71ae3..41dcaafa33 100644 --- a/tests/auto/qml/qqmlecmascript/data/date.qml +++ b/tests/auto/qml/qqmlecmascript/data/date.qml @@ -17,4 +17,10 @@ Item { var dt = new Date(""); return isNaN(dt); } + + function test_rfc2822_date() + { + var dt = new Date("Wed, 18 Sep 2013 07:00:51 -0700"); + return dt.getTime(); + } } diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp index e137f6b042..8b95770312 100644 --- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp +++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp @@ -7360,7 +7360,8 @@ void tst_qqmlecmascript::dateParse() QMetaObject::invokeMethod(object, "test_is_invalid_qtDateTime", Q_RETURN_ARG(QVariant, q)); QVERIFY(q.toBool() == true); - + QMetaObject::invokeMethod(object, "test_rfc2822_date", Q_RETURN_ARG(QVariant, q)); + QCOMPARE(q.toLongLong(), 1379512851000LL); } void tst_qqmlecmascript::utcDate() diff --git a/tests/auto/qml/qv4debugger/tst_qv4debugger.cpp b/tests/auto/qml/qv4debugger/tst_qv4debugger.cpp index 70e6739aff..628cd143cf 100644 --- a/tests/auto/qml/qv4debugger/tst_qv4debugger.cpp +++ b/tests/auto/qml/qv4debugger/tst_qv4debugger.cpp @@ -287,6 +287,8 @@ private slots: // exceptions: void pauseOnThrow(); + void breakInCatch(); + void breakInWith(); void evaluateExpression(); @@ -613,6 +615,42 @@ void tst_qv4debugger::pauseOnThrow() QCOMPARE(m_debuggerAgent->m_thrownValue.toString(), QString("hard")); } +void tst_qv4debugger::breakInCatch() +{ + QString script = + "try {\n" + " throw 'catch...'\n" + "} catch (e) {\n" + " console.log(e, 'me');\n" + "}\n"; + + m_debuggerAgent->addBreakPoint("breakInCatch", 4); + evaluateJavaScript(script, "breakInCatch"); + QVERIFY(m_debuggerAgent->m_wasPaused); + QCOMPARE(m_debuggerAgent->m_pauseReason, BreakPoint); + QCOMPARE(m_debuggerAgent->m_statesWhenPaused.count(), 1); + QV4::Debugging::Debugger::ExecutionState state = m_debuggerAgent->m_statesWhenPaused.first(); + QCOMPARE(state.fileName, QString("breakInCatch")); + QCOMPARE(state.lineNumber, 4); +} + +void tst_qv4debugger::breakInWith() +{ + QString script = + "with (42) {\n" + " console.log('give the answer');\n" + "}\n"; + + m_debuggerAgent->addBreakPoint("breakInWith", 2); + evaluateJavaScript(script, "breakInWith"); + QVERIFY(m_debuggerAgent->m_wasPaused); + QCOMPARE(m_debuggerAgent->m_pauseReason, BreakPoint); + QCOMPARE(m_debuggerAgent->m_statesWhenPaused.count(), 1); + QV4::Debugging::Debugger::ExecutionState state = m_debuggerAgent->m_statesWhenPaused.first(); + QCOMPARE(state.fileName, QString("breakInWith")); + QCOMPARE(state.lineNumber, 2); +} + void tst_qv4debugger::evaluateExpression() { QString script = diff --git a/tests/auto/quick/nokeywords/tst_nokeywords.cpp b/tests/auto/quick/nokeywords/tst_nokeywords.cpp index 1a20649b2d..ddd9dccf4f 100644 --- a/tests/auto/quick/nokeywords/tst_nokeywords.cpp +++ b/tests/auto/quick/nokeywords/tst_nokeywords.cpp @@ -87,7 +87,13 @@ Q_SIGNALS: void mySignal(); public Q_SLOTS: - inline void mySlot() { mySignal(); } + inline void mySlot() + { + Q_UNUSED(signals); + Q_UNUSED(slots); + + mySignal(); + } private: int signals; diff --git a/tests/auto/quick/qquickpixmapcache/tst_qquickpixmapcache.cpp b/tests/auto/quick/qquickpixmapcache/tst_qquickpixmapcache.cpp index db69020589..83c678214d 100644 --- a/tests/auto/quick/qquickpixmapcache/tst_qquickpixmapcache.cpp +++ b/tests/auto/quick/qquickpixmapcache/tst_qquickpixmapcache.cpp @@ -113,7 +113,7 @@ void tst_qquickpixmapcache::initTestCase() // This avoids a race condition/deadlock bug in network config // manager when it is accessed by the HTTP server thread before // anything else. Bug report can be found at: - // https://bugreports.qt-project.org/browse/QTBUG-26355 + // QTBUG-26355 QNetworkConfigurationManager cm; cm.updateConfigurations(); diff --git a/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp b/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp index 4f10b4ce82..c61504ef99 100644 --- a/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp +++ b/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp @@ -201,6 +201,7 @@ private slots: void emptytags_QTBUG_22058(); void cursorRectangle_QTBUG_38947(); + void textCached_QTBUG_41583(); private: void simulateKeys(QWindow *window, const QList<Key> &keys); @@ -5302,6 +5303,17 @@ void tst_qquicktextedit::cursorRectangle_QTBUG_38947() QTest::mouseRelease(&window, Qt::LeftButton, Qt::NoModifier, to); } +void tst_qquicktextedit::textCached_QTBUG_41583() +{ + QQmlComponent component(&engine); + component.setData("import QtQuick 2.0\nTextEdit { property int margin: 10; text: \"TextEdit\"; textMargin: margin; property bool empty: !text; }", QUrl()); + QQuickTextEdit *textedit = qobject_cast<QQuickTextEdit*>(component.create()); + QVERIFY(textedit); + QCOMPARE(textedit->textMargin(), qreal(10.0)); + QCOMPARE(textedit->text(), QString("TextEdit")); + QVERIFY(!textedit->property("empty").toBool()); +} + QTEST_MAIN(tst_qquicktextedit) #include "tst_qquicktextedit.moc" diff --git a/tests/testapplications/elements/content/BugPanel.qml b/tests/testapplications/elements/content/BugPanel.qml index 48de12ab15..fcbdd941bc 100644 --- a/tests/testapplications/elements/content/BugPanel.qml +++ b/tests/testapplications/elements/content/BugPanel.qml @@ -37,7 +37,7 @@ Rectangle { property string urltext urltext: "<a href=\"" + bugreports + bugnumber + "\">QTBUG-" + bugnumber + "</a>" property string bugnumber: "" - property string bugreports: "http://bugreports.qt-project.org/browse/QTBUG-" + property string bugreports: "http://bugreports.qt.io/browse/QTBUG-" visible: opacity != 0 opacity: bugnumber == "" ? 0 : 1 Behavior on opacity { NumberAnimation { duration: 1500 } } diff --git a/tools/qmljs/qmljs.cpp b/tools/qmljs/qmljs.cpp index c9765c57df..f4a561fac6 100644 --- a/tools/qmljs/qmljs.cpp +++ b/tools/qmljs/qmljs.cpp @@ -166,7 +166,7 @@ int main(int argc, char *argv[]) } if (args.first() == QLatin1String("--help")) { - std::cerr << "Usage: qmljs [|--debug|-d] [|--jit|--interpret|--compile|--aot|--llvm-jit] file..." << std::endl; + std::cerr << "Usage: qmljs [|--jit|--interpret|--qml] file..." << std::endl; return EXIT_SUCCESS; } } |