Closed
Bug 191448
Opened 22 years ago
Closed 16 years ago
space manager too limited for handling floats
Categories
(Core :: Layout: Floats, defect)
Core
Layout: Floats
Tracking
()
VERIFIED
FIXED
mozilla1.9.1b3
People
(Reporter: dbaron, Assigned: dbaron)
References
(Blocks 1 open bug)
Details
(Keywords: meta, verified1.9.1)
Attachments
(9 files, 4 obsolete files)
12.37 KB,
patch
|
roc
:
review+
roc
:
superreview+
|
Details | Diff | Splinter Review |
29.89 KB,
patch
|
roc
:
review+
roc
:
superreview+
|
Details | Diff | Splinter Review |
109.68 KB,
patch
|
roc
:
review+
roc
:
superreview+
|
Details | Diff | Splinter Review |
107.42 KB,
patch
|
roc
:
review+
roc
:
superreview+
|
Details | Diff | Splinter Review |
8.52 KB,
text/plain; charset=us-ascii
|
Details | |
13.51 KB,
text/plain; charset=us-ascii
|
Details | |
3.32 KB,
patch
|
benjamin
:
review+
|
Details | Diff | Splinter Review |
25.35 KB,
application/octet-stream
|
Details | |
274.87 KB,
patch
|
Details | Diff | Splinter Review |
I'm filing this as a meta-bug for problems with the space manager (which is just
one part of the way we handle floats). In particular, treating floats as just a
bunch of rectangles taking up space (which is an oversimplification of what the
space manager does, but it probably tends too much in that direction) doesn't
seem sufficient for some purposes. I admit I haven't looked at the code closely
enough to know how deep the design problems are, but when I do get a chance to
look at it I want a list of all the relevant issues that I've noticed.
Assignee | ||
Comment 1•18 years ago
|
||
...and it's also much more general than it needs to be, in many ways.
I think we should probably just toss it out and write an nsFloatManager designed to manage floats. (Thinking about fixing things like bug 25888 is quite hard right now.)
Blocks: 25888
![]() |
||
Comment 2•18 years ago
|
||
I swear I thought roc made that comment until I loaded the bug. ;) See bug 270392 comment 15 and bug 270392 comment 16.
Comment 3•18 years ago
|
||
My thoughts (I thought it would be an interesting exercise to figure out how to put this together, so here it is. I haven't done any coding on this, and I don't know if I will.):
The simplest implementation would be something like bug 270392 comment 16: two linked lists detailing the boundaries of the left and right floats, i.e. the left float edge is -Infinity until 100 pixels, then 150px until 200 pixels, etc., plus a similar list for right floats. I believe this is sufficient to completely represent all the state we need to keep about floats.
Normal cost to generate is about O(N) in the number of floats. I think if we cache the topmost region appended floats can be inserted into (which is just the top of the last float inserted), it ends up being O(N) in general for float appends even in extreme cases like bug 371885 because of the CSS rule that a later float can't begin above an earlier float. The structure would probably be thrown out and regenerated for operations other than appends because the state needed would be complicated to keep around otherwise. Memory cost per float is at most 24 bytes, but probably more like 12 bytes or less per float in most float-intense cases (approaching 0 bytes per float in extreme cases). An nsFloatManager would probably be 24 bytes: for each of left and right, a pointer to the float insertion point, a pointer to the beginning of the list, and the y-coordinate of the bottom of the last region (we could pull some circular linked list trickery, but it's probably not worth bothering).
Overall, it's cheap enough that it wouldn't be an issue to keep around, and it would be a significant performance win for incremental document construction if we kept it around because it would eliminate the need to call RecoverFloats in the append case. Also, since we're going to throw out the float manager for operations other than appends, we can throw out the state for floats above the last line reflowed, leading to a small memory footprint in most cases.
Another advantage of this approach is that it would be basically a drop-in replacement for the current space manager, with very few changes to other code needed.
We could possibly do something more complicated, but I can't think of any real-world cases where it would be a benefit, and it would be difficult to make O(N) in general.
It'll be a pain to implement Push/PopState efficiently, though... probably the best way would be through some sort of delegation scheme, where regions can refer to regions in the parent instead of storing their own data, plus a merge function. I think that'll end up leading to some ugly code involving a union and storing a flag in a pointer so as not the bloat the list elements; however, it is cheap and algorithmically simple.
Assignee | ||
Updated•16 years ago
|
Status: NEW → ASSIGNED
Assignee | ||
Comment 4•16 years ago
|
||
So I have some work in progress in my patch queue (written today) that drastically simplifies the space manager (and renames it to float manager). It doesn't attempt to add any functionality (e.g., ability to keep around); the idea is to start by removing all the stuff we don't need so we have something easier to work with. (I'd also like to use the new foundation to fix bug 25888.)
http://hg.mozilla.org/users/dbaron_mozilla.com/patches/
The data structures I picked are a bit different from what Eli suggested in comment3; I'm also not all that happy about them, but it seemed like the quickest way to get something somewhat efficient working. I suspect there are some clever ways to improve things.
I'm currently trying to get reftests passing again; I fixed a whole bunch, but now I'm failing layout/reftests/bugs/387201-1.html (although I think the new behavior may actually be correct per spec; I'm still not sure why it changed, though; perhaps there was code deep in the space manager to ignore 0-width rects), and then crashing on layout/reftests/bugs/421710-1.html.
Assignee | ||
Comment 5•16 years ago
|
||
For what it's worth, I got reftests passing again last night. I'm still not all that confident about my PopState and RemoveTrailingRegions implementations, although I did have to rewrite the latter to fix the crash in layout/reftests/bugs/421710-1.html.
Assignee | ||
Comment 6•16 years ago
|
||
I just removed this, since I didn't see the need to reimplement this because:
(1) I don't see the need to compare float manager state rather than just the resulting frame positions
(2) I don't know of anybody using VerifyReflow in the past 8 years
Attachment #354838 -
Flags: superreview?(roc)
Attachment #354838 -
Flags: review?(roc)
Assignee | ||
Comment 7•16 years ago
|
||
It hasn't been part of the build for ages anyway.
Assignee | ||
Updated•16 years ago
|
Attachment #354839 -
Flags: superreview?(roc)
Attachment #354839 -
Flags: review?(roc)
Assignee | ||
Comment 8•16 years ago
|
||
I tried to separate out most of the really boring part into its own patch. Substantial parts of this patch were written with sed. (I don't think I have any nsNameFloatManagers in it, though :-).)
The file renames are *not* in this patch; they're in the main patch.
Attachment #354840 -
Flags: superreview?(roc)
Attachment #354840 -
Flags: review?(roc)
Assignee | ||
Comment 9•16 years ago
|
||
Here's the main patch; holding off for now on requesting review on this one.
Assignee | ||
Comment 10•16 years ago
|
||
I think I'm going to simplify patch 4 a good bit: as roc suggested yesterday, there's no need to have the band data structures at all. GetBandInfo shouldn't be any more complicated without it. (I'm not sure why I didn't see that when he said so.) That will make PopState much simpler, since most of the complexity there is updating the bands.
Assignee | ||
Comment 11•16 years ago
|
||
Here's the simpler version. GetBandInfo is a little more complicated now, but it's still just walking backwards through a list, and the rest is a lot simpler.
I'll attach nsFloatManager.h and .cpp separately as well, since they're pretty unreadable in diff form.
Attachment #354841 -
Attachment is obsolete: true
Attachment #354858 -
Flags: superreview?(roc)
Attachment #354858 -
Flags: review?(roc)
Assignee | ||
Comment 12•16 years ago
|
||
Assignee | ||
Comment 13•16 years ago
|
||
Attachment #354838 -
Flags: superreview?(roc)
Attachment #354838 -
Flags: superreview+
Attachment #354838 -
Flags: review?(roc)
Attachment #354838 -
Flags: review+
Comment on attachment 354839 [details] [diff] [review]
patch 2: remove TestSpaceManager
This is why I'm not a big fan of unit tests...
Attachment #354839 -
Flags: superreview?(roc)
Attachment #354839 -
Flags: superreview+
Attachment #354839 -
Flags: review?(roc)
Attachment #354839 -
Flags: review+
Attachment #354840 -
Flags: superreview?(roc)
Attachment #354840 -
Flags: superreview+
Attachment #354840 -
Flags: review?(roc)
Attachment #354840 -
Flags: review+
Only one substantive comment on the main patch: instead of a linked list of FloatInfos, why not just use an nsTArray<FloatInfo>? I think everything gets simpler and we'd do fewer heap allocations. SavedState would contain an array index instead of a FloatInfo*.
+ // The number of floats on the sides of mAvailSpaceRect, including
+ // floats that do not reduce mAvailSpaceRect because they are in the
+ // margins.
+ PRBool mBandHasFloats;
PRPackedBool, and move it next to something narrow if you can.
+ void GetBandInfo(nscoord aY, nscoord aMaxHeight, nscoord aContentAreaWidth,
+ nsRect& aAvailSpace, PRBool* aHasFloats) const;
Wouldn't it be better to just call this GetBand and return aAvailSpace as a direct result?
+ * aMarginRect is relative to the current translation. The caller
+ * must ensure aMarginRect.height >= 0.
Is aMarginRect.width < 0 allowed here? I think not. I would have assumed negative widths/heights are generally invalid without having to mention it explicitly, so mentioning the height requirement makes it sound like negative widths would be allowed...
+ struct SavedState;
+ friend struct SavedState;
struct SavedState {
Can't you just move the friend declaration down below the definition of the struct?
+void
+nsFloatManager::GetBandInfo(nscoord aYOffset,
+ nscoord aMaxHeight,
+ nscoord aContentAreaWidth,
+ nsRect& aAvailSpace,
+ PRBool* aHasFloats) const
Overindented parameter names
+ if (floatTop < bottom)
+ bottom = floatTop;
Aren't we supposed to put these statements in {}? Alternatively, I like
bottom = PR_MIN(bottom, floatTop);
+ // This could be a good bit simpler if we could guarantee that the
+ // floats given were at the end of our list. (But we can't;
+ // layout/reftests/bugs/421710-1.html crashes.)
I'm not sure what this comment means exactly, since your code (like the old code) does require that
the floats be the last floats on the list (since we stop as soon as our backward traversal finds
a float that's not in the list). I think it would be a bit clear if you wrote
+ // This could be a good bit simpler if we could guarantee that all the
+ // floats given were in our list. (But we can't;
+ // layout/reftests/bugs/421710-1.html crashes.)
Assignee | ||
Comment 16•16 years ago
|
||
(In reply to comment #15)
> I'm not sure what this comment means exactly, since your code (like the old
> code) does require that
> the floats be the last floats on the list (since we stop as soon as our
> backward traversal finds
> a float that's not in the list). I think it would be a bit clear if you wrote
My initial implementation got rid of the hash set and just walked backwards through the FloatInfo until it found one corresponding to the frame it was given as an argument (ignoring all the next siblings), on the assumption that all of the floats in that list would have FloatInfo. That crashed, so I put back all the nsVoidHashSet code.
Assignee | ||
Comment 17•16 years ago
|
||
(In reply to comment #15)
> + struct SavedState;
> + friend struct SavedState;
> struct SavedState {
>
> Can't you just move the friend declaration down below the definition of the
> struct?
That pattern because it provides uniformity between compilers that follow C++ 1998 strictly and those that follow the errata. (C++ 1998 said that subclasses don't have any special access to their parent classes; this was incompatible with earlier implementations and changed in errata, but some compilers do it.)
Otherwise there's no reason for the pattern at all, but I think we may still support some compilers that follow C++ 1998 strictly.
Assignee | ||
Comment 18•16 years ago
|
||
I think this should address roc's comments; it also tweaks the bounds checking for bottom in nsFloatManager::GetBand.
Attachment #354858 -
Attachment is obsolete: true
Attachment #355237 -
Flags: superreview?(roc)
Attachment #355237 -
Flags: review?(roc)
Attachment #354858 -
Flags: superreview?(roc)
Attachment #354858 -
Flags: review?(roc)
Assignee | ||
Comment 19•16 years ago
|
||
Attachment #354859 -
Attachment is obsolete: true
Assignee | ||
Comment 20•16 years ago
|
||
Attachment #354861 -
Attachment is obsolete: true
Assignee | ||
Updated•16 years ago
|
Attachment #355238 -
Attachment is patch: false
Attachment #355238 -
Attachment mime type: text/plain → text/plain; charset=us-ascii
Assignee | ||
Comment 21•16 years ago
|
||
I landed patches 1 and 2:
http://hg.mozilla.org/mozilla-central/rev/4a30801c7e45
http://hg.mozilla.org/mozilla-central/rev/454a4f1c98a5
Comment on attachment 355237 [details] [diff] [review]
patch 4: replace nsSpaceManager and nsBlockBandData with nsFloatManager
+ mFloats.RemoveElementsAt(newLength, mFloats.Length() - newLength);
mFloats.SetLength(newLength);
+ mFloats.RemoveElementsAt(aState->mFloatInfoCount,
+ mFloats.Length() - aState->mFloatInfoCount);
mFloats.SetLength(aState->mFloatInfoCount);
My question about "friend" was not objecting to the use of "friend", I was just observing that
struct A;
friend struct A;
struct A { ... };
is, AFAIK, equivalent to
struct A { ... };
friend struct A;
Attachment #355237 -
Flags: superreview?(roc)
Attachment #355237 -
Flags: superreview+
Attachment #355237 -
Flags: review?(roc)
Attachment #355237 -
Flags: review+
Assignee | ||
Comment 23•16 years ago
|
||
(In reply to comment #22)
> (From update of attachment 355237 [details] [diff] [review])
> + mFloats.RemoveElementsAt(newLength, mFloats.Length() - newLength);
>
> mFloats.SetLength(newLength);
>
> + mFloats.RemoveElementsAt(aState->mFloatInfoCount,
> + mFloats.Length() - aState->mFloatInfoCount);
>
> mFloats.SetLength(aState->mFloatInfoCount);
I tried that first, but that requires that FloatInfo have a default constructor, since SetLength can make things longer or shorter. If nsTArray had a variant of SetLength that only went shorter, I could use it.
> My question about "friend" was not objecting to the use of "friend", I was just
> observing that
> struct A;
> friend struct A;
> struct A { ... };
> is, AFAIK, equivalent to
> struct A { ... };
> friend struct A;
Not for things inside the braces, which are a major part of what it matters for.
Assignee | ||
Comment 24•16 years ago
|
||
landed patches 3 and 4:
http://hg.mozilla.org/mozilla-central/rev/b19f0a7a3c4c
http://hg.mozilla.org/mozilla-central/rev/496e0cb5c943
(I also merged one spelling fix in nsBlockFrame.cpp that I had underneath into patch 3.)
Status: ASSIGNED → RESOLVED
Closed: 16 years ago
Resolution: --- → FIXED
Target Milestone: --- → mozilla1.9.2a1
Assignee | ||
Comment 25•16 years ago
|
||
Also landed:
http://hg.mozilla.org/mozilla-central/rev/aa32889429db
to avoid confusing refcount logging.
Assignee | ||
Comment 26•16 years ago
|
||
This adds a new method to nsTArray to provide a cleaner API for solving the problem in comment 23.
Benjamin, what do you think of this?
Attachment #355344 -
Flags: review?
Assignee | ||
Updated•16 years ago
|
Attachment #355344 -
Flags: review? → review?(benjamin)
Updated•16 years ago
|
Attachment #355344 -
Flags: review?(benjamin) → review+
Comment 27•16 years ago
|
||
Comment on attachment 355344 [details] [diff] [review]
patch 6: add nsTArray<E>::TruncateLength
>+ void TruncateLength(size_type newLen) {
>+ size_type oldLen = Length();
>+ NS_ASSERTION(newLen <= oldLen, "caller should use SetLength instead");
Use NS_ABORT_IF_FALSE here...
Assignee | ||
Comment 28•16 years ago
|
||
Also, for what it's worth, if we decide we want to keep the space manager around between reflows (rather than recover state into it every time), we might want to convert back to a linked list (for cheaper insertion/removal in the middle). (I suppose I should have remembered that when you suggested switching to an array...) (If we kept it around, it would have a cursor into the list, and the things that currently work with the end of the list would instead work from the cursor.)
Assignee | ||
Comment 29•16 years ago
|
||
(In reply to comment #24)
> landed patches 3 and 4:
> http://hg.mozilla.org/mozilla-central/rev/b19f0a7a3c4c
> http://hg.mozilla.org/mozilla-central/rev/496e0cb5c943
For what it's worth, this led to:
Linux Firefox: Zdiff:-5504 (+2924/-8428)
Mac Firefox: Zdiff:-8208 (+4116/-12324) (had some other changes in it too)
(In reply to comment #28)
> Also, for what it's worth, if we decide we want to keep the space manager
> around between reflows (rather than recover state into it every time), we might
> want to convert back to a linked list (for cheaper insertion/removal in the
> middle).
Yeah, although it would be a doubly-linked list.
Assignee | ||
Comment 31•16 years ago
|
||
Landed TruncateLength:
http://hg.mozilla.org/mozilla-central/rev/63fc1585fe00
Updated•16 years ago
|
QA Contact: ian → layout.floats
Assignee | ||
Comment 32•16 years ago
|
||
Fixed on 1.9.1 in order to fix some of the other bugs this happens to fix (esp. bug 467493, which is blocking):
http://hg.mozilla.org/releases/mozilla-1.9.1/rev/31cbae892de7
http://hg.mozilla.org/releases/mozilla-1.9.1/rev/4bb8dbbc3832
http://hg.mozilla.org/releases/mozilla-1.9.1/rev/217208c67bd5
http://hg.mozilla.org/releases/mozilla-1.9.1/rev/33091764b7ba
http://hg.mozilla.org/releases/mozilla-1.9.1/rev/f75293f0c230
http://hg.mozilla.org/releases/mozilla-1.9.1/rev/fde2979a4912
Keywords: fixed1.9.1
Target Milestone: mozilla1.9.2a1 → mozilla1.9.1b3
Assignee | ||
Comment 33•16 years ago
|
||
Note that in order to land it I also landed:
http://hg.mozilla.org/releases/mozilla-1.9.1/rev/808c7fd368a9
before the patches above and:
http://hg.mozilla.org/releases/mozilla-1.9.1/rev/796feafea6b8
http://hg.mozilla.org/releases/mozilla-1.9.1/rev/3d50c726626b
http://hg.mozilla.org/releases/mozilla-1.9.1/rev/110384dabb87
after them.
Comment 34•16 years ago
|
||
David, a couple of reftests have been checked in. Do you plan more tests or are those tests enough and we can set in-testsuite+?
Flags: in-testsuite?
Assignee | ||
Comment 35•16 years ago
|
||
Reftests for what? This patch wasn't intended to change behavior; I think the tests that are checked in are tests for things that I noticed or broke along the way. We have a bunch of existing tests to test the behavior that this code was changing, and I'm sure we could use more, though, but I don't think there's anything in particular associated with this bug that ought to be in a test suite.
Flags: in-testsuite? → in-testsuite-
Comment 36•16 years ago
|
||
Based on comment 35 and that all reftests don't show any problems we could mark this bug as verified.
Status: RESOLVED → VERIFIED
Keywords: fixed1.9.1 → verified1.9.1
Updated•16 years ago
|
Flags: wanted1.9.0.x+
Flags: blocking1.9.0.12+
Comment 37•16 years ago
|
||
Here's a mercurial patch-bundle backporting this bug's patches to the 1.9.0.x branch. I've listed all the included patches below, with their changeset IDs from the 1.9.1 branch.
The first three patches I applied were pre-requisites for later patches to apply. (They're pretty straightforward, I think -- two of them just remove dead code, and the other replaces explicit QI's with a utility method to do the same.)
> dd28fa11cb15 Bug 432891: Remove unneeded border-box and padding-box values of -moz-float-edge.
> 140ebc8ba146 Bug 409331: Instead of QIing to nsBlockFrame in various places, call an nsLayoutUtils method to do it.
> 3a4f96251014 Bug 458969: dead stuff in nsSpaceManager.
Then, I applied these changesets listed in comment 32 and comment 33:
> 808c7fd368a9 Add some reftests for float behavior.
> 31cbae892de7 Bug 191448: Remove the VerifyReflow code that checked the space manager state.
> 4bb8dbbc3832 Bug 191448: Remove TestSpaceManager.
> 217208c67bd5 Bug 191448: Rename flags and methods from space manager to float manager.
> 33091764b7ba Bug 191448: Replace space manager with a more limited float manager.
> f75293f0c230 Bug 191448: Give nsFloatManager::FloatInfo a copy constructor to avoid confusing refcount logging.
> fde2979a4912 Bug 191448: Add nsTArray<E>::TruncateLength, which is like SetLength, except only allows shortening of the array.
> 796feafea6b8 Bug 472252: Fix tests to match what they should have been testing, and fix nsFloatManager behavior [...]
> 3d50c726626b Bug 472218: Change code for handling out-of-nscoord-range values from NS_NOTREACHED to NS_WARNING.
> 110384dabb87 Bug 476372: Keep width of avail space rect at least 0.
(Note that the final 3 changesets mentioned above are the fixes for the three regressions from this bug -- bug 472252, Bug 472218, Bug 476372)
I had to fix some bitrot to backport some of those changesets, but it was all minor stuff in contextual code (rather than in the patched lines).
Comment 38•16 years ago
|
||
For convenience, here's a combined patch for the 1.9.0.x branch, taken from the above patch-bundle. (If we end up landing this on the 1.9.0.x branch, though, we should still land the patches from the patch-bundle as separate patches.)
This is a non-git-style diff, because the 'patch' tool doesn't understand these git-style patch commands (which would be included in the git-style version of this patch):
rename from layout/generic/nsSpaceManager.cpp
rename to layout/generic/nsFloatManager.cpp
rename from layout/generic/nsSpaceManager.h
rename to layout/generic/nsFloatManager.h
Assignee | ||
Comment 39•16 years ago
|
||
So backporting this seems a little scary to me given the amount of Web page testing we get for branch releases. (I'm also not sure we should be removing support for values of -moz-float-edge on a stable branch.)
I'm not sure I'd have time to write other fixes for whichever bugs led this to be blocking+ for this security release in the next week, though. (Which bugs are those, exactly? I remember a conversation about backporting this bug in a bug that I couldn't find in this bug's dependency list.) Why did this bug end up as a blocker for this particular security release rather than, say, the previous one or the next one?
I'm not comfortable with backporting this just to fix a random security bug that, as far as we know, no-one else knows about. (In general I think we should fix fewer of those bugs in stable branches.)
Updated•16 years ago
|
Flags: blocking1.9.0.12+
Assignee | ||
Comment 43•15 years ago
|
||
Even with the followups, this did change behavior by fixing bug 75286 (though it wasn't intended to).
Assignee | ||
Comment 44•15 years ago
|
||
...also bug 81710.
Assignee | ||
Comment 45•15 years ago
|
||
Er, in the previous comment I meant bug 219385, not bug 81710.
You need to log in
before you can comment on or make changes to this bug.
Description
•