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: