Closed
Bug 293825
Opened 19 years ago
Closed 19 years ago
[FIX]Improve CSSLoader api
Categories
(Core :: CSS Parsing and Computation, defect, P1)
Core
CSS Parsing and Computation
Tracking
()
RESOLVED
FIXED
mozilla1.9alpha1
People
(Reporter: bzbarsky, Assigned: bzbarsky)
References
Details
Attachments
(3 files, 3 obsolete files)
95.77 KB,
patch
|
peterv
:
review+
peterv
:
superreview+
|
Details | Diff | Splinter Review |
97.09 KB,
patch
|
Details | Diff | Splinter Review | |
1.09 KB,
patch
|
jst
:
review+
jst
:
superreview+
|
Details | Diff | Splinter Review |
I started poking at bug 84582 again and realized that making the CSSLoader api saner was more or less a prerequisite for me fixing that bug... Patch coming up; the goal is to change behavior as little as possible, but at the same time make async loads really async, make it clear when observers are notified, make error handling more consistent, and move the alternate sheet stuff as much as possible into the loader. Note that this patch depends on the patch in bug 293818.
Assignee | ||
Comment 1•19 years ago
|
||
Assignee | ||
Updated•19 years ago
|
Attachment #183325 -
Attachment description: Proposed pach → Proposed patch (diff -w)
Assignee | ||
Comment 2•19 years ago
|
||
Assignee | ||
Updated•19 years ago
|
Attachment #183325 -
Flags: superreview?(peterv)
Attachment #183325 -
Flags: review?(bugmail)
Assignee | ||
Comment 3•19 years ago
|
||
For now, because of the way the parser-blocking stuff works, I addded the following in the "sheet already complete" branch in LoadStyleLink before PostLoadEvent: // XXXbz nasty hack because we end up blocking the parser in XUL, then // unblocking it, but firing onload first... Just don't block the parser // for stylesheets that are already complete. It's not like the load event // will do anything useful for us anyway here. *aIsAlternate = PR_TRUE; Otherwise any XUL doc with more than one sheet was having issues (since the loadgroup counter got decremented before the new sheet was seen by the content sink, basically). The other option would be to make UnblockOnload async, I guess... Not sure whether we want that.
Assignee | ||
Comment 4•19 years ago
|
||
Ignore comment 3. That was happening because I was unblocking onload in both HandleEvent and DestroyEvent. The former should not have been there, and removing it makes things here quite happy without that hack.
Assignee | ||
Updated•19 years ago
|
Priority: -- → P1
Target Milestone: --- → mozilla1.9alpha
Assignee | ||
Updated•19 years ago
|
Assignee | ||
Comment 5•19 years ago
|
||
It looks like the problems described in bug 188030 are not around anymore; XBL now always does a sync sheet load for chrome... Given that, I'd rather not design the CSSLoader api around XBL brokenness (and would like the fully-async API for the async case).
Comment 6•19 years ago
|
||
Comment on attachment 183325 [details] [diff] [review] Proposed patch (diff -w) > Index: layout/style/nsICSSLoaderObserver.h > =================================================================== > + * @param aWasAlternate whether the sheet was an alternate. This will always > + * match the value LoadStyleLink or LoadInlineStyle returned if one of > + * those methods were used to load the sheet, and will always be false > + * otherwise. Er, those return nsresult, you mean "... LoadStyleLink or LoadInlineStyle returned in aIsAlternate ...". Isn't it simpler to just say that it returns "whether the stylesheet ended up being an alternate sheet."? >Index: layout/style/nsICSSLoader.h >=================================================================== >+ * @return whether the stylesheet ended up being an alternate sheet. This seems to describe aIsAlternate. > NS_IMETHOD LoadInlineStyle(nsIContent* aElement, >+ * @return whether the stylesheet actually ended up being an alternate sheet. >+ * Note that this need not match aHasAlternateRel. This seems to describe aIsAlternate. It always matches if aHasAlternateRel is true, right? > NS_IMETHOD LoadStyleLink(nsIContent* aElement, >+ /** >+ * Load a child (@import-ed) style sheet. In addition to loading the sheet, >+ * this method will insert it into the child sheet list of aParentSheet. If >+ * there is no sheet currently being parsed, aParentSheet will be QIed to >+ * nsICSSLoaderObserver and asynchronously notified, just like for >+ * LoadStyleLink, when the child sheet is complete if it's not already. If >+ * the child sheet _is_ already complete, no notification will be sent. I find this sentence confusing. "... just like for LoadStyleLink, once the child sheet is complete. If ..."? >+ * @return the loaded, complete sheet. This seems to describe aSheet. >+ NS_IMETHOD LoadSheetSync(nsIURI* aURL, nsICSSStyleSheet** aSheet) = 0; >Index: layout/style/nsCSSLoader.h >=================================================================== >+ // mIsAgent is true if the load was triggered by LoadSheetSync or >+ // LoadSheet or an @import from such a sheet. Agent loads can Hmm, I didn't see any doc for LoadSheetSync or LoadSheet that said they load agent sheets. >+ // proceed even if we have no document. >+ PRPackedBool mIsAgent : 1; > // mIsLoading is true from the moment we are placed in the loader's > // "loading datas" table (right after the async channel is opened) > // to the moment we are removed from said table (due to the load > // completing or being cancelled). >- PRPackedBool mIsLoading; // Set once the data is in the "loading" table >+ PRPackedBool mIsLoading : 1; // Set once the data is in the "loading" table While you're in there, remove the redundant comment? >Index: layout/style/nsCSSLoader.cpp >=================================================================== > PR_STATIC_CALLBACK(PLDHashOperator) > StartNonAlternates(nsIURI *aKey, SheetLoadData* &aData, void* aClosure) >+ // Note that we don't want to affect what the selected style set is, >+ // so use PR_TRUE for aHasAlternateRel. It seems a bit fragile that aHasAlternateRel affects what IsAlternate does to the selected style set. >+CSSLoaderImpl::IsAlternate(const nsAString& aTitle, PRBool aHasAlternateRel) >+ if (!aHasAlternateRel && mDocument && mPreferredSheet.IsEmpty()) { >+ // There's no preferred set yet, and we now have a sheet with a title. >+ // Make that be the preferred set. >+ // XXXbz maybe this should be checking IsVoid(), actually, since the >+ // preferred set can be explicitly set to the empty string. Look into >+ // this. IMHO, yes. File a bug? >+ mDocument->SetHeaderData(nsHTMLAtoms::headerDefaultStyle, aTitle); Please document clearly that IsAlternate can set the default styleset. >+nsresult >+CSSLoaderImpl::PostLoadEvent(nsIURI* aURI, >+ nsICSSStyleSheet* aSheet, >+ nsICSSLoaderObserver* aObserver, >+ nsIParser* aParserToUnblock, >+ PRBool aWasAlternate) >+ nsresult rv; >+ nsCOMPtr<nsIEventQueueService> eventQService = >+ do_GetService("@mozilla.org/event-queue-service;1", &rv); >+ NS_ENSURE_TRUE(eventQService, rv); nsContentUtils::EventQueueService(). >+void >+CSSLoaderImpl::HandleLoadEvent(SheetLoadData* aEvent) >+ if (mDocument) { >+ mDocument->UnblockOnload(); >+ } >+} >+ >+void >+CSSLoaderImpl::DestroyLoadEvent(SheetLoadData* aEvent) >+{ >+ mPostedEvents.RemoveElement(aEvent); >+ NS_RELEASE(aEvent); >+ if (mDocument) { >+ mDocument->UnblockOnload(); Won't this call UnblockOnload too many times (since you called it in HandleLoadEvent)? >Index: content/xul/document/src/nsXULContentSink.cpp >=================================================================== >- // Nope, we need to load it asynchronously >- PRBool blockParser = PR_FALSE; >- if (! aAlternate) { >- if (!aTitle.IsEmpty()) { // possibly preferred sheet >- if (mPreferredStyle.IsEmpty()) { >- mPreferredStyle = aTitle; I think this means you can remove mPreferredStyle. Why do we pass aWasAlternate to StyleSheetLoaded?
Assignee | ||
Comment 7•19 years ago
|
||
> Er, those return nsresult I meant "return" in the idl sense... For the rest, I just wanted to precisely define what it means to have "ended up being an alternate sheet", since whether a sheet is alternate can actually change while the sheet is loading. I'll explicitly mention aIsAlternate. > >+ * @return whether the stylesheet ended up being an alternate sheet. > This seems to describe aIsAlternate. Again, that would be the return value if this were expressed in IDL... I suppose I can call it @param instead if you'd prefer. Same for a few other places. > It always matches if aHasAlternateRel is true, right? No, it matches if the title isn't the default title. All aHasAlternateRel affects is setting of the default if no default is set yet. > I find this sentence confusing. What I'm trying to say is that if the child is not yet complete by the time LoadChildSheet returns, when it becomes complete the parent will be notified. I'll rephrase to make this clearer. > Hmm, I didn't see any doc for LoadSheetSync or LoadSheet that said they load > agent sheets. mIsAgent is perhaps somewhat misnamed (just as LoadAgentSheet was); I could rename it to mNonDocumentSheet throughout, I suppose. Let me know if you want me to do that. > It seems a bit fragile that aHasAlternateRel affects what IsAlternate does to > the selected style set If there is no currently selected style set then per spec <link rel="stylesheet" title="foo"> should make "foo" the currently selected set and make this sheet not be an alternate sheet, while <link rel="alternate stylesheet" title="foo"> should leave things as they are (no selected set) and make this sheet be an alternate sheet. I could move the changing of the style set out of IsAlternate and just call that function before calling IsAlternate in every single place where I call IsAlternate... But that seemed a little silly. > IMHO, yes. File a bug? It sorta falls under the bug about scriptable selection of style sets I already have... > Please document clearly that IsAlternate can set the default styleset. Will do. > nsContentUtils::EventQueueService(). I should have posted an updated patch. :( > Won't this call UnblockOnload too many times See comment 4. I really should have posted an updated patch. :( > I think this means you can remove mPreferredStyle. Hmm.. Actually, I can, but I need to make sure to copy over the header from the proto doc to the non-proto one. I'll do that; could you check over that part carefully again when I post the updated patch? > Why do we pass aWasAlternate to StyleSheetLoaded? Because I need that for bug 84582.
Comment 8•19 years ago
|
||
peterv: In case this helps -- there are three types of stylesheet sets; persistent, preferred, and alternate. The currently selected stylesheet set is one of the preferred and alternate sets. The persistent stylesheets are enabled regardless of which set is selected. Hope this helps. :-)
Comment 9•19 years ago
|
||
Comment on attachment 183325 [details] [diff] [review] Proposed patch (diff -w) Setting to minus, awaiting new patch.
Attachment #183325 -
Flags: superreview?(peterv)
Attachment #183325 -
Flags: superreview-
Attachment #183325 -
Flags: review?(bugmail)
Assignee | ||
Comment 10•19 years ago
|
||
Attachment #183325 -
Attachment is obsolete: true
Attachment #183326 -
Attachment is obsolete: true
Attachment #195464 -
Flags: superreview?(peterv)
Attachment #195464 -
Flags: review?(peterv)
Assignee | ||
Comment 11•19 years ago
|
||
Comment 12•19 years ago
|
||
Comment on attachment 195464 [details] [diff] [review] Updated diff -w With adding a comment that LoadSheet(Sync) load non-document stylesheets.
Attachment #195464 -
Flags: superreview?(peterv)
Attachment #195464 -
Flags: superreview+
Attachment #195464 -
Flags: review?(peterv)
Attachment #195464 -
Flags: review+
Assignee | ||
Comment 13•19 years ago
|
||
Hurray! Fixed!
Status: NEW → RESOLVED
Closed: 19 years ago
Resolution: --- → FIXED
Comment 14•19 years ago
|
||
Well, yes, but it seems like this caused random crashes in odd places... I pointed Purify at this, and here's what I got: [E] FMW: Free memory write in CSSLoaderImpl::LoadChildSheet(nsICSSStyleSheet *,nsIURI *,nsMediaList *,nsICSSImportRule *) {2 occurrences} Writing 1 byte to 0x05987ba0 (1 byte at 0x05987ba0 illegal) Address 0x05987ba0 is 112 bytes into a 124 byte block at 0x05987b30 Address 0x05987ba0 points to a C++ new block in heap 0x01c70000 Thread ID: 0xecc Error location CSSLoaderImpl::LoadChildSheet(nsICSSStyleSheet *,nsIURI *,nsMediaList *,nsICSSImportRule *) [e:\tip\mozilla\layout\style\nscssloader.cpp:1839] rv = LoadSheet(data, state); NS_ENSURE_SUCCESS(rv, rv); => data->mMustNotify = PR_TRUE; return rv; } CSSParserImpl::ProcessImport(UINT&,nsString const&,nsMediaList *,(*)(nsICSSRule *,void *),void *) [e:\tip\mozilla\layout\style\nscssparser.cpp:1365] CSSParserImpl::ParseImportRule(UINT&,(*)(nsICSSRule *,void *),void *) [e:\tip\mozilla\layout\style\nscssparser.cpp:1336] CSSParserImpl::ParseAtRule(UINT&,(*)(nsICSSRule *,void *),void *) [e:\tip\mozilla\layout\style\nscssparser.cpp:1177] CSSParserImpl::Parse(nsIUnicharInputStream *,nsIURI *,nsIURI *,UINT,nsICSSStyleSheet *&) [e:\tip\mozilla\layout\style\nscssparser.cpp:697] CSSLoaderImpl::ParseSheet(nsIUnicharInputStream *,SheetLoadData *,int&) [e:\tip\mozilla\layout\style\nscssloader.cpp:1421] CSSLoaderImpl::LoadSheet(SheetLoadData *,StyleSheetState) [e:\tip\mozilla\layout\style\nscssloader.cpp:1272] CSSLoaderImpl::LoadChildSheet(nsICSSStyleSheet *,nsIURI *,nsMediaList *,nsICSSImportRule *) [e:\tip\mozilla\layout\style\nscssloader.cpp:1836] CSSParserImpl::ProcessImport(UINT&,nsString const&,nsMediaList *,(*)(nsICSSRule *,void *),void *) [e:\tip\mozilla\layout\style\nscssparser.cpp:1365] CSSParserImpl::ParseImportRule(UINT&,(*)(nsICSSRule *,void *),void *) [e:\tip\mozilla\layout\style\nscssparser.cpp:1336] Allocation location new(UINT) [f:\vs70builds\3077\vc\crtbld\crt\src\newop.cpp:10] CSSLoaderImpl::LoadChildSheet(nsICSSStyleSheet *,nsIURI *,nsMediaList *,nsICSSImportRule *) [e:\tip\mozilla\layout\style\nscssloader.cpp:1825] CSSParserImpl::ProcessImport(UINT&,nsString const&,nsMediaList *,(*)(nsICSSRule *,void *),void *) [e:\tip\mozilla\layout\style\nscssparser.cpp:1365] CSSParserImpl::ParseImportRule(UINT&,(*)(nsICSSRule *,void *),void *) [e:\tip\mozilla\layout\style\nscssparser.cpp:1336] CSSParserImpl::ParseAtRule(UINT&,(*)(nsICSSRule *,void *),void *) [e:\tip\mozilla\layout\style\nscssparser.cpp:1177] CSSParserImpl::Parse(nsIUnicharInputStream *,nsIURI *,nsIURI *,UINT,nsICSSStyleSheet *&) [e:\tip\mozilla\layout\style\nscssparser.cpp:697] CSSLoaderImpl::ParseSheet(nsIUnicharInputStream *,SheetLoadData *,int&) [e:\tip\mozilla\layout\style\nscssloader.cpp:1421] CSSLoaderImpl::LoadSheet(SheetLoadData *,StyleSheetState) [e:\tip\mozilla\layout\style\nscssloader.cpp:1272] CSSLoaderImpl::LoadChildSheet(nsICSSStyleSheet *,nsIURI *,nsMediaList *,nsICSSImportRule *) [e:\tip\mozilla\layout\style\nscssloader.cpp:1836] CSSParserImpl::ProcessImport(UINT&,nsString const&,nsMediaList *,(*)(nsICSSRule *,void *),void *) [e:\tip\mozilla\layout\style\nscssparser.cpp:1365] Free location SheetLoadData::`vector deleting destructor'(UINT) [E:\tip\fb-prf\dist\bin\components\gklayout.dll] SheetLoadData::Release(void) [e:\tip\mozilla\layout\style\nscssloader.cpp:141] CSSLoaderImpl::SheetComplete(SheetLoadData *,UINT) [e:\tip\mozilla\layout\style\nscssloader.cpp:1551] CSSLoaderImpl::ParseSheet(nsIUnicharInputStream *,SheetLoadData *,int&) [e:\tip\mozilla\layout\style\nscssloader.cpp:1431] CSSLoaderImpl::LoadSheet(SheetLoadData *,StyleSheetState) [e:\tip\mozilla\layout\style\nscssloader.cpp:1272] CSSLoaderImpl::LoadChildSheet(nsICSSStyleSheet *,nsIURI *,nsMediaList *,nsICSSImportRule *) [e:\tip\mozilla\layout\style\nscssloader.cpp:1836] CSSParserImpl::ProcessImport(UINT&,nsString const&,nsMediaList *,(*)(nsICSSRule *,void *),void *) [e:\tip\mozilla\layout\style\nscssparser.cpp:1365] CSSParserImpl::ParseImportRule(UINT&,(*)(nsICSSRule *,void *),void *) [e:\tip\mozilla\layout\style\nscssparser.cpp:1336] CSSParserImpl::ParseAtRule(UINT&,(*)(nsICSSRule *,void *),void *) [e:\tip\mozilla\layout\style\nscssparser.cpp:1177] CSSParserImpl::Parse(nsIUnicharInputStream *,nsIURI *,nsIURI *,UINT,nsICSSStyleSheet *&) [e:\tip\mozilla\layout\style\nscssparser.cpp:697] I'll try to have a look at this, but I don't know when I'll get to it. Reopening until we figure this out.
Status: RESOLVED → REOPENED
Resolution: FIXED → ---
Comment 15•19 years ago
|
||
Attachment #196275 -
Flags: superreview?(bzbarsky)
Attachment #196275 -
Flags: review?(bzbarsky)
Assignee | ||
Comment 16•19 years ago
|
||
Hmm.... jst, does saving data->mSyncLoad in a local before calling LoadSheet and only messing with data->mMustNotify if data->mSyncLoad is false also fix the FMR? That's the only way I can think of that |data| would be gone there; if |data| is dying and |data->mSyncLoad| is false and NS_OK is being returned from LoadSheet, we have a problem.
Assignee | ||
Comment 17•19 years ago
|
||
Comment 18•19 years ago
|
||
Comment on attachment 196284 [details] [diff] [review] Like so Yeah, that fixes it too. It'd still be cool to eliminate some of this manual refcounting in favor of nsRefPtr<>'s and a cleaner model in general, but this does at least fix the crashes I'm seeing, and the FMW in Purify.
Attachment #196284 -
Flags: superreview+
Attachment #196284 -
Flags: review+
Assignee | ||
Updated•19 years ago
|
Attachment #196275 -
Attachment is obsolete: true
Attachment #196275 -
Flags: superreview?(bzbarsky)
Attachment #196275 -
Flags: review?(bzbarsky)
Assignee | ||
Comment 19•19 years ago
|
||
Checked that patch in.
Status: REOPENED → RESOLVED
Closed: 19 years ago → 19 years ago
Resolution: --- → FIXED
You need to log in
before you can comment on or make changes to this bug.
Description
•