Closed Bug 261064 Opened 20 years ago Closed 20 years ago

Clicking unnumbered list (ul) causes page to shift in some cases

Categories

(Core :: Layout: Block and Inline, defect)

x86
Windows 2000
defect
Not set
normal

Tracking

()

RESOLVED FIXED

People

(Reporter: avbohemen, Assigned: roc)

References

()

Details

(Keywords: testcase)

Attachments

(5 files, 3 obsolete files)

User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.0; @AB_CD@; rv:1.8a4) Gecko/20040922 Firefox/0.9.1+ (BlueFyre) Build Identifier: Mozilla/5.0 (Windows; U; Windows NT 5.0; @AB_CD@; rv:1.8a4) Gecko/20040922 Firefox/0.9.1+ (BlueFyre) Clicking a link in a list causes the page to shift, and not follow the link because the mouse cursor is not on it anymore. Clicking the link for the second time works. Not all ul's are effected though, part of this bug is already fixed. Reproducible: Always Steps to Reproduce: 1. Go to site mentioned above 2. Click one of the links in the right half of the page (under "XUL applications") 3. Actual Results: Page shifts up a little, missing the link you just tried to click. Expected Results: Do not shift and hit the link the first time. Follow-up to bug 257612 and bug 255584. This entire site shows the bug, not only this page, so feel free to click around.
Robert, you requested a minimal testcase. I'm sorry, my knowledge of html is too limited for that. If anyone can provide one, feel free to do so.
Can you jump on irc.mozilla.org #mozilla and find someone to help you?
Attached file Minimal testcase
Well, this is a minimal testcase derived from that site. In case you wonder, the empty css rule "body::first-line {}" is also somehow needed to trigger the bug.
Attached file another testcase
Thanks for that testcase again, Martjin! After some debugging I've localized the problem and I've produced this testcase, which is simpler because it doesn't involve ::first-line (which is really odd code).
Assignee: nobody → roc
Status: UNCONFIRMED → ASSIGNED
Attached patch partial fix (obsolete) — Splinter Review
This patch fixes the assertion that fires in the testcase. Basically when we're checking for empty frames before the absolute placeholder we need to scan the deep frame tree not just the direct line children, because the placeholder can be inside an inline (or in the earlier testcase, the first-line psuedo-inline). This patch helps a lot; deleting the text moves the absolute up to the top of its placeholder's block. But it's not totally fixed; margin collapsing should cause all the margins to collapse out and leave the absolute frame's top edge adjacent to the top of the content window. But we're not detecting the margin collapse until a reflow is forced again.
Blocks: 261196
The remaining problem is this: we get an incremental reflow targeted at the absolute frame and at the line containing its placeholder. In nsBlockFrame::Reflow we incrementally reflow the absolute frame. Then we reflow the line, moving the placeholder. Then we skip reflowing the incremental frames again, because we already reflowed them incrementally and the block's size didn't change. Clearly we need to reflow again any absolute frames whose placeholders moved and which have auto left or top. I wonder what the best way is to do this. One quite simple approach would be to modfiy nsAbsoluteContainingBlock::IncrementalReflow to detect if any absolute frames have auto left or top. Then we would reflow the absolute frames again at the end of nsBlockFrame::Reflow if any such were found during the incremental pass. I think this would perform quite well because I believe that auto left or top is fairly uncommon and not the interesting case for DHTML. One question is, why reflow the absolute frames twice, anyway? The only reason I can see is if an incremental reflow is targeted only at absolute frames, then we can skip all the work of line reflow (even if no lines are dirty, it's still a lot of work). So I think the *best* fix, if not the smallest, would be to change the call to nsAbsoluteContainingBlock::IncrementalReflow to first check whether "handled" will be true (all the incremental reflow is to absolute frames) without reflowing anything, which is fairly cheap (just inspecting the reflow path). If "handled" is not true then we don't do any incremental reflow of the absolute frames until after all the lines are reflowed, then we reflow all the absolute frames. How does that sound?
Attached patch complete fix (obsolete) — Splinter Review
This fixes the bug completely. I've tested this against a variety of absolute, fixed and relative positioning testcases and it seems to work OK. I don't know about performance but I don't think it will get worse.
Attachment #159825 - Attachment is obsolete: true
BTW we could add back the optimization which skips the reflow of absolute frames when the block was reflowed incrementally and its size didn't change; we'd just have to also scan the list of absolute frames and ensure that none of them have auto top or left. I haven't done that since I'm not sure it matters.
(In reply to comment #8) > BTW we could add back the optimization which skips the reflow of absolute frames > when the block was reflowed incrementally and its size didn't change; we'd just If I understand what you're saying, that's important. The containing block for most absolutely positioned elements is the root, and the root is involved in pretty much every incremental reflow.
Okay, this patch adds the size-change optimization. We do have to scan for frames whose position depends on the placeholder since placeholders might have moved. This would be much improved by folding the incremental reflow and the normal reflow together, but I'm not qutie sure how the reflows should combine.
Attachment #159934 - Attachment is obsolete: true
Attachment #160116 - Flags: superreview?(dbaron)
Attachment #160116 - Flags: review?(dbaron)
Blocks: 175364
Mozilla Windows Trunk Nightly Build Regression Window Pass: 2004071609 Fail: 2004071808
Keywords: testcase
Blocks: 242159
Comment on attachment 160116 [details] [diff] [review] fix including size-change optimization r+sr=dbaron, rubber-stamp. I didn't look at the absolute stuff -- I'm hoping to rewrite that when refactoring reflow. Please file a bug on making nsLineLayout::VerticalAlignFrames use IsFrameEmpty for its quirks mode stuff. I don't like the name IsFrameEmpty. IsSelfEmpty might be a little more consistent with one other thing in the tree (PaintSelf), but I don't much like that either.
Attachment #160116 - Flags: superreview?(dbaron)
Attachment #160116 - Flags: superreview+
Attachment #160116 - Flags: review?(dbaron)
Attachment #160116 - Flags: review+
But before landing please profile a DHTML testcase that has a lot of incremental reflows not in absolutely positioned content *and* has a lot of absolutely positioned elements (non-auto, but with the root (or is it ICB?) as a containing block) to make sure that this doesn't hurt the previously-known performance problem.
OK. I'll change it to IsSelfEmpty.
This is the testcase I will use to check incremental reflow performance.
times in milliseconds: normal run: 18347 18356 18381 patched: 24542 24570 24713 so I guess I'm going to have to work harder
Attached patch better fixSplinter Review
With this patch I got these times: 18879 18909 18943 Much better, just a 3% regression on this annoying testcase. The problem was that in the testcase I posted, we always reflowed the absolute frames because the block height was changing. There are two reasons why we don't need to do that: -- All the frames had fixed left, top, width and height, and thus couldn't be affected by changes in the size of the containing block -- The containing block height for the initial containing block is not the actual block height, but the viewport height, which isn't changing during incremental reflow. So this patch improves the previous patch by detecting both of those cases and optimizing for them. Checking to see whether the absolute frame's size or position depends on the containing block's size is unfortunately complex. But this logic could be reused to avoid reflowing absolute frames in a Resize reflow of their containing block. I'll post a followup patch for that once I've tested it. The existing code avoided reflowing the absolute frames only because it has a major bug. There's a check 'mRect != oldRect' that's supposed to detect a block size change. But it doesn't work because where mRect is tested, it hasn't yet been updated (the new size is only in aMetrics). I will post a testcase that demonstrates the bug. That bug is fixed by this patch. David, if you intend to carry over your rubber-stamp, just do it :-)
Attachment #160116 - Attachment is obsolete: true
Attached patch testcaseSplinter Review
This is the bug in the current code I was referring to. When you click the button, the bottom-positioned DIV should move down to keep a constant distance to the bottom of its containing block, but it doesn't move ... until you force a reflow e.g. by resizing, which pops it into the right place.
Checked in. Waiting to see Tp impact
No apparent Tp impact --- maybe a 1% loss on creature only, hard to tell with only one number. Seems to have cut Tdhtml on luna by about 1% :-)
Status: ASSIGNED → RESOLVED
Closed: 20 years ago
Resolution: --- → FIXED
Yeah, the creature number was just noise. There was no Tp impact at all.
Blocks: 269682
Depends on: 277760
This did cause some dhtml-type regressions -- see bug 277760.
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: