Closed Bug 218837 Opened 21 years ago Closed 21 years ago

Share code between XML and HTML contentsinks

Categories

(Core :: DOM: Core & HTML, defect)

defect
Not set
normal

Tracking

()

RESOLVED FIXED

People

(Reporter: keeda, Assigned: keeda)

References

Details

Attachments

(5 files, 4 obsolete files)

There's is a quite a bit of code in XML and HTML contentsink that really looks very similar and should be relatively easy to factor out into a common place.
Attached patch v1 (obsolete) — Splinter Review
Initial stab at making them inherit from a common base class. This throws a bunch of random stuff including link handling, script element handling into a class called nsContentSink. - The link stuff is mostly taken from the htmlsink. This means that prefetch should now work for xml/xhtml. - The script element stuff is closer to the xmlsink. This will mean that the scriptloader no longer holds on to a hard ref to the html contentsink. - Other than these, there really shouldn't be any major functional change. The other stuff is minor. I've tried to stay away from the temptation to cleanup some of the code that I am copying, except for straightforward nsCOMPtr conversions, or when its needed because the code in the two places has deviated. One other thing that deserves a mention is that nsXMLContentSink had threadsafe AddRef and Release. I couldnt see the point of that. Removed. This is not really tested. I have just confirmed, I am able to bring up the browser and browse around, load a few xml docs and xhtml pages.
Yeah, I know about bug 21771. This is a subset and and should probably block that bug. I don't want to deal with XUL for now. Adding some more ppl who might be interested. Some more things I should have said about the patch ... - nsContentSink is probably not a good name for that class, since it clearly is not a very generic contentsink implementation. I can't think of anything better though. Suggestions welcome. - I wanted nsContentSink to inherit from nsIContentSink, but ran into trouble since nsIHTMLContentSink and nsIXMLContentSink inherit from nsIContentSink too. Which means that we end up with diamond inheritance issues. I'm not sure we want to use virtual inheritance etc. So I don't know how to proceed with that. Some stuff is currently |#if 0|ed out as a result. - This really is not ready for review. Actucally, it started out more as an investigation of how much common code there really was. But I am looking for feedback about whether people like the general direction in which this is going.
Status: NEW → ASSIGNED
first off, i only looked at the patch briefly, but i'd definitly be interested in a deeper look when i've got the time. In general though this sounds like a very good first step and I agree with your suggested relationship to bug 21771. (Btw, this takes care of the remainder of bug 188729 too). Wrt nsContentSink inhereting nsIContentSink. As you noted it won't really help since the other contentsinks will need to implement it anyway. Which functions do you want to implement in nsContentSink? You could always put the implementation in nsContentSink and then forward the call in the html/xml sinks.
Blocks: 21771, 188729
Attachment #131187 - Attachment is obsolete: true
Attached patch updated patch (obsolete) — Splinter Review
Minor updates. Nothing much new. I've been running with this in my tree for a while now. Its ready for review. (BTW, this will conflict a little bit with caillon's big security patch.)
Attachment #131252 - Attachment is obsolete: true
Attachment #131962 - Flags: review?(bugmail)
Comment on attachment 131962 [details] [diff] [review] updated patch This is an awsome patch! The only think that i'm slightly worried about is change to the linkhandling in the xml-sink. The code in the http-sink is definitly better so you made a good choise, but I'm wondering if there might be any xml-specific things (or general bugfixes) in the xmlsink that got lost? What I would mostly like to hear is if/how you compared the differences between the two? Some of the things i've commented on are things in code that you've just copied. I tried to stay away from it as much as possible so that we can keep general cleanups in a separate patch, but I think a few snuck through anyway. >Index: base/src/nsContentSink.cpp >+nsContentSink::Init(nsIDocument* aDoc, ... >+ nsCOMPtr<nsIScriptLoader> loader; >+ nsresult rv = mDocument->GetScriptLoader(getter_AddRefs(loader)); >+ NS_ENSURE_SUCCESS(rv, rv); >+ loader->AddObserver(proxy); Please check the returnvalue from AddObserver >+nsContentSink::ScriptAvailable(nsresult aResult, ... >+ // Check if this is the element we were waiting for >+ nsIDOMHTMLScriptElement* scriptElement = mScriptElements[count - 1]; >+ if (aElement != scriptElement) { >+ return NS_OK; >+ } You can compare directly to mScriptElements[...] here. No need for the temporary variable. Same in ScriptEvaluated >+static const PRUnichar kSemiCh = PRUnichar(';'); >+static const PRUnichar kCommaCh = PRUnichar(','); >+static const PRUnichar kEqualsCh = PRUnichar('='); >+static const PRUnichar kLessThanCh = PRUnichar('<'); >+static const PRUnichar kGreaterThanCh = PRUnichar('>'); Does declaring |static| on a global do anything? >+nsresult >+nsContentSink::ProcessStyleLink(nsIContent* aElement, >+ const nsAString& aHref, >+ const PRBool aAlternate, >+ const nsAString& aTitle, >+ const nsAString& aType, >+ const nsAString& aMedia) >+{ >+ nsresult result = NS_OK; >+ PRBool isAlternate = PR_FALSE; in the places further down in this function you should use aAlternate rather then isAlternate (and of course remove isAlternate) >+PRBool >+nsContentSink::ScrollToRef(PRBool aReallyScroll) >+{ >+ PRBool didScroll = PR_FALSE; >+ >+ if (!mRef.IsEmpty()) { Please make this function earlyreturn the way the HTMLSink one did. >+ char* tmpstr = ToNewCString(mRef); >+ if(! tmpstr) { >+ return PR_FALSE; >+ } >+ nsUnescape(tmpstr); >+ nsCAutoString unescapedRef; >+ unescapedRef.Assign(tmpstr); >+ nsMemory::Free(tmpstr); >+ >+ nsresult rv = NS_ERROR_FAILURE; >+ // We assume that the bytes are in UTF-8, as it says in the spec: >+ // http://www.w3.org/TR/html4/appendix/notes.html#h-B.2.1 >+ NS_ConvertUTF8toUCS2 ref(unescapedRef); >+ >+ PRInt32 i, ns = mDocument->GetNumberOfShells(); >+ for (i = 0; i < ns; i++) { >+ nsCOMPtr<nsIPresShell> shell; >+ mDocument->GetShellAt(i, getter_AddRefs(shell)); >+ if (shell) { >+ // Scroll to the anchor >+ if (aReallyScroll) { >+ shell->FlushPendingNotifications(PR_FALSE); >+ } >+ >+ // Check an empty string which might be caused by the UTF-8 conversion >+ if (!ref.IsEmpty()) >+ rv = shell->GoToAnchor(ref, aReallyScroll); >+ else >+ rv = NS_ERROR_FAILURE; Please stick to a single '{' pattern. Most files nowadays use if (foo) { ... } else { ... } Which also happens to be the one i prefer :). >Index: html/document/src/nsHTMLContentSink.cpp ... >- NS_DECL_ISUPPORTS >- NS_DECL_NSISCRIPTLOADEROBSERVER >+ NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr); >+ >+ NS_IMETHOD_(nsrefcnt) AddRef(void); >+ NS_IMETHOD_(nsrefcnt) Release(void); Use NS_DECL_ISUPPORTS_INHERITED instead. Same in the xml contentsink. >+NS_INTERFACE_MAP_BEGIN(HTMLContentSink) >+ NS_INTERFACE_MAP_ENTRY(nsIContentSink) >+ NS_INTERFACE_MAP_ENTRY(nsIHTMLContentSink) >+ NS_INTERFACE_MAP_ENTRY(nsITimerCallback) >+ NS_INTERFACE_MAP_ENTRY(nsIDocumentObserver) >+ NS_INTERFACE_MAP_ENTRY(nsIDebugDumpContent) >+NS_INTERFACE_MAP_END_INHERITING(nsContentSink) > #else >-NS_IMPL_ISUPPORTS6(HTMLContentSink, >- nsIHTMLContentSink, >- nsIContentSink, >- nsIScriptLoaderObserver, >- nsITimerCallback, >- nsICSSLoaderObserver, >- nsIDocumentObserver) >+NS_INTERFACE_MAP_BEGIN(HTMLContentSink) >+ NS_INTERFACE_MAP_ENTRY(nsIContentSink) >+ NS_INTERFACE_MAP_ENTRY(nsIHTMLContentSink) >+ NS_INTERFACE_MAP_ENTRY(nsITimerCallback) >+ NS_INTERFACE_MAP_ENTRY(nsIDocumentObserver) >+NS_INTERFACE_MAP_END_INHERITING(nsContentSink) You can use NS_IMPL_ISUPPORTS_INHERITED here. Same in the XMLContentSink > HTMLContentSink::Init(nsIDocument* aDoc, > nsIURI* aURL, > nsISupports* aContainer, > nsIChannel* aChannel) > { >+ NS_ENSURE_TRUE(aContainer, NS_ERROR_NULL_POINTER); >+ >+ nsresult rv = nsContentSink::Init(aDoc, aURL, aContainer, aChannel); >+ NS_ENSURE_SUCCESS(rv, rv); >+ > MOZ_TIMER_DEBUGLOG(("Reset and start: nsHTMLContentSink::Init(), this=%p\n", > this)); > MOZ_TIMER_RESET(mWatch); > MOZ_TIMER_START(mWatch); > >- if (!aDoc || !aURL || !aContainer) { >- NS_ERROR("Null ptr!"); >- >- MOZ_TIMER_DEBUGLOG(("Stop: nsHTMLContentSink::Init()\n")); >- MOZ_TIMER_STOP(mWatch); >- >- return NS_ERROR_NULL_POINTER; >- } It might be a good idea to do the logging before calling nsContentSinke::Init and keep the |if| (though of course change the condition to NS_FAILED(rv)). I honestly don't know how important it is though. Peterv? > void > HTMLContentSink::TryToScrollToRef() > { > if (mRef.IsEmpty()) { > return; > } > > if (mScrolledToRefAlready) { > return; > } > >- ScrollToRef(PR_TRUE); >-} >- >-void >-HTMLContentSink::ScrollToRef(PRBool aReallyScroll) You're moving the setting of mScrolledToRefAlready into TryToScrollToRef but DidBuildModel calls ScrollToRef too. Do you need to add mScrolledToRefAlready-code in there too? >Index: xml/document/src/nsXMLContentSink.cpp > nsXMLContentSink::ProcessStyleLink(nsIContent* aElement, >- const nsString& aHref, >- PRBool aAlternate, >- const nsString& aTitle, >- const nsString& aType, >- const nsString& aMedia) >+ const nsAString& aHref, >+ const PRBool aAlternate, >+ const nsAString& aTitle, >+ const nsAString& aType, >+ const nsAString& aMedia) just keep aAlternate as a |PRBool| that's what we do elsewhere and it doesn't really make sense to use const on simple datatypes. >- if (aType.EqualsIgnoreCase(kXSLType) || >- aType.EqualsIgnoreCase(kXMLTextContentType) || >- aType.EqualsIgnoreCase(kXMLApplicationContentType)) { >+ NS_ConvertUTF16toUTF8 type(aType); >+ if (type.EqualsIgnoreCase(kXSLType) || >+ type.EqualsIgnoreCase(kXMLTextContentType) || >+ type.EqualsIgnoreCase(kXMLApplicationContentType)) { Hmm.. why wasn't the conversion needed before? >- if (aType.Equals(NS_LITERAL_STRING("text/css"))) { >- nsCOMPtr<nsIURI> url; >- rv = NS_NewURI(getter_AddRefs(url), aHref, nsnull, mDocumentBaseURL); >- if (NS_FAILED(rv)) { >- return NS_OK; // The URL is bad, move along, don't propagate the error (for now) >- } >- PRBool doneLoading; >- rv = mCSSLoader->LoadStyleLink(aElement, url, aTitle, aMedia, >- ((!aAlternate) ? mParser : nsnull), >- doneLoading, >- this); >- // XXX should probably use kBlockByDefault here, no? >- if (NS_SUCCEEDED(rv) && !doneLoading && !aAlternate && mParser) { >- mParser->BlockParser(); >- } >+ // Let nsContentSink deal with css. >+ rv = nsContentSink::ProcessStyleLink(aElement, aHref, aAlternate, >+ aTitle, aType, aMedia); >+ if (rv = NS_ERROR_HTMLPARSER_BLOCK) { >+ mParser->BlockParser(); should be |==|. And you need to check that mParser isn't null i think. And the ending return should return NS_OK, not rv since otherwise a block will be considered a failure in the caller of this function. (This is the reason why I dislike functions endind with "return rv"). Though you need to deal with other errorcodes then block and make sure that they return a failure. r=sicking if you get peterv to sr this
Attachment #131962 - Flags: review?(bugmail) → review+
From a quick glance, it looks like this causes the XML sink to handle style without a TYPE attribute/pseudo-attribute (I'm not sure in what cases the code is used) as CSS, whereas it didn't before. (See changes to ProcessStyleLink.) I don't think we want to do that.
More drive-by comments: ProcessHeaderData for the setcookie header uses ToNewUTF8String in HTML and NS_ConvertUCS2toUTF8().get() in XML. I'd assume you would want to use the latter... (especially since using nsCRT::free to deallocate the result of ToNewUTF8String is wrong, iirc), whereas your patch uses the former. And yes, what dbaron said. It's OK to load a <link rel="stylesheet"> with no type in HTML, but in XML we should load it only if it has type="text/css"... Perhaps we should make that a quirks-vs-standards distinction? David, what do you think?
I'm definitly for making that a quirks vs. standard thing. IMHO we should have as few modes as possible to make things easy for authors. So the closer xml behaves to standards mode the better IMHO. (if that means chaning the way strict behaves or the way that xml behaves i don't have an oppinion on)
For the HTML link element, the type attribute is optional. For the xml-stylesheet PI, it's required. (In both cases, it's advisory, and what the server says wins.) So we should do that.
The code under discussion is actually neither for <link> elements nor for PIs. This is the code use for the HTTP header: Link: <http://whatever>; type="text/css"; rel="stylesheet" and the equivalent <meta> tag. I _think_ the idea is that this should work like an HTML <link> element, but...
The "type" attribute is optional on all of the above (<link>, Link:, <? xml-stylesheet?>, etc). (For the XML Stylesheet PI, you have to read the errata to notice that it is optional.) So in all cases, preferably by only coding this once and having them all go through the same codepath, we should be treating the optional type attribute as advisory, and treating a missing (or empty) value as a wildcard. Note that an _empty_ type attribute for HTML is equivalent to a missing type attribute, and that since the others are all defined to have the same semantics as HTML, that goes for them too.
Comment on attachment 131962 [details] [diff] [review] updated patch Thanks for all the comments. I've got caught up in some other stuff. But hopefully, I'll get time to go through the comments and post an updated patch over the weekend. The <link> handling is clearly the most controversial part of this, and the part that I am least confident about. Maybe I should just first do a patch that refactors in-place only those parts of the two sinks, to bring them closer. I can then move the code into the base class as step 2?
Attachment #131962 - Attachment is obsolete: true
No, i think we should go with this. I'll look through the differences again to be extra sure that it all looks good. Ian: so what you're saying is that all links should behave exactly the same <meta>, http-header, <link> and <?xml-stylesheet?> ? Do we need any differences between strict and quirks mode? Harshals patch uses the current html-code for linkparsing in both html and xml, is there to your knowledge anything that it does wrong?
I'm not familiar with the bugs in those areas at the moment. I'm sure there are some, there always are. :-) Yes, as I understand it, those should all work in just the same way. You might want to run this past peterv, he knew this code quite well at one point IIRC.
I'll attach an updated patch shortly, but let me address a few comments first. > The only think that i'm slightly worried about is > change to the linkhandling in the xml-sink. The code in the http-sink is > definitly better so you made a good choise, but I'm wondering if there might > be any xml-specific things (or general bugfixes) in the xmlsink that got > lost? What I would mostly like to hear is if/how you compared the > differences between the two? I looked at cvs blame and relevant bugs. I don't think that the xml code has changed in any significant way since Heikki first introduced it in the XMLSink in bug 93218. I couldn't find any bugfix since that would needed to be carried over. The HTMLSink version has had a lot more attention. Amongst other bugfixes, it has been whacked significantly two times. First in bug 166647 by darin for the prefetch stuff, and then by jst when he cleaned up a lot of string and whitespace foo in bug 168371. So, I just went with the html version. Which means that, as far as I know, I have not changed behavior in any situation in the html case. In the xml case, I looked at what changed, and thought that in each case the html behavior was more desirable. I know of two such things, one of which dbaron pointed out. I'll shortly attach testcases for each.
Attached file Testcase 1
This is what dbaron pointed out. With the current patch, all the four lines here will be green. We currently make only the first three green. I'm open to changing it back to keeping the current behavior if people really want that, or making it a quirks thing or whatever. Let me know what this should render like, and I will make it so. For now, going by what Ian said in his last couple of comments, I've kept this behavior. I looked this up, and, as Ian pointed out http://www.w3.org/1999/06/REC-xml-stylesheet-19990629/errata makes type optional for PI's. http://www.w3.org/Style/styling-XML is resonably clear about this as well. Personally, I think it just make things more confusing to require type only in the header form and that too only for xml. (Oh and I'm using some css from Ian's tests for these testcases, I didn't want to have to attach tons of files here.)
Attached file Testcase 2
A PI testcase for completeness sake. Just to show that we appear to be doing the right thing per the errata, and that I did not change that.
Attached file Testcase 3
This is the only other case that I know of. The XMLSink currently doesn't have the bit of code over here http://lxr.mozilla.org/mozilla/source/content/html/document/src/nsHTMLContentSink.cpp#4585 So, this testcase renders differently from its html counterpart. You have to go and pick the "a" in "Use Style" to make it go green as it would have been if this were served as html. After the patch, the "a" stylesheet will be picked up as the default, as happens in the html case. Frankly, I don't know if this is "correct" per the specs. Let me know.
Attached patch v4 (obsolete) — Splinter Review
>>+ loader->AddObserver(proxy); > >Please check the returnvalue from AddObserver Done >>+ nsIDOMHTMLScriptElement* scriptElement = mScriptElements[count - 1]; >>+ if (aElement != scriptElement) { >>+ return NS_OK; >>+ } > >You can compare directly to mScriptElements[...] here. No need for the >temporary variable. Same in ScriptEvaluated Done. [BTW, now that I think about it, this check is not strictly sufficent is it? COM purists would QI to check the COM identity of the two pointers. We can ignore that since we know the implementation. Right? ] >>+static const PRUnichar kSemiCh = PRUnichar(';'); >>+static const PRUnichar kCommaCh = PRUnichar(','); >>+static const PRUnichar kEqualsCh = PRUnichar('='); >>+static const PRUnichar kLessThanCh = PRUnichar('<'); >>+static const PRUnichar kGreaterThanCh = PRUnichar('>'); > >Does declaring |static| on a global do anything? If I am not mistaken, it would make the variable "local to the translation unit". In other words, theoretically, this should make static builds less likely to break due to global variablename conflicts etc. >>+{ >>+ nsresult result = NS_OK; >>+ PRBool isAlternate = PR_FALSE; in the places further down in this function you should use aAlternate rather then isAlternate (and of course remove isAlternate) Doh ! >>+PRBool >>+nsContentSink::ScrollToRef(PRBool aReallyScroll) >>+{ >>+ PRBool didScroll = PR_FALSE; >>+ >>+ if (!mRef.IsEmpty()) { > >Please make this function earlyreturn the way the HTMLSink one did. Done. >Please stick to a single '{' pattern. Most files nowadays use That code was just cut-pasted :-) Its easy enough to fix up. Done. >>+ NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr); >>+ >>+ NS_IMETHOD_(nsrefcnt) AddRef(void); >>+ NS_IMETHOD_(nsrefcnt) Release(void); > >Use NS_DECL_ISUPPORTS_INHERITED instead. Same in the xml contentsink. Done. >>+NS_INTERFACE_MAP_BEGIN(HTMLContentSink) >>+ NS_INTERFACE_MAP_ENTRY(nsIContentSink) >>+ NS_INTERFACE_MAP_ENTRY(nsIHTMLContentSink) >>+ NS_INTERFACE_MAP_ENTRY(nsITimerCallback) >>+ NS_INTERFACE_MAP_ENTRY(nsIDocumentObserver) >>+NS_INTERFACE_MAP_END_INHERITING(nsContentSink) > >You can use NS_IMPL_ISUPPORTS_INHERITED here. Same in the XMLContentSink I actually have a slight preference for the MAP version. But ok. Done. >>+ >>+ nsresult rv = nsContentSink::Init(aDoc, aURL, aContainer, aChannel); >>+ NS_ENSURE_SUCCESS(rv, rv); >>+ >> MOZ_TIMER_DEBUGLOG(("Reset and start: nsHTMLContentSink::Init(), this=%p\n", >> this)); >> MOZ_TIMER_RESET(mWatch); >> MOZ_TIMER_START(mWatch); >> >>- if (!aDoc || !aURL || !aContainer) { >>- NS_ERROR("Null ptr!"); >>- >>- MOZ_TIMER_DEBUGLOG(("Stop: nsHTMLContentSink::Init()\n")); >>- MOZ_TIMER_STOP(mWatch); >>- >>- return NS_ERROR_NULL_POINTER; >>- } > >It might be a good idea to do the logging before calling nsContentSinke::Init >and keep the |if| (though of course change the condition to NS_FAILED(rv)). I >honestly don't know how important it is though. Peterv? Done. >> void >> HTMLContentSink::TryToScrollToRef() >> { >> if (mRef.IsEmpty()) { >> return; >> } >> >> if (mScrolledToRefAlready) { >> return; >> } >> >>- ScrollToRef(PR_TRUE); >>-} >>- >>-void >>-HTMLContentSink::ScrollToRef(PRBool aReallyScroll) > >You're moving the setting of mScrolledToRefAlready into TryToScrollToRef but >DidBuildModel calls ScrollToRef too. Do you need to add >mScrolledToRefAlready-code in there too? DidBuildModel() behavior did change there. Actually, I had concluded that this didn't matter. We cancel the notification timer a bit further up in DidBuildModel(). And the only place TryToScrollToRef() is called is from that timer's callback. So, setting mScrolledToRefAlready should really not matter beyond this point. However, its really trivial to do so, and I've tried to stay faithful to what was there earlier in most other places, so I fixed this up it up. >> nsXMLContentSink::ProcessStyleLink(nsIContent* aElement, >>- const nsString& aHref, >>- PRBool aAlternate, >>- const nsString& aTitle, >>- const nsString& aType, >>- const nsString& aMedia) >>+ const nsAString& aHref, >>+ const PRBool aAlternate, >>+ const nsAString& aTitle, >>+ const nsAString& aType, >>+ const nsAString& aMedia) > >just keep aAlternate as a |PRBool| that's what we do elsewhere and it doesn't >really make sense to use const on simple datatypes. OK. Done. >>- if (aType.EqualsIgnoreCase(kXSLType) || >>- aType.EqualsIgnoreCase(kXMLTextContentType) || >>- aType.EqualsIgnoreCase(kXMLApplicationContentType)) { >>+ NS_ConvertUTF16toUTF8 type(aType); >>+ if (type.EqualsIgnoreCase(kXSLType) || >>+ type.EqualsIgnoreCase(kXMLTextContentType) || >>+ type.EqualsIgnoreCase(kXMLApplicationContentType)) { > >Hmm.. why wasn't the conversion needed before? Becuase the aType parameter in nsXMLContentSink::ProcessStyleLink() was a |nsString| and not |nsAString|. |nsString| has an (evil) EqualsIgnoreCase(const char*) method which will do a conversion transparently. It may have been converting to ASCII which maybe I should be doing too? Hmmmm.... >>- if (aType.Equals(NS_LITERAL_STRING("text/css"))) { >>- nsCOMPtr<nsIURI> url; >>- rv = NS_NewURI(getter_AddRefs(url), aHref, nsnull, mDocumentBaseURL); >>- if (NS_FAILED(rv)) { >>- return NS_OK; // The URL is bad, move along, don't propagate the error (for now) >>- } >>- PRBool doneLoading; >>- rv = mCSSLoader->LoadStyleLink(aElement, url, aTitle, aMedia, >>- ((!aAlternate) ? mParser : nsnull), >>- doneLoading, >>- this); >>- // XXX should probably use kBlockByDefault here, no? >>- if (NS_SUCCEEDED(rv) && !doneLoading && !aAlternate && mParser) { >>- mParser->BlockParser(); >>- } >>+ // Let nsContentSink deal with css. >>+ rv = nsContentSink::ProcessStyleLink(aElement, aHref, aAlternate, >>+ aTitle, aType, aMedia); >>+ if (rv = NS_ERROR_HTMLPARSER_BLOCK) { >>+ mParser->BlockParser(); > >should be |==|. And you need to check that mParser isn't null i think. Doh! Fixed. >And the ending return should return NS_OK, not rv since otherwise a block will >be considered a failure in the caller of this function. (This is the reason why >I dislike functions endind with "return rv"). Though you need to deal with >other errorcodes then block and make sure that they return a failure. Fixed. bz : >ProcessHeaderData for the setcookie header uses ToNewUTF8String in HTML and >NS_ConvertUCS2toUTF8().get() in XML. I'd assume you would want to use the >latter... (especially since using nsCRT::free to deallocate the result of >ToNewUTF8String is wrong, iirc), whereas your patch uses the former. Fixed. BTW, what is the right way to deallocate from ToNewUTF8String()? nsMemory::Free()?
Attachment #132299 - Flags: superreview?(peterv)
Attachment #132299 - Flags: review+
> right way to deallocate from ToNewUTF8String() Yes, nsMemory::Free()
Ok, i feel more confident on the stylesheet issues now. Adding the url to the link-spec for completness sake: http://www.ietf.org/rfc/rfc2068 (section 19.6.2.4) My r=sicking still stands (still with the requirement that you get peterv to sr)
Attached patch v4.1Splinter Review
Minor update over v4. (removed a hunk from unrelated patch, killed some un-necessary #include's)
Attachment #132299 - Attachment is obsolete: true
Comment on attachment 132511 [details] [diff] [review] v4.1 This one is current. peterv, could you please have a look.
Attachment #132511 - Flags: superreview?(peterv)
Attachment #132511 - Flags: review+
Comment on attachment 132299 [details] [diff] [review] v4 stale request
Attachment #132299 - Flags: superreview?(peterv)
Comment on attachment 132511 [details] [diff] [review] v4.1 >Index: base/src/nsContentSink.cpp >=================================================================== >+ * Version: NPL 1.1/GPL 2.0/LGPL 2.1 Make this MPL/GPL/LGPL >+nsresult >+nsContentSink::Init(nsIDocument* aDoc, >+ nsIURI* aURL, >+ nsISupports* aContainer, >+ nsIChannel* aChannel) >+{ >+ NS_PRECONDITION(aDoc, "null ptr"); >+ NS_PRECONDITION(aURL, "null ptr"); >+ >+ if ((nsnull == aDoc) || (nsnull == aURL)) { if (!aDoc || !aURL) { >+ nsCOMPtr<nsIHTMLContentContainer> htmlContainer(do_QueryInterface(aDoc)); >+ if (htmlContainer) { >+ htmlContainer->GetCSSLoader(*getter_AddRefs(mCSSLoader)); >+ } >+ >+ // XXX this presumes HTTP header info is alread set in document already >+NS_IMETHODIMP >+nsContentSink::ScriptEvaluated(nsresult aResult, >+ nsIDOMHTMLScriptElement *aElement, >+ PRBool aIsInline, >+ PRBool aWasPending) >+{ >+ if (aElement != mScriptElements[count-1]) { Spaces around -. >+ return NS_OK; >+ } >+ >+ // Pop the script element stack >+ mScriptElements.RemoveObjectAt(count-1); Spaces around -. >+nsresult >+nsContentSink::ProcessHTTPHeaders(nsIChannel* aChannel) >+{ >+ while (*name) { >+ rv = httpchannel->GetResponseHeader(nsDependentCString(*name), tmp); >+ if (NS_SUCCEEDED(rv) && !tmp.IsEmpty()) { >+ nsCOMPtr<nsIAtom> key = do_GetAtom(*name); >+ ProcessHeaderData(key, NS_ConvertASCIItoUCS2(tmp)); >+ } >+ name++; >+ } >+ >+ return rv; This return seems useless, we'll only return the result of the last GetResponseHeader anyway. I'd just return NS_OK and declare rv inside the loop. And use ++name. >+nsresult >+nsContentSink::ProcessHeaderData(nsIAtom* aHeader, const nsAString& aValue, >+ nsIContent* aContent) >+{ >+ } else if (aHeader == nsHTMLAtoms::setcookie) { >+ Move the else to the next line and remove the blank line. >+ } else if (aHeader == nsHTMLAtoms::link) { Move the else to the next line. >+nsresult >+nsContentSink::ProcessLink(nsIContent* aElement, >+ const nsAString& aHref, const nsAString& aRel, >+ const nsAString& aTitle, const nsAString& aType, >+ const nsAString& aMedia) >+{ >+ // is it a stylesheet link? >+ if (linkTypes.IndexOf(NS_LITERAL_STRING("stylesheet")) != -1) { >+ PRBool isAlternate = linkTypes.IndexOf(NS_LITERAL_STRING("alternate")) != -1; >+ rv = ProcessStyleLink(aElement, aHref, isAlternate, aTitle, aType, >+ aMedia); >+ } >+ >+ return rv; I'd return NS_OK for linkTypes.IndexOf(NS_LITERAL_STRING("stylesheet")) == -1 and return the result of ProcessStyleLink at the end. >+} >+ >+nsresult >+nsContentSink::ProcessStyleLink(nsIContent* aElement, >+ const nsAString& aHref, >+ PRBool aAlternate, >+ const nsAString& aTitle, >+ const nsAString& aType, >+ const nsAString& aMedia) >+{ >+ nsresult rv = NS_OK; ... >+ nsCOMPtr<nsIURI> url; >+ rv = NS_NewURI(getter_AddRefs(url), aHref, nsnull, mDocumentBaseURL); Declare rv here. >+nsresult >+nsContentSink::RefreshIfEnabled(nsIViewManager* vm) >+{ >+ if (vm) { Return early on !vm >+ nsCOMPtr<nsIContentViewer> contentViewer; >+ nsresult rv = mDocShell->GetContentViewer(getter_AddRefs(contentViewer)); >+ if (NS_SUCCEEDED(rv) && contentViewer) { Drop rv, just check contentViewer and return early. >+ PRBool enabled; >+ contentViewer->GetEnableRendering(&enabled); >+ if (enabled) { >+ vm->EnableRefresh(NS_VMREFRESH_IMMEDIATE); >+ } >+ } >+ } >+ return NS_OK; >+} >Index: base/src/nsContentSink.h >=================================================================== >+ * Version: NPL 1.1/GPL 2.0/LGPL 2.1 MPL/GPL/LGPL >Index: html/document/src/nsHTMLContentSink.cpp >=================================================================== >+class HTMLContentSink : public nsContentSink, >+ public nsIHTMLContentSink, > public nsITimerCallback, >- public nsICSSLoaderObserver, > #ifdef DEBUG > public nsIDebugDumpContent, > #endif > public nsIDocumentObserver > { >- nsresult RefreshIfEnabled(nsIViewManager* vm); >+ virtual nsresult RefreshIfEnabled(nsIViewManager* vm); This doesn't need to be virtual, does it? >- PRBool PreEvaluateScript(); >- void PostEvaluateScript(); >+ virtual void PreEvaluateScript(); >+ virtual void PostEvaluateScript(); This doesn't need to be virtual, does it? > nsresult > HTMLContentSink::RefreshIfEnabled(nsIViewManager* vm) > { > NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE); > >+ return nsContentSink::RefreshIfEnabled(vm); I wonder if we could just move the mDocShell check into nsContentSink::RefreshIfEnabled and remove this. This looks good, though I think we might want to freshen up at least ProcessLinkHeader at some time in the future. I'm not worried about the changes in link-handling for XML, I think you've actually fixed bugs by unifying the implementations.
Attachment #132511 - Flags: superreview?(peterv) → superreview+
>Make this MPL/GPL/LGPL Just a quick question about this. This patch is primarily moving around code. The code going into the new files came from files that are currently NPL/GPL/LGPL. Am I allowed to relicence this code when I move it to a new file?
In this case yes, since Netscape granted permission to relicense its NPL code to MPL.
Actually, since it's already triple-licensed we might want to keep it as is and let the relicensing effort (does thats still exist?) figure it out.
The relicensing effort still exists, but don't wait for it. Help it out, relicense from N => M now, and with the latest tri-license versions all around. The Mozilla Foundation has permission to do this, and we could use your help, to reduce the global relicensing effort's "tail end" work. /be
>>+ virtual void PreEvaluateScript(); >>+ virtual void PostEvaluateScript(); > >This doesn't need to be virtual, does it? These do need to be virtual. They are overridding the nsContentSink ones. I put a comment there to that effect. >> nsresult >> HTMLContentSink::RefreshIfEnabled(nsIViewManager* vm) >> { >> NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE); >> >>+ return nsContentSink::RefreshIfEnabled(vm); > >I wonder if we could just move the mDocShell check into >nsContentSink::RefreshIfEnabled and remove this. That made total sense. I went ahead and made that change. I've changed the license to MPL/GPL/LGPL. All the other stuff you raised has been fixed.
Attached patch Final patchSplinter Review
mZ dropped by about 6K on Linux and under 4K on Windows. However, this seems to have regressed Tp by ~1%. I tried backing out the ScrollToRef() changes from the htmlsink. It didn't help. I tried backing out all the <script> stuff. That seems to have not helped either. So I've checked the whole thing back in again for now. I'm puzzled. Other than these two bits, nothing much should have changed for html. And Tp should only really be affected by what happens in the htmlsink. (Right?) comet seems to be showing a minor increase in Ts too (~0.5%) . But luna doesn't agree, it shows no change at all. So, I don't think this is that serious. The Tp thing is the bigger problem. Does anyone have any idea about why this patch might have affected Tp? I don't have a clue. Should I back the whole thing out?
> Should I back the whole thing out? No, let's not do that.. If we could get access to way to run the Tp tests reasonably, it would be possible to start with a pre-patch build and then slowly drop in the patch a bit at a time till we found the problem... Doing this with tinderbox via cvs seems like overkill. Would it be possible to coopt one of the Tp tinderboxen for a day or two for this?
dbaron and bryner are on more intimate terms than I am with the tinderboxen, but sure. We have other machines moved into the Mozilla Foundation HQ but not yet on the net (we're waiting an inordinate amount of time for Pac Bell to install a T1). Any of those machines could be brought home by a volunteer in the area and used temporarily to find out what regressed Tp here. /be
I did a bit of testing on btek yesterday. Most if not all of the performance loss was related to the nsHTMLContentSink changes, not surprisingly. Making only the changes to make nsHTMLContentSink inherit from nsContentSink didn't seem to cause any loss, but only eliminating the shadowing member variables from nsHTMLContentSink so it used the nsCOMPtr/nsCOMArray member variables from nsContentSink caused about half the performance loss. At that point I gave up investigating.
Thanks a lot for the testing! (I've been looking into setting up the pageload tests locally, but it sure looked like that would turn into a minor "project" by itself :-)) I just saw your comments and numbers on tinderbox. It's very surprising to me that using the members from nsContentSink would have so much of an effect. That is the last thing that I would have suspected. So, what does this really indicate? It doesnt look like the nsCOMArray of scriptelements is accessed that often. So, nsCOMPtr's are for some reason much slower to use than the corresponding raw ptr in this case? Is should really not be the case right? Should I try going back to using raw pointers and explicit addref/release for the three members that are accessed most often? (mParser/ mDocument/ mNodeInfoManager)
My guess is that it's using nsCOMPtrs/nsCOMArrays that slows things down (though at least nsCOMPtr really shouldn't). Try using the same datatypes as are in nsHTMLContentSink now and see if that helps. Other then that I can only think of that the order of the members would matter, though i have no idea why it should. You can test this by moving the members that were moved to the baseclass to be first in the class.
nsContentSink.cpp cause bug 226700. Could someone take a look at that bug? Thanks!
Marking fixed since the patch landed a long time back. For the last couple of months, I've not been able to make time to deal with the pref regression from this patch (or any other mozilla stuff). I think I will be able to do so during 1.7a. I've filed bug 229163 for the regression.
Status: ASSIGNED → RESOLVED
Closed: 21 years ago
Resolution: --- → FIXED
Component: DOM → DOM: Core & HTML
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: