fast/repaint/float-in-new-block-with-layout-delta.html is overpainting Looking at the expected image: http://trac.webkit.org/browser/trunk/LayoutTests/platform/mac/fast/repaint/float-in-new-block-with-layout-delta-expected.png Notice how we repaint 100x200 instead of 100x100 (which is actually all we need). The "overpaint" is caused by: RenderBlock::repaintDirtyFloats which is called at the last line of: RenderBlock::layoutRunsAndFloats and repaints the float inside the div which is of course still at 0,0. The problem appears to be the layoutDelta in: LayoutRect RenderBox::clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer) const { if (style()->visibility() != VISIBLE && !enclosingLayer()->hasVisibleContent()) return LayoutRect(); LayoutRect r = visualOverflowRect(); RenderView* v = view(); if (v) { // FIXME: layoutDelta needs to be applied in parts before/after transforms and // repaint containers. https://bugs.webkit.org/show_bug.cgi?id=23308 r.move(v->layoutDelta()); } Which at time of repaint is 0, -118, which adjusts the rect from the repaint() call back to 0. It seems that the repaintDirtyFloats call is attempting to repaint the *new* location of the float, not the *old* location, but maybe I"m misunderstanding. I'll have to look again to understand why we're actually invalidating the new location, although initial testing of my patch on bug 92800, may suggest that our invalidation of the new location is wrong, as bug 92800 disables it (possibly incorrectly). The first issue is for me to understand what the purpose of RenderBlock::repaintDirtyFloats at the end of RenderBlock::layoutRunsAndFloats is.
It's also unclear to me what the purpose of layoutDelta() is. Since it makes it awkward to call clippedOverflowRectForRepaint() as you'll never know whether you're getting the "new" or "old" repaint rect for an object, as layoutDelta will make that function return the "old" bounds when it's in effect.
Yup, re-confirmed. repaintDirtyFloats() causes this new float to repaint it's old (invalid) bounds of 8,8; 100,100 This code in layoutBlockChild(): if (!childHadLayout && child->checkForRepaintDuringLayout()) { child->repaint(); child->repaintOverhangingFloats(true); } is causing the new bounds to repaint. Which is correct. Except checkForRepaintDuringLayout() may be wrong there. This is an example of the current contract whereby your parent will force you to repaint when you're painting for the first time. In bug 92800, I'm exploring making checkForRepaintDuringLayout return true only if the object has ever painted before. Obviously that would be incompatible with this usage here. From this analysis it looks like repaintDirtyFloats() is intentionally repainting the old bounds. Which is just wrong in the first-layout case.
I've sorted through my confusion enough to fix this as part of bug 92800. *** This bug has been marked as a duplicate of bug 92800 ***