Closed
Bug 526178
Opened 15 years ago
Closed 15 years ago
binding loading order changed in 3.6b1 compared to previous version of firefox
Categories
(Core :: XBL, defect, P2)
Tracking
()
RESOLVED
FIXED
mozilla1.9.2
Tracking | Status | |
---|---|---|
status1.9.2 | --- | beta2-fixed |
People
(Reporter: fstauffer, Assigned: bzbarsky)
References
()
Details
(Keywords: regression)
Attachments
(2 files, 2 obsolete files)
49.80 KB,
patch
|
Details | Diff | Splinter Review | |
49.77 KB,
patch
|
Details | Diff | Splinter Review |
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.9.2b1) Gecko/20091029 Firefox/3.6b1 (.NET CLR 3.5.30729)
Build Identifier: Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.9.2b1) Gecko/20091029 Firefox/3.6b1 (.NET CLR 3.5.30729)
We have the following DOM (simplified testcase: http://www.rbs.fr/static/test.xul):
<bindinga>
<bindingb />
</bindinga>
where bindinga and bindinga are mapped to custom bindings using the -moz-binding CSS property:
* In firefox 3.5.4, bindinga gets constructed before bindingb.
* In firefox 3.6b1, bindingb gets constructed before bindinga.
This is a major change in the way bindings get loaded, which breaks a lot code that was written based on the current loading mechanism (parent gets constructed before children).
Reproducible: Always
Steps to Reproduce:
1. Load http://www.rbs.fr/static/test.xul
Actual Results:
Two alerts : constructing B then constructing A
Expected Results:
Two alerts : constructing A then constructing B
Assignee | ||
Updated•15 years ago
|
Status: UNCONFIRMED → NEW
Ever confirmed: true
Flags: blocking1.9.2?
Assignee | ||
Comment 1•15 years ago
|
||
Looks like this behavior changed between 2009-03-05-02 (rev 5e81fbdd55e4) and 2009-03-06-02 (rev 3270fd0db0f0).
Pushlog: http://hg.mozilla.org/mozilla-central/pushloghtml?fromchange=5e81fbdd55e4&tochange=3270fd0db0f0
Likely a change from bug 480979.
Blocks: 480979
Assignee | ||
Comment 2•15 years ago
|
||
Yeah, so the old code flow was that we'd process all the kids for the frame _then_ call AddToAttachedQueue (misnamed, since it's actually adding to a stack) on the binding of the frame. So the constructor for the parent would run before the constructors for the kids.
The new code flow is that the order actually depends on the display type; the binding is enqueued from AddFrameConstructionItemsInternal, which usually does NOT recurse into kids, but might for inline frames.
It's a little sad-making that we didn't have a test for this. :(
Of course this raises the interesting question of what we do now that we shipped b1 this way... Its pretty easy to restore the old behavior; will put up a patch for it tomorrow (well, later today).
Comment 3•15 years ago
|
||
This is a regression since Firefox 3.5, blocking. bz is working on a patch for this, initial ETA later today.
Assignee: nobody → bzbarsky
Flags: blocking1.9.2? → blocking1.9.2+
Keywords: regression
Priority: -- → P2
Target Milestone: --- → mozilla1.9.2
Assignee | ||
Comment 4•15 years ago
|
||
OK. So the two behaviors we need to preserve from 1.9.1, presumably, are:
1) Sibling constructors fire in reverse order, even if some of the nodes are
display:none.
2) Ancestor constructors fire before descendant constructors.
So effectively the constructors fire in a depth-first preorder traversal of the DOM, with child lists walked backwards...
In terms of calling AddToAttachedQueue(), that means it needs to be called in a depth-first post-order traversal of the tree, walking child lists normally.
The display:none thing means that we can't just store the binding to call AddToAttachedQueue on in the frame construction item, which is what I was initially planning to do. If we relax condition 1 above for display:none nodes, then we could go with that plan. If not, I need to think about the right data structure to use here... It's probably better to preserve compat for now, I guess.
Assignee | ||
Comment 5•15 years ago
|
||
Oh, and ETA is pretty definitely tomorrow afternoon (since I'm taking tomorrow morning off as a half-belated-birthday kind of thing).
Assignee | ||
Comment 6•15 years ago
|
||
The idea is described in the big comment in nsCSSFrameConstructor.h. Most of the patch is passing around the relevant nsBindingTracker; the fact that some of the construction functions (e.g. ConstructBlock or the select stuff) don't take FrameConstructionItems made this a bit more annoying.
I made sure that native anonymous content gets the same treatment, with one exception: scrollframes. Their native anonymous content is somewhat inconsistent anyway, and the ordering there shouldn't matter. I can add some more code to handle that if desired, but I don't think we need that.
This passes the content/xbl tests; I pushed to try for the rest.
If desired we could easily allocate nsBindingTracker out of the presshell arena; I just figured it wasn't worth the hassle. If this seems to be a Txul hit, I'll reconsider.
roc, I think beltzner wants this on 1.9.2 sometime tomorrrow. :(
Attachment #410343 -
Flags: review?(roc)
Comment on attachment 410343 [details] [diff] [review]
Patch
+ // No parent anything here with pending binding ctors
I can only barely parse this, please rephrase.
Would it make more sense to call nsBindingTracker nsPendingBinding? Or just PendingBinding since this is file scope.
+ nsBindingTracker* bindingTracker = nsnull;
Make this an nsAutoPtr and use .forget() when calling AddBindingTracker?
Attachment #410343 -
Flags: review?(roc) → review+
Assignee | ||
Comment 8•15 years ago
|
||
> I can only barely parse this, please rephrase.
How about:
// We don't have a parent frame with a pending binding constructor here,
// so no need to worry about ordering of the kids' constructors with it.
// Pass null for the PendingBinding.
> Would it make more sense to call nsBindingTracker nsPendingBinding? Or just
> PendingBinding since this is file scope.
Yeah, ok. I can do that. It's not quite file scope since it's mentioned in the header, but good enough.
> Make this an nsAutoPtr and use .forget() when calling AddBindingTracker?
I need the pointer after that point in the function. I suppose I could have a separate variable for that, and use an nsAutoPtr around the allocation to keep track of ownership and simplify logic (and set the variable right before adding to the state). I'll do that.
Assignee | ||
Comment 9•15 years ago
|
||
Attachment #410343 -
Attachment is obsolete: true
Assignee | ||
Comment 10•15 years ago
|
||
Status: NEW → RESOLVED
Closed: 15 years ago
Flags: in-testsuite+
Resolution: --- → FIXED
Assignee | ||
Comment 11•15 years ago
|
||
Backed out due to browser-chrome failures in browser_sanitizeDialog.js:
http://hg.mozilla.org/mozilla-central/rev/6258b513a554
It seems to be confused about whether the expander is actually open and whether the warning panel should be appearing... I have no idea yet whether this is a real issue or a bug in the test (though I can't see any problems when manually opening the dialog in question, so I suspect bug in the test). Will investigate tomorrow.
Status: RESOLVED → REOPENED
Flags: in-testsuite+
Resolution: FIXED → ---
Comment 12•15 years ago
|
||
I didn't have any ideas after a quick look; maybe Drew has some?
Comment 13•15 years ago
|
||
It's the last test that's failing, the one made up of six functions testing persisting the details expansion. Investigating...
Assignee | ||
Comment 14•15 years ago
|
||
OK. With Drew's help, I think I know what's up here. The problem is that the sanitize dialog is not ending up sizing intrinsically. This happens because its nsXULWindow::mIntrinsicallySized is false, and _that_ happens because nsXULWindow::SetSize gets called before nsXULWindow::OnChromeLoaded.
The caller of SetSize is a resizeBy call from JS, with this JS stack:
1 anonymous() ["chrome://browser/content/sanitizeDialog.js":114]
warningBox = [object XULElement @ 0x1a9a4990 (native @ 0x1a9bbf10)]
this = [object Object]
2 onselect(event = [object Event @ 0x1989dfd0 (native @ 0x1989df90)]) ["chrome://brow
ser/content/sanitize.xul":1]
this = [object XULElement @ 0x1ed50830 (native @ 0x19858050)]
3 set_selectedItem(val = [object XULElement @ 0x19868980 (native @ 0x1a9bdf30)]) ["ch
rome://global/content/bindings/menulist.xml":249]
event = [object Event @ 0x1989dfd0 (native @ 0x1989df90)]
oldval = [object XULElement @ 0x1a92e700 (native @ 0x197de430)]
this = [object XULElement @ 0x1ed50830 (native @ 0x19858050)]
4 set_value(val = 0) ["chrome://global/content/bindings/menulist.xml":101]
popup = [object XULElement @ 0x1ac101f0 (native @ 0x197e64c0)]
arr = [object HTMLCollection @ 0x19630880 (native @ 0x198ed740)]
this = [object XULElement @ 0x1ed50830 (native @ 0x19858050)]
5 setValue(value = 0, attribute = "value", element = [object XULElement @ 0x1ed50830
(native @ 0x19858050)]) ["chrome://global/content/bindings/preferences.xml":423]
this = [object ChromeWindow @ 0x197c3870 (native @ 0x197af510)]
6 setElementValue(aElement = [object XULElement @ 0x1ed50830 (native @ 0x19858050)])
["chrome://global/content/bindings/preferences.xml":440]
setValue = [function]
val = 0
f = undefined
event = undefined
rv = undefined
this = [object XULElement @ 0x1eef0580 (native @ 0x198e8280)]
7 updateElements() ["chrome://global/content/bindings/preferences.xml":524]
i = 0
elements = [object HTMLCollection @ 0x19630840 (native @ 0x197c9cb0)]
this = [object XULElement @ 0x1eef0580 (native @ 0x198e8280)]
8 _setValue(aUpdate = false, aValue = 0) ["chrome://global/content/bindings/preferences.xml":168]
this = [object XULElement @ 0x1eef0580 (native @ 0x198e8280)]
9 () ["chrome://global/content/bindings/preferences.xml":118]
l = undefined
parentPrefs = undefined
k = undefined
parentPreferences = undefined
preference = undefined
pdoc = undefined
this = [object XULElement @ 0x1eef0580 (native @ 0x198e8280)]
This is the <preference> constructor running, reading the privacy.sanitize.timeSpan preference and calling this._setValue on the <preference> element. That goes and updates the elements observing the preference, which in this case is a <menulist>. The menulist's value setter triggers its onselect handler, which calls gSanitizePromptDialog.selectByTimespan() which makes the resizeBy call. This code was added in bug 480169, which did land on 1.9.1, but didn't land on trunk until after bug 480979...
Note that the failing part of the test (the last 6 entries in the test array) was largely added post-1.9.1 (in bug 488691).
Assignee | ||
Comment 15•15 years ago
|
||
OK, I changed frame construction to fix this bug (so fire parent constructors before children) but not restore the 3.5 behavior otherwise (so construct children in order, not reverse order) and I still get the sanitize failure.
If I do children before parents, children in reverse order, I do NOT get the sanitize failure.
Assignee | ||
Comment 16•15 years ago
|
||
In other words, the sanitize test is somehow actually depending on the buggy behavior.
Assignee | ||
Comment 17•15 years ago
|
||
OK, a bit more digging... the first failing test is the first one that calls checkDetails after the sanitize.timeSpan pref has been set to Sanitizer.TIMESPAN_EVERYTHING. The test before that one also has the bogus SetSize call, but doesn't ever check the window size, so passes.
And the reason for the behavior change is that the <prefwindow> constructor fires paneload on the prefpane here (because it has no src=""), so that calls gSanitizePromptDialog.init() from he prefwindow constructor. selectByTimespan(), which is what makes those resizeBy() calls, is a no-op if init() hasn't been called yet.
Assignee | ||
Comment 18•15 years ago
|
||
OK, if on 1.9.1 I change selectByTimespan to not pay attention to whether init() has been called, I get failures there too.
Assignee | ||
Comment 19•15 years ago
|
||
Aaaand on 1.9.1 the <preference> constructors fire _before_ the <prefwindow> constructor does.
Assignee | ||
Comment 20•15 years ago
|
||
And _that_ is because the parent's constructor fires before the children _unless_ the parent is the root. In that case it fires after. In 1.9.1, that is.
And that behavior dates back to when hyatt initially made constructors run on the root at all, back in bug 73137.
The good news is that this simply means I need to take out the ConstructDocElementFrame parts of this patch. Will post updated patch for relanding, but after dinner.
Assignee | ||
Comment 21•15 years ago
|
||
This just adjusts the test to test the root element too, and reverts the changes to ConstructDocElementFrame, replacing them with comments about the screwed-up-behavior.
Attachment #410354 -
Attachment is obsolete: true
Assignee | ||
Comment 22•15 years ago
|
||
Pushed that last patch as http://hg.mozilla.org/mozilla-central/rev/77512fa7701e
Status: REOPENED → RESOLVED
Closed: 15 years ago → 15 years ago
Flags: in-testsuite+
Resolution: --- → FIXED
Assignee | ||
Comment 23•15 years ago
|
||
Assignee | ||
Comment 24•15 years ago
|
||
status1.9.2:
--- → beta2-fixed
Assignee | ||
Comment 25•15 years ago
|
||
Somehow I failed to remove AutoEnqueueBinding in these patches. Just pushed http://hg.mozilla.org/mozilla-central/rev/d859fbeb4fca to remove that on m-c; not going to worry for 1.9.2.
You need to log in
before you can comment on or make changes to this bug.
Description
•