From 93affd9ff660456bde2d380788ea8ebfabb0f1c3 Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Mon, 26 Jan 2015 15:53:15 +0100 Subject: [PATCH] Canvas: don't crash when getContext("2d") is called on destruction. 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 --- src/quick/items/context2d/qquickcanvasitem.cpp | 3 ++ .../quick/qquickcanvasitem/data/CanvasTestCase.qml | 5 +++ .../quick/qquickcanvasitem/data/tst_canvas.qml | 46 ++++++++++++++++++++++ 3 files changed, 54 insertions(+) diff --git a/src/quick/items/context2d/qquickcanvasitem.cpp b/src/quick/items/context2d/qquickcanvasitem.cpp index c31b772..4b28517 100644 --- a/src/quick/items/context2d/qquickcanvasitem.cpp +++ b/src/quick/items/context2d/qquickcanvasitem.cpp @@ -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"); diff --git a/tests/auto/quick/qquickcanvasitem/data/CanvasTestCase.qml b/tests/auto/quick/qquickcanvasitem/data/CanvasTestCase.qml index b0cae69..e49f0ac 100644 --- a/tests/auto/quick/qquickcanvasitem/data/CanvasTestCase.qml +++ b/tests/auto/quick/qquickcanvasitem/data/CanvasTestCase.qml @@ -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); } diff --git a/tests/auto/quick/qquickcanvasitem/data/tst_canvas.qml b/tests/auto/quick/qquickcanvasitem/data/tst_canvas.qml index 31413c2..79c89bb 100644 --- a/tests/auto/quick/qquickcanvasitem/data/tst_canvas.qml +++ b/tests/auto/quick/qquickcanvasitem/data/tst_canvas.qml @@ -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); + } + } } -- 2.7.4