This bug is reproducible in Safari and Chrome with GPU-accelerated canvas rendering. Load attached "grid bug.html" file in the browser, and zoom the page in or out. Result -> White grid lines appear and most zoom factors Seems to be a problem with the compositor's layout algorithm. The rounding of canvas layers' zoomed size is probably to blame.
Created attachment 151758 [details] Test case
@leviw: any idea what may have caused this? It appears to be a recent regression.
I found that the problem has to do with the rounding of the zomed canvas size in WebCore::RenderHTMLCanvas::canvasSizeChanges. It disagrees with the coordinate snapping. The following way of computing intrinsic size seems to fix the bug on windows, but not quite on linux, so I think there is more to it that what I understand so far: void RenderHTMLCanvas::canvasSizeChanged() { IntSize canvasSize = static_cast<HTMLCanvasElement*>(node())->size(); IntSize zoomedSize; RenderStyle* styleToUse = style(); float effectiveZoom = styleToUse->effectiveZoom(); if (styleToUse->isOutOfFlowPositioned()) { // When positioning is out of flow, the zoomed size must be computed from the zoomed bounds, // otherwise there is a risk of creating gaps between adjacent canvases due to integer coordinate // snapping float left = styleToUse->logicalLeft().getFloatValue(); float right = left + canvasSize.width() * effectiveZoom; zoomedSize.setWidth(roundToInt(right) - roundToInt(left)); float top = styleToUse->top().getFloatValue(); float bottom = top + canvasSize.height() * effectiveZoom; zoomedSize.setHeight(roundToInt(bottom) - roundToInt(top)); } else { zoomedSize.setWidth(roundToInt(canvasSize.width() * effectiveZoom)); zoomedSize.setHeight(roundToInt(canvasSize.height() * effectiveZoom)); } if (zoomedSize == intrinsicSize()) return; (...) (In reply to comment #2) > @leviw: any idea what may have caused this? It appears to be a recent regression.
(In reply to comment #3) > I found that the problem has to do with the rounding of the zomed canvas size in WebCore::RenderHTMLCanvas::canvasSizeChanges. It disagrees with the coordinate snapping. > > The following way of computing intrinsic size seems to fix the bug on windows, but not quite on linux, so I think there is more to it that what I understand so far: > > void RenderHTMLCanvas::canvasSizeChanged() > { > IntSize canvasSize = static_cast<HTMLCanvasElement*>(node())->size(); > IntSize zoomedSize; > > RenderStyle* styleToUse = style(); > float effectiveZoom = styleToUse->effectiveZoom(); > > if (styleToUse->isOutOfFlowPositioned()) { > // When positioning is out of flow, the zoomed size must be computed from the zoomed bounds, > // otherwise there is a risk of creating gaps between adjacent canvases due to integer coordinate > // snapping > float left = styleToUse->logicalLeft().getFloatValue(); > float right = left + canvasSize.width() * effectiveZoom; > zoomedSize.setWidth(roundToInt(right) - roundToInt(left)); > float top = styleToUse->top().getFloatValue(); > float bottom = top + canvasSize.height() * effectiveZoom; > zoomedSize.setHeight(roundToInt(bottom) - roundToInt(top)); > } else { > zoomedSize.setWidth(roundToInt(canvasSize.width() * effectiveZoom)); > zoomedSize.setHeight(roundToInt(canvasSize.height() * effectiveZoom)); > } > > if (zoomedSize == intrinsicSize()) > return; > (...) > > (In reply to comment #2) > > @leviw: any idea what may have caused this? It appears to be a recent regression. Interesting! I'm not surprised this doesn't solve the problem in all cases since we use different snapping logic than what you implemented here. I've got another Layout issue in front of this, but it's on my list. Thanks for taking a preliminary look!
This seems quite similar to bug 98205, will try the same approach for canvas.
Bug 99104 tracks another approach for fixing this.
*** This bug has been marked as a duplicate of bug 99104 ***