/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Mozilla Communicator client code. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Chris Waterson * David Hyatt * Brendan Eich * Mark Hammond * * Alternatively, the contents of this file may be used under the terms of * either of the GNU General Public License Version 2 or later (the "GPL"), * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ /* * An implementation for a Gecko-style content sink that knows how * to build a content model (the "prototype" document) from XUL. * * For more information on XUL, * see http://developer.mozilla.org/en/docs/XUL */ #include "nsXULContentSink.h" #include "nsCOMPtr.h" #include "nsForwardReference.h" #include "nsIContentSink.h" #include "nsIDOMDocument.h" #include "nsIDOMEventListener.h" #include "nsIDOMHTMLFormElement.h" #include "nsIDOMXULDocument.h" #include "nsIDocument.h" #include "nsIFormControl.h" #include "nsHTMLStyleSheet.h" #include "nsINameSpaceManager.h" #include "nsINodeInfo.h" #include "nsIParser.h" #include "nsIPresShell.h" #include "nsIScriptContext.h" #include "nsIScriptRuntime.h" #include "nsIScriptGlobalObject.h" #include "nsIServiceManager.h" #include "nsIURL.h" #include "nsIViewManager.h" #include "nsIXULDocument.h" #include "nsIScriptSecurityManager.h" #include "nsLayoutCID.h" #include "nsNetUtil.h" #include "nsRDFCID.h" #include "nsParserUtils.h" #include "nsIMIMEHeaderParam.h" #include "nsXPIDLString.h" #include "nsReadableUtils.h" #include "nsXULElement.h" #include "prlog.h" #include "prmem.h" #include "jscntxt.h" // for JSVERSION_HAS_XML #include "nsCRT.h" #include "nsXULPrototypeDocument.h" // XXXbe temporary #include "nsICSSLoader.h" #include "nsUnicharUtils.h" #include "nsGkAtoms.h" #include "nsContentUtils.h" #include "nsAttrName.h" #include "nsXMLContentSink.h" #include "nsIConsoleService.h" #include "nsIScriptError.h" #ifdef PR_LOGGING static PRLogModuleInfo* gLog; #endif //---------------------------------------------------------------------- XULContentSinkImpl::ContextStack::ContextStack() : mTop(nsnull), mDepth(0) { } XULContentSinkImpl::ContextStack::~ContextStack() { while (mTop) { Entry* doomed = mTop; mTop = mTop->mNext; delete doomed; } } nsresult XULContentSinkImpl::ContextStack::Push(nsXULPrototypeNode* aNode, State aState) { Entry* entry = new Entry; if (! entry) return NS_ERROR_OUT_OF_MEMORY; entry->mNode = aNode; entry->mState = aState; entry->mNext = mTop; mTop = entry; ++mDepth; return NS_OK; } nsresult XULContentSinkImpl::ContextStack::Pop(State* aState) { if (mDepth == 0) return NS_ERROR_UNEXPECTED; Entry* entry = mTop; mTop = mTop->mNext; --mDepth; *aState = entry->mState; delete entry; return NS_OK; } nsresult XULContentSinkImpl::ContextStack::GetTopNode(nsXULPrototypeNode** aNode) { if (mDepth == 0) return NS_ERROR_UNEXPECTED; *aNode = mTop->mNode; return NS_OK; } nsresult XULContentSinkImpl::ContextStack::GetTopChildren(nsVoidArray** aChildren) { if (mDepth == 0) return NS_ERROR_UNEXPECTED; *aChildren = &(mTop->mChildren); return NS_OK; } nsresult XULContentSinkImpl::ContextStack::GetTopNodeScriptType(PRUint32 *aScriptType) { if (mDepth == 0) return NS_ERROR_UNEXPECTED; // This would be much simpler if nsXULPrototypeNode itself // stored the language ID - but text elements don't need it! nsresult rv = NS_OK; nsXULPrototypeNode* node; rv = GetTopNode(&node); if (NS_FAILED(rv)) return rv; switch (node->mType) { case nsXULPrototypeNode::eType_Element: { nsXULPrototypeElement *parent = \ reinterpret_cast(node); *aScriptType = parent->mScriptTypeID; break; } case nsXULPrototypeNode::eType_Script: { nsXULPrototypeScript *parent = \ reinterpret_cast(node); *aScriptType = parent->mScriptObject.mLangID; break; } default: { NS_WARNING("Unexpected parent node type"); rv = NS_ERROR_UNEXPECTED; } } return rv; } void XULContentSinkImpl::ContextStack::Clear() { Entry *cur = mTop; while (cur) { // Release all children (with their descendants) that haven't been added to // their parents. for (PRInt32 i = cur->mChildren.Count() - 1; i >= 0; --i) { nsXULPrototypeNode* child = reinterpret_cast(cur->mChildren.ElementAt(i)); child->ReleaseSubtree(); } // Release the root element (and its descendants). Entry *next = cur->mNext; if (!next) cur->mNode->ReleaseSubtree(); delete cur; cur = next; } mTop = nsnull; mDepth = 0; } //---------------------------------------------------------------------- XULContentSinkImpl::XULContentSinkImpl() : mText(nsnull), mTextLength(0), mTextSize(0), mConstrainSize(PR_TRUE), mState(eInProlog), mParser(nsnull) { #ifdef PR_LOGGING if (! gLog) gLog = PR_NewLogModule("nsXULContentSink"); #endif } XULContentSinkImpl::~XULContentSinkImpl() { NS_IF_RELEASE(mParser); // XXX should've been released by now, unless error. // The context stack _should_ be empty, unless something has gone wrong. NS_ASSERTION(mContextStack.Depth() == 0, "Context stack not empty?"); mContextStack.Clear(); PR_FREEIF(mText); } //---------------------------------------------------------------------- // nsISupports interface NS_IMPL_ISUPPORTS3(XULContentSinkImpl, nsIXMLContentSink, nsIContentSink, nsIExpatSink) //---------------------------------------------------------------------- // nsIContentSink interface NS_IMETHODIMP XULContentSinkImpl::WillBuildModel(void) { #if FIXME if (! mParentContentSink) { // If we're _not_ an overlay, then notify the document that // the load is beginning. mDocument->BeginLoad(); } #endif return NS_OK; } NS_IMETHODIMP XULContentSinkImpl::DidBuildModel(void) { nsCOMPtr doc = do_QueryReferent(mDocument); if (doc) { doc->EndLoad(); mDocument = nsnull; } // Drop our reference to the parser to get rid of a circular // reference. NS_IF_RELEASE(mParser); return NS_OK; } NS_IMETHODIMP XULContentSinkImpl::WillInterrupt(void) { // XXX Notify the docshell, if necessary return NS_OK; } NS_IMETHODIMP XULContentSinkImpl::WillResume(void) { // XXX Notify the docshell, if necessary return NS_OK; } NS_IMETHODIMP XULContentSinkImpl::SetParser(nsIParser* aParser) { NS_IF_RELEASE(mParser); mParser = aParser; NS_IF_ADDREF(mParser); return NS_OK; } NS_IMETHODIMP XULContentSinkImpl::SetDocumentCharset(nsACString& aCharset) { nsCOMPtr doc = do_QueryReferent(mDocument); if (doc) { doc->SetDocumentCharacterSet(aCharset); } return NS_OK; } nsISupports * XULContentSinkImpl::GetTarget() { nsCOMPtr doc = do_QueryReferent(mDocument); return doc; } //---------------------------------------------------------------------- nsresult XULContentSinkImpl::Init(nsIDocument* aDocument, nsXULPrototypeDocument* aPrototype) { NS_PRECONDITION(aDocument != nsnull, "null ptr"); if (! aDocument) return NS_ERROR_NULL_POINTER; nsresult rv; mDocument = do_GetWeakReference(aDocument); mPrototype = aPrototype; mDocumentURL = mPrototype->GetURI(); // XXX this presumes HTTP header info is already set in document // XXX if it isn't we need to set it here... // XXXbz not like GetHeaderData on the proto doc _does_ anything.... nsAutoString preferredStyle; rv = mPrototype->GetHeaderData(nsGkAtoms::headerDefaultStyle, preferredStyle); if (NS_FAILED(rv)) return rv; if (!preferredStyle.IsEmpty()) { aDocument->SetHeaderData(nsGkAtoms::headerDefaultStyle, preferredStyle); } // Set the right preferred style on the document's CSSLoader. aDocument->CSSLoader()->SetPreferredSheet(preferredStyle); mNodeInfoManager = aPrototype->GetNodeInfoManager(); if (! mNodeInfoManager) return NS_ERROR_UNEXPECTED; mState = eInProlog; return NS_OK; } //---------------------------------------------------------------------- // // Text buffering // PRBool XULContentSinkImpl::IsDataInBuffer(PRUnichar* buffer, PRInt32 length) { for (PRInt32 i = 0; i < length; ++i) { if (buffer[i] == ' ' || buffer[i] == '\t' || buffer[i] == '\n' || buffer[i] == '\r') continue; return PR_TRUE; } return PR_FALSE; } nsresult XULContentSinkImpl::FlushText(PRBool aCreateTextNode) { nsresult rv; do { // Don't do anything if there's no text to create a node from, or // if they've told us not to create a text node if (! mTextLength) break; if (! aCreateTextNode) break; nsXULPrototypeNode* node; rv = mContextStack.GetTopNode(&node); if (NS_FAILED(rv)) return rv; PRBool stripWhitespace = PR_FALSE; if (node->mType == nsXULPrototypeNode::eType_Element) { nsINodeInfo *nodeInfo = static_cast(node)->mNodeInfo; if (nodeInfo->NamespaceEquals(kNameSpaceID_XUL)) stripWhitespace = !nodeInfo->Equals(nsGkAtoms::label) && !nodeInfo->Equals(nsGkAtoms::description); } // Don't bother if there's nothing but whitespace. if (stripWhitespace && ! IsDataInBuffer(mText, mTextLength)) break; // Don't bother if we're not in XUL document body if (mState != eInDocumentElement || mContextStack.Depth() == 0) break; nsXULPrototypeText* text = new nsXULPrototypeText(); if (! text) return NS_ERROR_OUT_OF_MEMORY; text->mValue.Assign(mText, mTextLength); if (stripWhitespace) text->mValue.Trim(" \t\n\r"); // hook it up nsVoidArray* children; rv = mContextStack.GetTopChildren(&children); if (NS_FAILED(rv)) return rv; // transfer ownership of 'text' to the children array children->AppendElement(text); } while (0); // Reset our text buffer mTextLength = 0; return NS_OK; } //---------------------------------------------------------------------- nsresult XULContentSinkImpl::NormalizeAttributeString(const PRUnichar *aExpatName, nsAttrName &aName) { PRInt32 nameSpaceID; nsCOMPtr prefix, localName; nsContentUtils::SplitExpatName(aExpatName, getter_AddRefs(prefix), getter_AddRefs(localName), &nameSpaceID); if (nameSpaceID == kNameSpaceID_None) { aName.SetTo(localName); return NS_OK; } nsCOMPtr ni; nsresult rv = mNodeInfoManager->GetNodeInfo(localName, prefix, nameSpaceID, getter_AddRefs(ni)); NS_ENSURE_SUCCESS(rv, rv); aName.SetTo(ni); return NS_OK; } nsresult XULContentSinkImpl::CreateElement(nsINodeInfo *aNodeInfo, nsXULPrototypeElement** aResult) { nsXULPrototypeElement* element = new nsXULPrototypeElement(); if (! element) return NS_ERROR_OUT_OF_MEMORY; element->mNodeInfo = aNodeInfo; *aResult = element; return NS_OK; } /**** BEGIN NEW APIs ****/ NS_IMETHODIMP XULContentSinkImpl::HandleStartElement(const PRUnichar *aName, const PRUnichar **aAtts, PRUint32 aAttsCount, PRInt32 aIndex, PRUint32 aLineNumber) { // XXX Hopefully the parser will flag this before we get here. If // we're in the epilog, there should be no new elements NS_PRECONDITION(mState != eInEpilog, "tag in XUL doc epilog"); NS_PRECONDITION(aIndex >= -1, "Bogus aIndex"); NS_PRECONDITION(aAttsCount % 2 == 0, "incorrect aAttsCount"); // Adjust aAttsCount so it's the actual number of attributes aAttsCount /= 2; if (mState == eInEpilog) return NS_ERROR_UNEXPECTED; if (mState != eInScript) { FlushText(); } PRInt32 nameSpaceID; nsCOMPtr prefix, localName; nsContentUtils::SplitExpatName(aName, getter_AddRefs(prefix), getter_AddRefs(localName), &nameSpaceID); nsCOMPtr nodeInfo; nsresult rv = mNodeInfoManager->GetNodeInfo(localName, prefix, nameSpaceID, getter_AddRefs(nodeInfo)); NS_ENSURE_SUCCESS(rv, rv); switch (mState) { case eInProlog: // We're the root document element rv = OpenRoot(aAtts, aAttsCount, nodeInfo); break; case eInDocumentElement: rv = OpenTag(aAtts, aAttsCount, aLineNumber, nodeInfo); break; case eInEpilog: case eInScript: PR_LOG(gLog, PR_LOG_WARNING, ("xul: warning: unexpected tags in epilog at line %d", aLineNumber)); rv = NS_ERROR_UNEXPECTED; // XXX break; } // Set the ID attribute atom on the node info object for this node if (aIndex != -1 && NS_SUCCEEDED(rv)) { nsCOMPtr IDAttr = do_GetAtom(aAtts[aIndex]); if (IDAttr) { nodeInfo->SetIDAttributeAtom(IDAttr); } } return rv; } NS_IMETHODIMP XULContentSinkImpl::HandleEndElement(const PRUnichar *aName) { // Never EVER return anything but NS_OK or // NS_ERROR_HTMLPARSER_BLOCK from this method. Doing so will blow // the parser's little mind all over the planet. nsresult rv; nsXULPrototypeNode* node; rv = mContextStack.GetTopNode(&node); if (NS_FAILED(rv)) { return NS_OK; } switch (node->mType) { case nsXULPrototypeNode::eType_Element: { // Flush any text _now_, so that we'll get text nodes created // before popping the stack. FlushText(); // Pop the context stack and do prototype hookup. nsVoidArray* children; rv = mContextStack.GetTopChildren(&children); if (NS_FAILED(rv)) return rv; nsXULPrototypeElement* element = reinterpret_cast(node); PRInt32 count = children->Count(); if (count) { element->mChildren = new nsXULPrototypeNode*[count]; if (! element->mChildren) return NS_ERROR_OUT_OF_MEMORY; for (PRInt32 i = count - 1; i >= 0; --i) element->mChildren[i] = reinterpret_cast(children->ElementAt(i)); element->mNumChildren = count; } } break; case nsXULPrototypeNode::eType_Script: { nsXULPrototypeScript* script = static_cast(node); // If given a src= attribute, we must ignore script tag content. if (! script->mSrcURI && ! script->mScriptObject.mObject) { nsCOMPtr doc = do_QueryReferent(mDocument); script->mOutOfLine = PR_FALSE; if (doc) script->Compile(mText, mTextLength, mDocumentURL, script->mLineNo, doc, mPrototype); } FlushText(PR_FALSE); } break; default: NS_ERROR("didn't expect that"); break; } rv = mContextStack.Pop(&mState); NS_ASSERTION(NS_SUCCEEDED(rv), "context stack corrupted"); if (NS_FAILED(rv)) return rv; if (mContextStack.Depth() == 0) { // The root element should -always- be an element, because // it'll have been created via XULContentSinkImpl::OpenRoot(). NS_ASSERTION(node->mType == nsXULPrototypeNode::eType_Element, "root is not an element"); if (node->mType != nsXULPrototypeNode::eType_Element) return NS_ERROR_UNEXPECTED; // Now that we're done parsing, set the prototype document's // root element. This transfers ownership of the prototype // element tree to the prototype document. nsXULPrototypeElement* element = static_cast(node); mPrototype->SetRootElement(element); mState = eInEpilog; } return NS_OK; } NS_IMETHODIMP XULContentSinkImpl::HandleComment(const PRUnichar *aName) { FlushText(); return NS_OK; } NS_IMETHODIMP XULContentSinkImpl::HandleCDataSection(const PRUnichar *aData, PRUint32 aLength) { FlushText(); return AddText(aData, aLength); } NS_IMETHODIMP XULContentSinkImpl::HandleDoctypeDecl(const nsAString & aSubset, const nsAString & aName, const nsAString & aSystemId, const nsAString & aPublicId, nsISupports* aCatalogData) { return NS_OK; } NS_IMETHODIMP XULContentSinkImpl::HandleCharacterData(const PRUnichar *aData, PRUint32 aLength) { if (aData && mState != eInProlog && mState != eInEpilog) { return AddText(aData, aLength); } return NS_OK; } NS_IMETHODIMP XULContentSinkImpl::HandleProcessingInstruction(const PRUnichar *aTarget, const PRUnichar *aData) { FlushText(); const nsDependentString target(aTarget); const nsDependentString data(aData); // Note: the created nsXULPrototypePI has mRefCnt == 1 nsXULPrototypePI* pi = new nsXULPrototypePI(); if (!pi) return NS_ERROR_OUT_OF_MEMORY; pi->mTarget = target; pi->mData = data; if (mState == eInProlog) { // Note: passing in already addrefed pi return mPrototype->AddProcessingInstruction(pi); } nsresult rv; nsVoidArray* children; rv = mContextStack.GetTopChildren(&children); if (NS_FAILED(rv)) { pi->Release(); return rv; } if (!children->AppendElement(pi)) { pi->Release(); return NS_ERROR_OUT_OF_MEMORY; } return NS_OK; } NS_IMETHODIMP XULContentSinkImpl::HandleXMLDeclaration(const PRUnichar *aVersion, const PRUnichar *aEncoding, PRInt32 aStandalone) { return NS_OK; } NS_IMETHODIMP XULContentSinkImpl::ReportError(const PRUnichar* aErrorText, const PRUnichar* aSourceText, nsIScriptError *aError, PRBool *_retval) { NS_PRECONDITION(aError && aSourceText && aErrorText, "Check arguments!!!"); // The expat driver should report the error. *_retval = PR_TRUE; nsresult rv = NS_OK; // make sure to empty the context stack so that // could become the root element. mContextStack.Clear(); mState = eInProlog; // Clear any buffered-up text we have. It's enough to set the length to 0. // The buffer itself is allocated when we're created and deleted in our // destructor, so don't mess with it. mTextLength = 0; nsCOMPtr doc = do_QueryReferent(mDocument); if (doc && !doc->OnDocumentParserError()) { // The overlay was broken. Don't add a messy element to the master doc. return NS_OK; } const PRUnichar* noAtts[] = { 0, 0 }; NS_NAMED_LITERAL_STRING(errorNs, "http://www.mozilla.org/newlayout/xml/parsererror.xml"); nsAutoString parsererror(errorNs); parsererror.Append((PRUnichar)0xFFFF); parsererror.AppendLiteral("parsererror"); rv = HandleStartElement(parsererror.get(), noAtts, 0, -1, 0); NS_ENSURE_SUCCESS(rv,rv); rv = HandleCharacterData(aErrorText, nsCRT::strlen(aErrorText)); NS_ENSURE_SUCCESS(rv,rv); nsAutoString sourcetext(errorNs); sourcetext.Append((PRUnichar)0xFFFF); sourcetext.AppendLiteral("sourcetext"); rv = HandleStartElement(sourcetext.get(), noAtts, 0, -1, 0); NS_ENSURE_SUCCESS(rv,rv); rv = HandleCharacterData(aSourceText, nsCRT::strlen(aSourceText)); NS_ENSURE_SUCCESS(rv,rv); rv = HandleEndElement(sourcetext.get()); NS_ENSURE_SUCCESS(rv,rv); rv = HandleEndElement(parsererror.get()); NS_ENSURE_SUCCESS(rv,rv); return rv; } nsresult XULContentSinkImpl::SetElementScriptType(nsXULPrototypeElement* element, const PRUnichar** aAttributes, const PRUint32 aAttrLen) { // First check if the attributes specify an explicit script type. nsresult rv = NS_OK; PRUint32 i; PRBool found = PR_FALSE; for (i=0;i runtime; rv = NS_GetScriptRuntime(value, getter_AddRefs(runtime)); if (NS_SUCCEEDED(rv)) element->mScriptTypeID = runtime->GetScriptTypeID(); else { // probably just a bad language name (typo, etc) NS_WARNING("Failed to load the node's script language!"); // Leave the default language as unknown - we don't want js // trying to execute this stuff. NS_ASSERTION(element->mScriptTypeID == nsIProgrammingLanguage::UNKNOWN, "Default script type should be unknown"); } found = PR_TRUE; break; } } } // If not specified, look at the context stack and use the element // there. if (!found) { if (mContextStack.Depth() == 0) { // This is the root element - default to JS element->mScriptTypeID = nsIProgrammingLanguage::JAVASCRIPT; } else { // Ask the top-node for its script type (which has already // had this function called for it - so no need to recurse // until we find it) PRUint32 scriptId = 0; rv = mContextStack.GetTopNodeScriptType(&scriptId); element->mScriptTypeID = scriptId; } } return rv; } nsresult XULContentSinkImpl::OpenRoot(const PRUnichar** aAttributes, const PRUint32 aAttrLen, nsINodeInfo *aNodeInfo) { NS_ASSERTION(mState == eInProlog, "how'd we get here?"); if (mState != eInProlog) return NS_ERROR_UNEXPECTED; nsresult rv; if (aNodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_XHTML) || aNodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_XUL)) { PR_LOG(gLog, PR_LOG_ERROR, ("xul: script tag not allowed as root content element")); return NS_ERROR_UNEXPECTED; } // Create the element nsXULPrototypeElement* element; rv = CreateElement(aNodeInfo, &element); if (NS_FAILED(rv)) { #ifdef PR_LOGGING if (PR_LOG_TEST(gLog, PR_LOG_ERROR)) { nsAutoString anodeC; aNodeInfo->GetName(anodeC); PR_LOG(gLog, PR_LOG_ERROR, ("xul: unable to create element '%s' at line %d", NS_ConvertUTF16toUTF8(anodeC).get(), -1)); // XXX pass in line number } #endif return rv; } // Set the correct script-type for the element. rv = SetElementScriptType(element, aAttributes, aAttrLen); if (NS_FAILED(rv)) return rv; // Push the element onto the context stack, so that child // containers will hook up to us as their parent. rv = mContextStack.Push(element, mState); if (NS_FAILED(rv)) { element->Release(); return rv; } // Add the attributes rv = AddAttributes(aAttributes, aAttrLen, element); if (NS_FAILED(rv)) return rv; mState = eInDocumentElement; return NS_OK; } nsresult XULContentSinkImpl::OpenTag(const PRUnichar** aAttributes, const PRUint32 aAttrLen, const PRUint32 aLineNumber, nsINodeInfo *aNodeInfo) { nsresult rv; // Create the element nsXULPrototypeElement* element; rv = CreateElement(aNodeInfo, &element); if (NS_FAILED(rv)) { #ifdef PR_LOGGING if (PR_LOG_TEST(gLog, PR_LOG_ERROR)) { nsAutoString anodeC; aNodeInfo->GetName(anodeC); PR_LOG(gLog, PR_LOG_ERROR, ("xul: unable to create element '%s' at line %d", NS_ConvertUTF16toUTF8(anodeC).get(), aLineNumber)); } #endif return rv; } // Link this element to its parent. nsVoidArray* children; rv = mContextStack.GetTopChildren(&children); if (NS_FAILED(rv)) { delete element; return rv; } // Add the attributes rv = AddAttributes(aAttributes, aAttrLen, element); if (NS_FAILED(rv)) return rv; children->AppendElement(element); if (aNodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_XHTML) || aNodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_XUL)) { // Do scripty things now. Set a script language for the element, // even though it is ignored (the nsPrototypeScriptElement // has its own script-type). element->mScriptTypeID = nsIProgrammingLanguage::JAVASCRIPT; rv = OpenScript(aAttributes, aLineNumber); NS_ENSURE_SUCCESS(rv, rv); NS_ASSERTION(mState == eInScript || mState == eInDocumentElement, "Unexpected state"); if (mState == eInScript) { // OpenScript has pushed the nsPrototypeScriptElement onto the // stack, so we're done. return NS_OK; } } // Set the correct script-type for the element. rv = SetElementScriptType(element, aAttributes, aAttrLen); if (NS_FAILED(rv)) return rv; // Push the element onto the context stack, so that child // containers will hook up to us as their parent. rv = mContextStack.Push(element, mState); if (NS_FAILED(rv)) return rv; mState = eInDocumentElement; return NS_OK; } nsresult XULContentSinkImpl::OpenScript(const PRUnichar** aAttributes, const PRUint32 aLineNumber) { PRUint32 langID; nsresult rv = mContextStack.GetTopNodeScriptType(&langID); if (NS_FAILED(rv)) return rv; PRUint32 version = 0; // Look for SRC attribute and look for a LANGUAGE attribute nsAutoString src; while (*aAttributes) { const nsDependentString key(aAttributes[0]); if (key.EqualsLiteral("src")) { src.Assign(aAttributes[1]); } else if (key.EqualsLiteral("type")) { nsCOMPtr mimeHdrParser = do_GetService("@mozilla.org/network/mime-hdrparam;1"); NS_ENSURE_TRUE(mimeHdrParser, NS_ERROR_FAILURE); NS_ConvertUTF16toUTF8 typeAndParams(aAttributes[1]); nsAutoString mimeType; rv = mimeHdrParser->GetParameter(typeAndParams, nsnull, EmptyCString(), PR_FALSE, nsnull, mimeType); if (NS_FAILED(rv)) { if (rv == NS_ERROR_INVALID_ARG) { // Might as well bail out now instead of setting langID to // nsIProgrammingLanguage::UNKNOWN and bailing out later. return NS_OK; } // We do want the warning here NS_ENSURE_SUCCESS(rv, rv); } // Javascript keeps the fast path, optimized for most-likely type // Table ordered from most to least likely JS MIME types. For .xul // files that we host, the likeliest type is application/x-javascript. // See bug 62485, feel free to add