Merge remote-tracking branch 'origin/5.5' into dev
authorSimon Hausmann <simon.hausmann@theqtcompany.com>
Thu, 4 Jun 2015 08:24:46 +0000 (10:24 +0200)
committerSimon Hausmann <simon.hausmann@theqtcompany.com>
Thu, 4 Jun 2015 08:28:48 +0000 (10:28 +0200)
Conflicts:
src/qml/jsruntime/qv4engine_p.h
src/quick/items/qquickitemsmodule.cpp
src/quick/items/qquicktext.cpp
src/quick/util/qquickpixmapcache.cpp
tests/auto/quick/qquickwindow/tst_qquickwindow.cpp

Change-Id: I90ecaad6a4bfaa4f36149a7463f4d7141f4a516a

29 files changed:
1  2 
src/qml/compiler/qqmlirbuilder.cpp
src/qml/compiler/qv4codegen.cpp
src/qml/compiler/qv4compiler.cpp
src/qml/jsruntime/qv4arraydata.cpp
src/qml/jsruntime/qv4engine.cpp
src/qml/jsruntime/qv4engine_p.h
src/qml/jsruntime/qv4qobjectwrapper.cpp
src/qml/jsruntime/qv4qobjectwrapper_p.h
src/qml/memory/qv4mm.cpp
src/qml/qml/qqmldata_p.h
src/qml/qml/qqmlvmemetaobject.cpp
src/qml/qml/qqmlxmlhttprequest.cpp
src/quick/items/qquickimage_p.h
src/quick/items/qquickitemsmodule.cpp
src/quick/items/qquicktext.cpp
src/quick/items/qquicktextedit.cpp
src/quick/items/qquicktextinput.cpp
src/quick/items/qquickwindow.cpp
src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp
src/quick/scenegraph/qsgrenderloop.cpp
src/quick/scenegraph/qsgthreadedrenderloop.cpp
src/quick/util/qquickimageprovider.h
src/quick/util/qquickpixmapcache.cpp
src/quick/util/qquicktimeline.cpp
src/quickwidgets/qquickwidget.cpp
tests/auto/quick/qquicktext/tst_qquicktext.cpp
tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp
tests/auto/quick/qquickwindow/tst_qquickwindow.cpp
tools/qmllint/main.cpp

Simple merge
Simple merge
Simple merge
Simple merge
@@@ -1219,10 -1262,12 +1219,12 @@@ static QVariant toVariant(QV4::Executio
          return value.asDouble();
      if (value.isString())
          return value.stringValue()->toQString();
 -    if (QV4::QQmlLocaleData *ld = value.as<QV4::QQmlLocaleData>())
 +    if (const QV4::QQmlLocaleData *ld = value.as<QV4::QQmlLocaleData>())
          return ld->d()->locale;
 -    if (QV4::DateObject *d = value.asDateObject())
 +    if (const QV4::DateObject *d = value.as<DateObject>())
          return d->toQDateTime();
 -    if (QV4::ArrayBuffer *d = value.as<ArrayBuffer>())
++    if (const QV4::ArrayBuffer *d = value.as<ArrayBuffer>())
+         return d->asByteArray();
      // NOTE: since we convert QTime to JS Date, round trip will change the variant type (to QDateTime)!
  
      QV4::ScopedObject o(scope, value);
@@@ -1580,6 -1625,13 +1582,12 @@@ QV4::ReturnedValue ExecutionEngine::met
      return 0;
  }
  
 -void ExecutionEngine::assertObjectBelongsToEngine(const Value &v)
++void ExecutionEngine::assertObjectBelongsToEngine(const Heap::Base &baseObject)
+ {
 -    Q_UNUSED(v);
 -    Q_ASSERT(!v.isObject() || v.objectValue()->engine() == this);
 -    Q_UNUSED(v);
++    Q_ASSERT(!baseObject.vtable->isObject || static_cast<const Heap::Object&>(baseObject).internalClass->engine == this);
++    Q_UNUSED(baseObject);
+ }
  // Converts a JS value to a meta-type.
  // data must point to a place that can store a value of the given type.
  // Returns true if conversion succeeded, false otherwise.
@@@ -392,6 -340,8 +392,8 @@@ public
      bool metaTypeFromJS(const Value &value, int type, void *data);
      QV4::ReturnedValue metaTypeToJS(int type, const void *data);
  
 -    void assertObjectBelongsToEngine(const Value &v);
++    void assertObjectBelongsToEngine(const Heap::Base &baseObject);
  private:
      QmlExtensions *m_qmlExtensions;
  };
@@@ -426,23 -376,29 +428,26 @@@ Heap::ExecutionContext::ExecutionContex
  }
  
  
 -// ### Remove me
  inline
 -void Managed::mark(QV4::ExecutionEngine *engine)
 +void Heap::Base::mark(QV4::ExecutionEngine *engine)
  {
      Q_ASSERT(inUse());
 -    if (markBit())
 +    if (isMarked())
          return;
 -    d()->setMarkBit();
 -    engine->pushForGC(d());
+ #ifndef QT_NO_DEBUG
+     engine->assertObjectBelongsToEngine(*this);
+ #endif
 +    setMarkBit();
 +    engine->pushForGC(this);
  }
  
 -
 -inline
 -void Heap::Base::mark(QV4::ExecutionEngine *engine)
 +inline void Value::mark(ExecutionEngine *e)
  {
 -    Q_ASSERT(inUse());
 -    if (isMarked())
 +    if (!val)
          return;
 -    setMarkBit();
 -    engine->pushForGC(this);
 +    Managed *m = as<Managed>();
 +    if (m)
 +        m->d()->mark(e);
  }
  
  
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
@@@ -259,16 -267,7 +259,17 @@@ static void qt_quickitems_defineModule(
      qmlRegisterUncreatableType<QQuickOpenGLInfo>(uri, 2, 4,"OpenGLInfo", QQuickOpenGLInfo::tr("OpenGLInfo is only available via attached properties"));
  
      qmlRegisterType<QQuickPinchArea, 1>(uri, 2, 5,"PinchArea");
+     qmlRegisterType<QQuickImage, 2>(uri, 2, 5,"Image");
 +
 +    qmlRegisterType<QQuickText, 6>(uri, 2, 6, "Text");
 +    qmlRegisterType<QQuickTextEdit, 6>(uri, 2, 6, "TextEdit");
 +    qmlRegisterType<QQuickTextInput, 6>(uri, 2, 6, "TextInput");
 +    qmlRegisterUncreatableType<QQuickBasePositioner, 6>(uri, 2, 6, "Positioner",
 +                                                  QStringLiteral("Positioner is an abstract type that is only available as an attached property."));
 +    qmlRegisterType<QQuickColumn, 6>(uri, 2, 6, "Column");
 +    qmlRegisterType<QQuickRow, 6>(uri, 2, 6, "Row");
 +    qmlRegisterType<QQuickGrid, 6>(uri, 2, 6, "Grid");
 +    qmlRegisterType<QQuickFlow, 6>(uri, 2, 6, "Flow");
  }
  
  static void initResources()
@@@ -809,7 -729,7 +809,7 @@@ QRectF QQuickTextPrivate::setupTextLayo
      lineWidth = (q->widthValid() || implicitWidthValid) && q->width() > 0
              ? q->width()
              : FLT_MAX;
--    qreal maxHeight = q->heightValid() ? q->height() : FLT_MAX;
++    qreal maxHeight = q->heightValid() ? availableHeight() : FLT_MAX;
  
      const bool customLayout = isLineLaidOutConnected();
      const bool wasTruncated = truncated;
              : largeFont;
      int scaledFontSize = largeFont;
  
 -    widthExceeded = q->width() <= 0 && (singlelineElide || canWrap || horizontalFit);
 -    heightExceeded = q->height() <= 0 && (multilineElide || verticalFit);
+     bool widthChanged = false;
 +    widthExceeded = availableWidth() <= 0 && (singlelineElide || canWrap || horizontalFit);
 +    heightExceeded = availableHeight() <= 0 && (multilineElide || verticalFit);
  
      QRectF br;
  
                  heightExceeded = false;
                  continue;
              }
 -            maxHeight = q->heightValid() ? q->height() : FLT_MAX;
+         } else if (widthChanged) {
+             widthChanged = false;
+             if (line.isValid()) {
+                 for (int lineCount = layout.lineCount(); lineCount < maxLineCount; ++lineCount) {
+                     line = layout.createLine();
+                     if (!line.isValid())
+                         break;
+                     setLineGeometry(line, lineWidth, naturalHeight);
+                 }
+             }
+             layout.endLayout();
+             bool wasInLayout = internalWidthUpdate;
+             internalWidthUpdate = true;
+             q->setImplicitHeight(naturalHeight);
+             internalWidthUpdate = wasInLayout;
+             multilineElide = elideMode == QQuickText::ElideRight
+                     && q->widthValid()
+                     && (q->heightValid() || maximumLineCountValid);
+             verticalFit = fontSizeMode() & QQuickText::VerticalFit
+                     && (q->heightValid() || (maximumLineCountValid && canWrap));
+             const qreal oldHeight = maxHeight;
++            maxHeight = q->heightValid() ? availableHeight() : FLT_MAX;
+             // If the height of the item has changed and it's possible the result of eliding,
+             // line count truncation or scaling has changed, do another layout.
+             if ((maxHeight < qMin(oldHeight, naturalHeight) || (heightExceeded && maxHeight > oldHeight))
+                     && (multilineElide || (canWrap && maximumLineCountValid))) {
+                 widthExceeded = false;
+                 heightExceeded = false;
+                 continue;
+             }
          } else {
              layout.endLayout();
          }
Simple merge
Simple merge
Simple merge
Simple merge
@@@ -193,9 -205,8 +195,9 @@@ protected
  private:
      friend class QQuickPixmapReaderThreadObject;
      void processJobs();
-     void processJob(QQuickPixmapReply *, const QUrl &, const QString &, QQuickImageProvider::ImageType, QQuickImageProvider *);
 -    void processJob(QQuickPixmapReply *, const QUrl &, const QSize &, AutoTransform);
++    void processJob(QQuickPixmapReply *, const QUrl &, const QString &, AutoTransform, QQuickImageProvider::ImageType, QQuickImageProvider *);
      void networkRequestDone(QNetworkReply *);
 +    void asyncResponseFinished(QQuickImageResponse *);
  
      QList<QQuickPixmapReply*> jobs;
      QList<QQuickPixmapReply*> cancelled;
@@@ -599,8 -577,10 +615,9 @@@ void QQuickPixmapReader::processJobs(
  
                      PIXMAP_PROFILE(pixmapStateChanged<QQuickProfiler::PixmapLoadingStarted>(url));
  
 -                    QSize requestSize = runningJob->requestSize;
 -                    AutoTransform autoTransform = runningJob->autoTransform;
++                    AutoTransform autoTransform = job->autoTransform;
                      locker.unlock();
-                     processJob(job, url, localFile, imageType, provider);
 -                    processJob(runningJob, url, requestSize, autoTransform);
++                    processJob(job, url, localFile, autoTransform, imageType, provider);
                      locker.relock();
                  }
              }
      }
  }
  
 -void QQuickPixmapReader::processJob(QQuickPixmapReply *runningJob, const QUrl &url,
 -                                    const QSize &requestSize, AutoTransform autoTransform)
 +void QQuickPixmapReader::processJob(QQuickPixmapReply *runningJob, const QUrl &url, const QString &localFile,
-                                           QQuickImageProvider::ImageType imageType, QQuickImageProvider *provider)
++                                    AutoTransform autoTransform, QQuickImageProvider::ImageType imageType, QQuickImageProvider *provider)
  {
      // fetch
      if (url.scheme() == QLatin1String("image")) {
              QImage image;
              QQuickPixmapReply::ReadError errorCode = QQuickPixmapReply::NoError;
              QString errorStr;
 -            QFile f(lf);
 +            QFile f(localFile);
              QSize readSize;
              if (f.open(QIODevice::ReadOnly)) {
-                 if (!readImage(url, &f, &image, &errorStr, &readSize, runningJob->requestSize))
 -                if (!readImage(url, &f, &image, &errorStr, &readSize, requestSize, autoTransform))
++                if (!readImage(url, &f, &image, &errorStr, &readSize, runningJob->requestSize, autoTransform))
                      errorCode = QQuickPixmapReply::Loading;
              } else {
                  errorStr = QQuickPixmap::tr("Cannot open: %1").arg(url.toString());
@@@ -809,9 -772,11 +827,9 @@@ inline bool operator==(const QQuickPixm
  
  inline uint qHash(const QQuickPixmapKey &key)
  {
-     return qHash(*key.url) ^ key.size->width() ^ key.size->height();
+     return qHash(*key.url) ^ (key.size->width()*7) ^ (key.size->height()*17) ^ (key.autoTransform * 0x5c5c5c5c);
  }
  
 -class QSGContext;
 -
  class QQuickPixmapStore : public QObject
  {
      Q_OBJECT
@@@ -1118,7 -1084,7 +1137,7 @@@ static QQuickPixmapData* createPixmapDa
                  QImage image = provider->requestImage(imageId(url), &readSize, requestSize);
                  if (!image.isNull()) {
                      *ok = true;
-                     return new QQuickPixmapData(declarativePixmap, url, QQuickTextureFactory::textureFactoryForImage(image), readSize, requestSize);
 -                    return new QQuickPixmapData(declarativePixmap, url, textureFactoryForImage(image), readSize, requestSize, autoTransform, UsePluginDefault);
++                    return new QQuickPixmapData(declarativePixmap, url, QQuickTextureFactory::textureFactoryForImage(image), readSize, requestSize, autoTransform, UsePluginDefault);
                  }
              }
              case QQuickImageProvider::Pixmap:
                  QPixmap pixmap = provider->requestPixmap(imageId(url), &readSize, requestSize);
                  if (!pixmap.isNull()) {
                      *ok = true;
-                     return new QQuickPixmapData(declarativePixmap, url, QQuickTextureFactory::textureFactoryForImage(pixmap.toImage()), readSize, requestSize);
 -                    return new QQuickPixmapData(declarativePixmap, url, textureFactoryForImage(pixmap.toImage()), readSize, requestSize, autoTransform, UsePluginDefault);
++                    return new QQuickPixmapData(declarativePixmap, url, QQuickTextureFactory::textureFactoryForImage(pixmap.toImage()), readSize, requestSize, autoTransform, UsePluginDefault);
                  }
              }
 +            case QQuickImageProvider::ImageResponse:
 +            {
 +                // Fall through, ImageResponse providers never get here
 +                Q_ASSERT(imageType != QQuickImageProvider::ImageResponse && "Sync call to ImageResponse provider");
 +            }
          }
  
          // provider has bad image type, or provider returned null image
  
      if (f.open(QIODevice::ReadOnly)) {
          QImage image;
-         if (readImage(url, &f, &image, &errorString, &readSize, requestSize)) {
+         AutoTransform appliedTransform = autoTransform;
+         if (readImage(url, &f, &image, &errorString, &readSize, requestSize, appliedTransform)) {
              *ok = true;
-             return new QQuickPixmapData(declarativePixmap, url, QQuickTextureFactory::textureFactoryForImage(image), readSize, requestSize);
 -            return new QQuickPixmapData(declarativePixmap, url, textureFactoryForImage(image), readSize, requestSize, autoTransform, appliedTransform);
++            return new QQuickPixmapData(declarativePixmap, url, QQuickTextureFactory::textureFactoryForImage(image), readSize, requestSize, autoTransform, appliedTransform);
          }
          errorString = QQuickPixmap::tr("Invalid image data: %1").arg(url.toString());
  
Simple merge
Simple merge
@@@ -621,8 -633,9 +633,9 @@@ void tst_qquickwindow::touchEvent_propa
  
      window->resize(250, 250);
      window->setPosition(100, 100);
+     window->setTitle(QTest::currentTestFunction());
      window->show();
 -    QVERIFY(QTest::qWaitForWindowExposed(window));
 +    QVERIFY(QTest::qWaitForWindowActive(window));
  
      TestTouchItem *bottomItem = new TestTouchItem(window->contentItem());
      bottomItem->setObjectName("Bottom Item");
@@@ -754,8 -767,9 +767,9 @@@ void tst_qquickwindow::touchEvent_cance
  
      window->resize(250, 250);
      window->setPosition(100, 100);
+     window->setTitle(QTest::currentTestFunction());
      window->show();
 -    QVERIFY(QTest::qWaitForWindowExposed(window));
 +    QVERIFY(QTest::qWaitForWindowActive(window));
  
      TestTouchItem *item = new TestTouchItem(window->contentItem());
      item->setPosition(QPointF(50, 50));
@@@ -787,8 -801,9 +801,9 @@@ void tst_qquickwindow::touchEvent_reent
  
      window->resize(250, 250);
      window->setPosition(100, 100);
+     window->setTitle(QTest::currentTestFunction());
      window->show();
 -    QVERIFY(QTest::qWaitForWindowExposed(window));
 +    QVERIFY(QTest::qWaitForWindowActive(window));
  
      TestTouchItem *item = new TestTouchItem(window->contentItem());
  
@@@ -973,8 -991,9 +991,9 @@@ void tst_qquickwindow::mouseFiltering(
      QScopedPointer<QQuickWindow> cleanup(window);
      window->resize(250, 250);
      window->setPosition(100, 100);
+     window->setTitle(QTest::currentTestFunction());
      window->show();
 -    QVERIFY(QTest::qWaitForWindowExposed(window));
 +    QVERIFY(QTest::qWaitForWindowActive(window));
  
      TestTouchItem *bottomItem = new TestTouchItem(window->contentItem());
      bottomItem->setObjectName("Bottom Item");
@@@ -1771,10 -1809,11 +1809,11 @@@ void tst_qquickwindow::crashWhenHoverIt
      QQmlEngine engine;
      QQmlComponent component(&engine);
      component.loadUrl(testFileUrl("hoverCrash.qml"));
-     QQuickWindow *window = qobject_cast<QQuickWindow *>(component.create());
-     QVERIFY(window);
+     QScopedPointer<QQuickWindow> window(qobject_cast<QQuickWindow *>(component.create()));
+     QVERIFY(!window.isNull());
+     window->setTitle(QTest::currentTestFunction());
      window->show();
-     QTest::qWaitForWindowActive(window);
 -    QTest::qWaitForWindowExposed(window.data());
++    QTest::qWaitForWindowActive(window.data());
  
      // Simulate a move from the first rectangle to the second. Crash will happen in here
      // Moving instantaneously from (0, 99) to (0, 102) does not cause the crash
@@@ -1810,8 -1850,9 +1850,9 @@@ void tst_qquickwindow::qobjectEventFilt
  
      window.resize(250, 250);
      window.setPosition(100, 100);
+     window.setTitle(QTest::currentTestFunction());
      window.show();
 -    QVERIFY(QTest::qWaitForWindowExposed(&window));
 +    QVERIFY(QTest::qWaitForWindowActive(&window));
  
      TestTouchItem *item = new TestTouchItem(window.contentItem());
      item->setSize(QSizeF(150, 150));
@@@ -1863,8 -1905,10 +1905,9 @@@ void tst_qquickwindow::qobjectEventFilt
  
      window.resize(250, 250);
      window.setPosition(100, 100);
+     window.setTitle(QTest::currentTestFunction());
      window.show();
 -
 -    QVERIFY(QTest::qWaitForWindowExposed(&window));
 +    QVERIFY(QTest::qWaitForWindowActive(&window));
  
      TestTouchItem *item = new TestTouchItem(window.contentItem());
      item->setSize(QSizeF(150, 150));
@@@ -2041,64 -2070,20 +2088,65 @@@ void tst_qquickwindow::testRenderJob(
          QQuickWindow::AfterSynchronizingStage,
          QQuickWindow::BeforeRenderingStage,
          QQuickWindow::AfterRenderingStage,
 -        QQuickWindow::AfterSwapStage
 +        QQuickWindow::AfterSwapStage,
 +        QQuickWindow::NoStage
      };
 -    // Schedule the jobs
 -    for (int i=0; i<5; ++i)
 -        window.scheduleRenderJob(new RenderJob(stages[i], &completedJobs), stages[i]);
 -    window.show();
  
 -    QTRY_COMPARE(completedJobs.size(), 5);
 +    const int numJobs = 6;
  
 -    for (int i=0; i<5; ++i) {
 -        QCOMPARE(completedJobs.at(i), stages[i]);
 +    {
 +        QQuickWindow window;
++        window.setTitle(QTest::currentTestFunction());
 +        RenderJob::deleted = 0;
 +
 +        // Schedule the jobs
 +        for (int i = 0; i < numJobs; ++i)
 +            window.scheduleRenderJob(new RenderJob(stages[i], &completedJobs), stages[i]);
 +        window.show();
 +        QVERIFY(QTest::qWaitForWindowExposed(&window));
 +
 +        // All jobs should be deleted
 +        QTRY_COMPARE(RenderJob::deleted, numJobs);
 +
 +        // The NoStage job is not completed, if it is issued when there is no context,
 +        // but the rest will be queued and completed once relevant render stage is hit.
 +        QCOMPARE(completedJobs.size(), numJobs - 1);
 +
 +        // Verify jobs were completed in correct order
 +        for (int i = 0; i < numJobs - 1; ++i)
 +            QCOMPARE(completedJobs.at(i), stages[i]);
 +
 +
 +        // Check that NoStage job gets executed if it is scheduled when window is exposed
 +        completedJobs.clear();
 +        RenderJob::deleted = 0;
 +        window.scheduleRenderJob(new RenderJob(QQuickWindow::NoStage, &completedJobs),
 +                                 QQuickWindow::NoStage);
 +        QTRY_COMPARE(RenderJob::deleted, 1);
 +        QCOMPARE(completedJobs.size(), 1);
 +
 +        // Do a synchronized GL job.
 +        GLubyte readPixel[4] = {0, 0, 0, 0};
 +        GlRenderJob *glJob = new GlRenderJob(readPixel);
 +        if (window.openglContext()->thread() != QThread::currentThread()) {
 +            QMutex mutex;
 +            QWaitCondition condition;
 +            glJob->mutex = &mutex;
 +            glJob->condition = &condition;
 +            mutex.lock();
 +            window.scheduleRenderJob(glJob, QQuickWindow::NoStage);
 +            condition.wait(&mutex);
 +            mutex.unlock();
 +        } else {
 +            window.scheduleRenderJob(glJob, QQuickWindow::NoStage);
 +        }
 +        QCOMPARE(int(readPixel[0]), 255);
 +        QCOMPARE(int(readPixel[1]), 0);
 +        QCOMPARE(int(readPixel[2]), 0);
 +        QCOMPARE(int(readPixel[3]), 255);
      }
  
 -    // Verify that jobs are deleted when window has not been rendered at all...
 +    // Verify that jobs are deleted when window is not rendered at all
      completedJobs.clear();
      RenderJob::deleted = 0;
      {
@@@ -2165,8 -2150,9 +2213,9 @@@ void tst_qquickwindow::testHoverChildMo
  
      window.resize(250, 250);
      window.setPosition(100, 100);
+     window.setTitle(QTest::currentTestFunction());
      window.show();
 -    QVERIFY(QTest::qWaitForWindowExposed(&window));
 +    QVERIFY(QTest::qWaitForWindowActive(&window));
  
      EventCounter *bottomItem = new EventCounter(window.contentItem());
      bottomItem->setObjectName("Bottom Item");
Simple merge