Canvas: don't crash when getContext("2d") is called on destruction.
authorMitch Curtis <mitch.curtis@theqtcompany.com>
Mon, 26 Jan 2015 14:53:15 +0000 (15:53 +0100)
committerMitch Curtis <mitch.curtis@digia.com>
Mon, 26 Jan 2015 16:28:37 +0000 (17:28 +0100)
We'd assume that a Window existed when that's not always the case.
For example:

import QtQuick 2.4
import QtQuick.Window 2.2
Window {
    Loader {
        sourceComponent: Canvas {
            Component.onDestruction: getContext("2d")
        }
        Component.onCompleted: active = false
    }
}

Change-Id: I5f30876e21ced5658adfa3bac494fd4196e0a7e3
Task-number: QTBUG-42222
Reviewed-by: Ulf Hermann <ulf.hermann@theqtcompany.com>
src/quick/items/context2d/qquickcanvasitem.cpp
tests/auto/quick/qquickcanvasitem/data/CanvasTestCase.qml
tests/auto/quick/qquickcanvasitem/data/tst_canvas.qml

index c31b772..4b28517 100644 (file)
@@ -1124,6 +1124,9 @@ bool QQuickCanvasItem::createContext(const QString &contextType)
 {
     Q_D(QQuickCanvasItem);
 
+    if (!window())
+        return false;
+
     if (contextType == QLatin1String("2d")) {
         if (d->contextType.compare(QLatin1String("2d"), Qt::CaseInsensitive) != 0)  {
             d->contextType = QLatin1String("2d");
index b0cae69..e49f0ac 100644 (file)
@@ -25,6 +25,11 @@ TestCase {
      return [];
   }
 
+  function renderStrategyToString(renderStrategy) {
+      return renderStrategy === Canvas.Immediate ? "Canvas.Immediate" :
+            (renderStrategy === Canvas.Threaded ? "Canvas.Threaded" : "Canvas.Cooperative");
+  }
+
   function createCanvasObject(data) {
     return component.createObject(testCase, data.properties);
   }
index 31413c2..79c89bb 100644 (file)
@@ -595,5 +595,51 @@ CanvasTestCase {
 
         canvas.destroy();
     }
+
+    function test_getContextOnDestruction_data() {
+        // We want to test all possible combinations deemed valid by the testcase,
+        // but we can't test FramebufferObject due to difficulties ignoring the "available" warning.
+        var allData = testData("2d");
+        var ourData = [];
+
+        for (var i = 0; i < allData.length; ++i) {
+            if (allData[i].properties.renderTarget !== Canvas.FramebufferObject) {
+                var row = allData[i].properties;
+                row.tag = allData[i].tag;
+                ourData.push(row);
+            }
+        }
+
+        return ourData;
+    }
+
+    function test_getContextOnDestruction(data) {
+        try {
+            var canvasWindow = Qt.createQmlObject("
+                import QtQuick 2.4\n
+                import QtQuick.Window 2.2\n
+                Window {\n
+                    function test() {\n
+                        loader.active = true\n
+                        loader.active = false\n
+                    }\n
+                    Loader {\n
+                        id: loader\n
+                        active: false\n
+                        sourceComponent: Canvas {\n
+                            renderStrategy: " + renderStrategyToString(data.renderStrategy) + "\n
+                            Component.onDestruction: getContext(\"2d\")
+                        }\n
+                    }\n
+                }\n",
+                testCase);
+            verify(canvasWindow);
+            canvasWindow.test();
+            // Shouldn't crash when destruction is done.
+            wait(0);
+        } catch (exception) {
+            fail(exception.message);
+        }
+    }
 }