Ensure that Canvas has the correct size with complex bindings.

When a Canvas is a child of an item with certain width and height
values (as described in the bug report), it won't paint correctly.

For example, the order of events might occur like so:

1. Canvas width set to 1
2. Canvas height set to 1
3. Canvas width set to 32, which causes the height to also be set to 32

Every size change causes QQuickCanvasItem::geometryChanged() to be
called, but the third event above causes it to be called recursively,
such that the most nested call results in the size being 32x32, but
then the execution returns to the first call and 32x1 is used instead,
overwriting the correct size.

We fix this by setting the new canvas size to width() and height(),
ignoring the recursion and instead using the latest size of the item.

Change-Id: Iebbcbfaa3217319b32b97f6b68f7a8af197a0e89
Task-number: QTBUG-42878
Reviewed-by: Gunnar Sletta <gunnar@sletta.org>
This commit is contained in:
Mitch Curtis 2015-01-27 18:09:56 +01:00 committed by Mitch Curtis
parent dd017ee946
commit fea8c9026d
2 changed files with 40 additions and 2 deletions

View File

@ -592,7 +592,9 @@ void QQuickCanvasItem::geometryChanged(const QRectF &newGeometry, const QRectF &
QQuickItem::geometryChanged(newGeometry, oldGeometry);
QSizeF newSize = newGeometry.size();
// Due to indirect recursion, newGeometry may be outdated
// after this call, so we use width and height instead.
QSizeF newSize = QSizeF(width(), height());
if (!d->hasCanvasSize && d->canvasSize != newSize) {
d->canvasSize = newSize;
emit canvasSizeChanged();

View File

@ -1,5 +1,10 @@
import QtQuick 2.0
Item {
id: container
width: 200
height: 200
CanvasTestCase {
id:testCase
name: "canvas"
@ -641,5 +646,36 @@ CanvasTestCase {
fail(exception.message);
}
}
}
property Component implicitlySizedComponent: Item {
implicitWidth: 32
implicitHeight: implicitWidth
anchors.centerIn: parent
property alias canvas: canvas
Canvas {
id: canvas
width: Math.max(1, Math.min(parent.width, parent.height))
height: width
onPaint: {
var ctx = getContext("2d");
ctx.reset();
ctx.beginPath();
ctx.fillRect(0, 0, width, height);
}
}
}
function test_implicitlySizedParent() {
var implicitlySizedItem = implicitlySizedComponent.createObject(container);
verify(implicitlySizedItem);
var xCenter = implicitlySizedItem.width / 2;
var yCenter = implicitlySizedItem.height / 2;
waitForRendering(implicitlySizedItem);
comparePixel(implicitlySizedItem.canvas.context, xCenter, yCenter, 0, 0, 0, 255);
}
}
}