1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/content/xul/document/src/nsXULContentSink.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1101 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 1.5 +/* vim: set ts=8 sts=4 et sw=4 tw=80: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +/* 1.11 + * An implementation for a Gecko-style content sink that knows how 1.12 + * to build a content model (the "prototype" document) from XUL. 1.13 + * 1.14 + * For more information on XUL, 1.15 + * see http://developer.mozilla.org/en/docs/XUL 1.16 + */ 1.17 + 1.18 +#include "nsXULContentSink.h" 1.19 + 1.20 +#include "jsfriendapi.h" 1.21 + 1.22 +#include "nsCOMPtr.h" 1.23 +#include "nsForwardReference.h" 1.24 +#include "nsHTMLStyleSheet.h" 1.25 +#include "nsIContentSink.h" 1.26 +#include "nsIDocument.h" 1.27 +#include "nsIDOMEventListener.h" 1.28 +#include "nsIDOMHTMLFormElement.h" 1.29 +#include "nsIDOMXULDocument.h" 1.30 +#include "nsIFormControl.h" 1.31 +#include "nsINodeInfo.h" 1.32 +#include "nsIScriptContext.h" 1.33 +#include "nsIScriptGlobalObject.h" 1.34 +#include "nsIServiceManager.h" 1.35 +#include "nsIURL.h" 1.36 +#include "nsNameSpaceManager.h" 1.37 +#include "nsParserBase.h" 1.38 +#include "nsViewManager.h" 1.39 +#include "nsIXULDocument.h" 1.40 +#include "nsIScriptSecurityManager.h" 1.41 +#include "nsLayoutCID.h" 1.42 +#include "nsNetUtil.h" 1.43 +#include "nsRDFCID.h" 1.44 +#include "nsXPIDLString.h" 1.45 +#include "nsReadableUtils.h" 1.46 +#include "nsXULElement.h" 1.47 +#include "prlog.h" 1.48 +#include "prmem.h" 1.49 +#include "nsCRT.h" 1.50 + 1.51 +#include "nsXULPrototypeDocument.h" // XXXbe temporary 1.52 +#include "mozilla/css/Loader.h" 1.53 + 1.54 +#include "nsUnicharUtils.h" 1.55 +#include "nsGkAtoms.h" 1.56 +#include "nsContentUtils.h" 1.57 +#include "nsAttrName.h" 1.58 +#include "nsXMLContentSink.h" 1.59 +#include "nsIConsoleService.h" 1.60 +#include "nsIScriptError.h" 1.61 +#include "nsContentTypeParser.h" 1.62 + 1.63 +#ifdef PR_LOGGING 1.64 +static PRLogModuleInfo* gContentSinkLog; 1.65 +#endif 1.66 + 1.67 +//---------------------------------------------------------------------- 1.68 + 1.69 +XULContentSinkImpl::ContextStack::ContextStack() 1.70 + : mTop(nullptr), mDepth(0) 1.71 +{ 1.72 +} 1.73 + 1.74 +XULContentSinkImpl::ContextStack::~ContextStack() 1.75 +{ 1.76 + while (mTop) { 1.77 + Entry* doomed = mTop; 1.78 + mTop = mTop->mNext; 1.79 + delete doomed; 1.80 + } 1.81 +} 1.82 + 1.83 +nsresult 1.84 +XULContentSinkImpl::ContextStack::Push(nsXULPrototypeNode* aNode, State aState) 1.85 +{ 1.86 + Entry* entry = new Entry; 1.87 + if (! entry) 1.88 + return NS_ERROR_OUT_OF_MEMORY; 1.89 + 1.90 + entry->mNode = aNode; 1.91 + entry->mState = aState; 1.92 + entry->mNext = mTop; 1.93 + mTop = entry; 1.94 + 1.95 + ++mDepth; 1.96 + return NS_OK; 1.97 +} 1.98 + 1.99 +nsresult 1.100 +XULContentSinkImpl::ContextStack::Pop(State* aState) 1.101 +{ 1.102 + if (mDepth == 0) 1.103 + return NS_ERROR_UNEXPECTED; 1.104 + 1.105 + Entry* entry = mTop; 1.106 + mTop = mTop->mNext; 1.107 + --mDepth; 1.108 + 1.109 + *aState = entry->mState; 1.110 + delete entry; 1.111 + 1.112 + return NS_OK; 1.113 +} 1.114 + 1.115 + 1.116 +nsresult 1.117 +XULContentSinkImpl::ContextStack::GetTopNode(nsRefPtr<nsXULPrototypeNode>& aNode) 1.118 +{ 1.119 + if (mDepth == 0) 1.120 + return NS_ERROR_UNEXPECTED; 1.121 + 1.122 + aNode = mTop->mNode; 1.123 + return NS_OK; 1.124 +} 1.125 + 1.126 + 1.127 +nsresult 1.128 +XULContentSinkImpl::ContextStack::GetTopChildren(nsPrototypeArray** aChildren) 1.129 +{ 1.130 + if (mDepth == 0) 1.131 + return NS_ERROR_UNEXPECTED; 1.132 + 1.133 + *aChildren = &(mTop->mChildren); 1.134 + return NS_OK; 1.135 +} 1.136 + 1.137 +void 1.138 +XULContentSinkImpl::ContextStack::Clear() 1.139 +{ 1.140 + Entry *cur = mTop; 1.141 + while (cur) { 1.142 + // Release the root element (and its descendants). 1.143 + Entry *next = cur->mNext; 1.144 + delete cur; 1.145 + cur = next; 1.146 + } 1.147 + 1.148 + mTop = nullptr; 1.149 + mDepth = 0; 1.150 +} 1.151 + 1.152 +void 1.153 +XULContentSinkImpl::ContextStack::Traverse(nsCycleCollectionTraversalCallback& aCb) 1.154 +{ 1.155 + nsCycleCollectionTraversalCallback& cb = aCb; 1.156 + for (ContextStack::Entry* tmp = mTop; tmp; tmp = tmp->mNext) { 1.157 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNode) 1.158 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChildren) 1.159 + } 1.160 +} 1.161 + 1.162 +//---------------------------------------------------------------------- 1.163 + 1.164 + 1.165 +XULContentSinkImpl::XULContentSinkImpl() 1.166 + : mText(nullptr), 1.167 + mTextLength(0), 1.168 + mTextSize(0), 1.169 + mConstrainSize(true), 1.170 + mState(eInProlog), 1.171 + mParser(nullptr) 1.172 +{ 1.173 + 1.174 +#ifdef PR_LOGGING 1.175 + if (! gContentSinkLog) 1.176 + gContentSinkLog = PR_NewLogModule("nsXULContentSink"); 1.177 +#endif 1.178 +} 1.179 + 1.180 + 1.181 +XULContentSinkImpl::~XULContentSinkImpl() 1.182 +{ 1.183 + NS_IF_RELEASE(mParser); // XXX should've been released by now, unless error. 1.184 + 1.185 + // The context stack _should_ be empty, unless something has gone wrong. 1.186 + NS_ASSERTION(mContextStack.Depth() == 0, "Context stack not empty?"); 1.187 + mContextStack.Clear(); 1.188 + 1.189 + moz_free(mText); 1.190 +} 1.191 + 1.192 +//---------------------------------------------------------------------- 1.193 +// nsISupports interface 1.194 + 1.195 +NS_IMPL_CYCLE_COLLECTION_CLASS(XULContentSinkImpl) 1.196 + 1.197 +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(XULContentSinkImpl) 1.198 + NS_IMPL_CYCLE_COLLECTION_UNLINK(mNodeInfoManager) 1.199 + tmp->mContextStack.Clear(); 1.200 + NS_IMPL_CYCLE_COLLECTION_UNLINK(mPrototype) 1.201 + NS_IF_RELEASE(tmp->mParser); 1.202 +NS_IMPL_CYCLE_COLLECTION_UNLINK_END 1.203 + 1.204 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(XULContentSinkImpl) 1.205 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNodeInfoManager) 1.206 + tmp->mContextStack.Traverse(cb); 1.207 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPrototype) 1.208 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE_RAWPTR(mParser) 1.209 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END 1.210 + 1.211 +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(XULContentSinkImpl) 1.212 + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXMLContentSink) 1.213 + NS_INTERFACE_MAP_ENTRY(nsIXMLContentSink) 1.214 + NS_INTERFACE_MAP_ENTRY(nsIExpatSink) 1.215 + NS_INTERFACE_MAP_ENTRY(nsIContentSink) 1.216 +NS_INTERFACE_MAP_END 1.217 + 1.218 +NS_IMPL_CYCLE_COLLECTING_ADDREF(XULContentSinkImpl) 1.219 +NS_IMPL_CYCLE_COLLECTING_RELEASE(XULContentSinkImpl) 1.220 + 1.221 +//---------------------------------------------------------------------- 1.222 +// nsIContentSink interface 1.223 + 1.224 +NS_IMETHODIMP 1.225 +XULContentSinkImpl::WillBuildModel(nsDTDMode aDTDMode) 1.226 +{ 1.227 +#if FIXME 1.228 + if (! mParentContentSink) { 1.229 + // If we're _not_ an overlay, then notify the document that 1.230 + // the load is beginning. 1.231 + mDocument->BeginLoad(); 1.232 + } 1.233 +#endif 1.234 + 1.235 + return NS_OK; 1.236 +} 1.237 + 1.238 +NS_IMETHODIMP 1.239 +XULContentSinkImpl::DidBuildModel(bool aTerminated) 1.240 +{ 1.241 + nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocument); 1.242 + if (doc) { 1.243 + doc->EndLoad(); 1.244 + mDocument = nullptr; 1.245 + } 1.246 + 1.247 + // Drop our reference to the parser to get rid of a circular 1.248 + // reference. 1.249 + NS_IF_RELEASE(mParser); 1.250 + return NS_OK; 1.251 +} 1.252 + 1.253 +NS_IMETHODIMP 1.254 +XULContentSinkImpl::WillInterrupt(void) 1.255 +{ 1.256 + // XXX Notify the docshell, if necessary 1.257 + return NS_OK; 1.258 +} 1.259 + 1.260 +NS_IMETHODIMP 1.261 +XULContentSinkImpl::WillResume(void) 1.262 +{ 1.263 + // XXX Notify the docshell, if necessary 1.264 + return NS_OK; 1.265 +} 1.266 + 1.267 +NS_IMETHODIMP 1.268 +XULContentSinkImpl::SetParser(nsParserBase* aParser) 1.269 +{ 1.270 + NS_IF_RELEASE(mParser); 1.271 + mParser = aParser; 1.272 + NS_IF_ADDREF(mParser); 1.273 + return NS_OK; 1.274 +} 1.275 + 1.276 +NS_IMETHODIMP 1.277 +XULContentSinkImpl::SetDocumentCharset(nsACString& aCharset) 1.278 +{ 1.279 + nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocument); 1.280 + if (doc) { 1.281 + doc->SetDocumentCharacterSet(aCharset); 1.282 + } 1.283 + 1.284 + return NS_OK; 1.285 +} 1.286 + 1.287 +nsISupports * 1.288 +XULContentSinkImpl::GetTarget() 1.289 +{ 1.290 + nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocument); 1.291 + return doc; 1.292 +} 1.293 + 1.294 +//---------------------------------------------------------------------- 1.295 + 1.296 +nsresult 1.297 +XULContentSinkImpl::Init(nsIDocument* aDocument, 1.298 + nsXULPrototypeDocument* aPrototype) 1.299 +{ 1.300 + NS_PRECONDITION(aDocument != nullptr, "null ptr"); 1.301 + if (! aDocument) 1.302 + return NS_ERROR_NULL_POINTER; 1.303 + 1.304 + nsresult rv; 1.305 + 1.306 + mDocument = do_GetWeakReference(aDocument); 1.307 + mPrototype = aPrototype; 1.308 + 1.309 + mDocumentURL = mPrototype->GetURI(); 1.310 + 1.311 + // XXX this presumes HTTP header info is already set in document 1.312 + // XXX if it isn't we need to set it here... 1.313 + // XXXbz not like GetHeaderData on the proto doc _does_ anything.... 1.314 + nsAutoString preferredStyle; 1.315 + rv = mPrototype->GetHeaderData(nsGkAtoms::headerDefaultStyle, 1.316 + preferredStyle); 1.317 + if (NS_FAILED(rv)) return rv; 1.318 + 1.319 + if (!preferredStyle.IsEmpty()) { 1.320 + aDocument->SetHeaderData(nsGkAtoms::headerDefaultStyle, 1.321 + preferredStyle); 1.322 + } 1.323 + 1.324 + // Set the right preferred style on the document's CSSLoader. 1.325 + aDocument->CSSLoader()->SetPreferredSheet(preferredStyle); 1.326 + 1.327 + mNodeInfoManager = aPrototype->GetNodeInfoManager(); 1.328 + if (! mNodeInfoManager) 1.329 + return NS_ERROR_UNEXPECTED; 1.330 + 1.331 + mState = eInProlog; 1.332 + return NS_OK; 1.333 +} 1.334 + 1.335 + 1.336 +//---------------------------------------------------------------------- 1.337 +// 1.338 +// Text buffering 1.339 +// 1.340 + 1.341 +bool 1.342 +XULContentSinkImpl::IsDataInBuffer(char16_t* buffer, int32_t length) 1.343 +{ 1.344 + for (int32_t i = 0; i < length; ++i) { 1.345 + if (buffer[i] == ' ' || 1.346 + buffer[i] == '\t' || 1.347 + buffer[i] == '\n' || 1.348 + buffer[i] == '\r') 1.349 + continue; 1.350 + 1.351 + return true; 1.352 + } 1.353 + return false; 1.354 +} 1.355 + 1.356 + 1.357 +nsresult 1.358 +XULContentSinkImpl::FlushText(bool aCreateTextNode) 1.359 +{ 1.360 + nsresult rv; 1.361 + 1.362 + do { 1.363 + // Don't do anything if there's no text to create a node from, or 1.364 + // if they've told us not to create a text node 1.365 + if (! mTextLength) 1.366 + break; 1.367 + 1.368 + if (! aCreateTextNode) 1.369 + break; 1.370 + 1.371 + nsRefPtr<nsXULPrototypeNode> node; 1.372 + rv = mContextStack.GetTopNode(node); 1.373 + if (NS_FAILED(rv)) return rv; 1.374 + 1.375 + bool stripWhitespace = false; 1.376 + if (node->mType == nsXULPrototypeNode::eType_Element) { 1.377 + nsINodeInfo *nodeInfo = 1.378 + static_cast<nsXULPrototypeElement*>(node.get())->mNodeInfo; 1.379 + 1.380 + if (nodeInfo->NamespaceEquals(kNameSpaceID_XUL)) 1.381 + stripWhitespace = !nodeInfo->Equals(nsGkAtoms::label) && 1.382 + !nodeInfo->Equals(nsGkAtoms::description); 1.383 + } 1.384 + 1.385 + // Don't bother if there's nothing but whitespace. 1.386 + if (stripWhitespace && ! IsDataInBuffer(mText, mTextLength)) 1.387 + break; 1.388 + 1.389 + // Don't bother if we're not in XUL document body 1.390 + if (mState != eInDocumentElement || mContextStack.Depth() == 0) 1.391 + break; 1.392 + 1.393 + nsXULPrototypeText* text = new nsXULPrototypeText(); 1.394 + if (! text) 1.395 + return NS_ERROR_OUT_OF_MEMORY; 1.396 + 1.397 + text->mValue.Assign(mText, mTextLength); 1.398 + if (stripWhitespace) 1.399 + text->mValue.Trim(" \t\n\r"); 1.400 + 1.401 + // hook it up 1.402 + nsPrototypeArray* children = nullptr; 1.403 + rv = mContextStack.GetTopChildren(&children); 1.404 + if (NS_FAILED(rv)) return rv; 1.405 + 1.406 + // transfer ownership of 'text' to the children array 1.407 + children->AppendElement(text); 1.408 + } while (0); 1.409 + 1.410 + // Reset our text buffer 1.411 + mTextLength = 0; 1.412 + return NS_OK; 1.413 +} 1.414 + 1.415 +//---------------------------------------------------------------------- 1.416 + 1.417 +nsresult 1.418 +XULContentSinkImpl::NormalizeAttributeString(const char16_t *aExpatName, 1.419 + nsAttrName &aName) 1.420 +{ 1.421 + int32_t nameSpaceID; 1.422 + nsCOMPtr<nsIAtom> prefix, localName; 1.423 + nsContentUtils::SplitExpatName(aExpatName, getter_AddRefs(prefix), 1.424 + getter_AddRefs(localName), &nameSpaceID); 1.425 + 1.426 + if (nameSpaceID == kNameSpaceID_None) { 1.427 + aName.SetTo(localName); 1.428 + 1.429 + return NS_OK; 1.430 + } 1.431 + 1.432 + nsCOMPtr<nsINodeInfo> ni; 1.433 + ni = mNodeInfoManager->GetNodeInfo(localName, prefix, 1.434 + nameSpaceID, 1.435 + nsIDOMNode::ATTRIBUTE_NODE); 1.436 + aName.SetTo(ni); 1.437 + 1.438 + return NS_OK; 1.439 +} 1.440 + 1.441 +nsresult 1.442 +XULContentSinkImpl::CreateElement(nsINodeInfo *aNodeInfo, 1.443 + nsXULPrototypeElement** aResult) 1.444 +{ 1.445 + nsXULPrototypeElement* element = new nsXULPrototypeElement(); 1.446 + if (! element) 1.447 + return NS_ERROR_OUT_OF_MEMORY; 1.448 + 1.449 + element->mNodeInfo = aNodeInfo; 1.450 + 1.451 + *aResult = element; 1.452 + return NS_OK; 1.453 +} 1.454 + 1.455 +/**** BEGIN NEW APIs ****/ 1.456 + 1.457 + 1.458 +NS_IMETHODIMP 1.459 +XULContentSinkImpl::HandleStartElement(const char16_t *aName, 1.460 + const char16_t **aAtts, 1.461 + uint32_t aAttsCount, 1.462 + int32_t aIndex, 1.463 + uint32_t aLineNumber) 1.464 +{ 1.465 + // XXX Hopefully the parser will flag this before we get here. If 1.466 + // we're in the epilog, there should be no new elements 1.467 + NS_PRECONDITION(mState != eInEpilog, "tag in XUL doc epilog"); 1.468 + NS_PRECONDITION(aIndex >= -1, "Bogus aIndex"); 1.469 + NS_PRECONDITION(aAttsCount % 2 == 0, "incorrect aAttsCount"); 1.470 + // Adjust aAttsCount so it's the actual number of attributes 1.471 + aAttsCount /= 2; 1.472 + 1.473 + if (mState == eInEpilog) 1.474 + return NS_ERROR_UNEXPECTED; 1.475 + 1.476 + if (mState != eInScript) { 1.477 + FlushText(); 1.478 + } 1.479 + 1.480 + int32_t nameSpaceID; 1.481 + nsCOMPtr<nsIAtom> prefix, localName; 1.482 + nsContentUtils::SplitExpatName(aName, getter_AddRefs(prefix), 1.483 + getter_AddRefs(localName), &nameSpaceID); 1.484 + 1.485 + nsCOMPtr<nsINodeInfo> nodeInfo; 1.486 + nodeInfo = mNodeInfoManager->GetNodeInfo(localName, prefix, nameSpaceID, 1.487 + nsIDOMNode::ELEMENT_NODE); 1.488 + 1.489 + nsresult rv = NS_OK; 1.490 + switch (mState) { 1.491 + case eInProlog: 1.492 + // We're the root document element 1.493 + rv = OpenRoot(aAtts, aAttsCount, nodeInfo); 1.494 + break; 1.495 + 1.496 + case eInDocumentElement: 1.497 + rv = OpenTag(aAtts, aAttsCount, aLineNumber, nodeInfo); 1.498 + break; 1.499 + 1.500 + case eInEpilog: 1.501 + case eInScript: 1.502 + PR_LOG(gContentSinkLog, PR_LOG_WARNING, 1.503 + ("xul: warning: unexpected tags in epilog at line %d", 1.504 + aLineNumber)); 1.505 + rv = NS_ERROR_UNEXPECTED; // XXX 1.506 + break; 1.507 + } 1.508 + 1.509 + // Set the ID attribute atom on the node info object for this node 1.510 + if (aIndex != -1 && NS_SUCCEEDED(rv)) { 1.511 + nsCOMPtr<nsIAtom> IDAttr = do_GetAtom(aAtts[aIndex]); 1.512 + 1.513 + if (IDAttr) { 1.514 + nodeInfo->SetIDAttributeAtom(IDAttr); 1.515 + } 1.516 + } 1.517 + 1.518 + return rv; 1.519 +} 1.520 + 1.521 +NS_IMETHODIMP 1.522 +XULContentSinkImpl::HandleEndElement(const char16_t *aName) 1.523 +{ 1.524 + // Never EVER return anything but NS_OK or 1.525 + // NS_ERROR_HTMLPARSER_BLOCK from this method. Doing so will blow 1.526 + // the parser's little mind all over the planet. 1.527 + nsresult rv; 1.528 + 1.529 + nsRefPtr<nsXULPrototypeNode> node; 1.530 + rv = mContextStack.GetTopNode(node); 1.531 + 1.532 + if (NS_FAILED(rv)) { 1.533 + return NS_OK; 1.534 + } 1.535 + 1.536 + switch (node->mType) { 1.537 + case nsXULPrototypeNode::eType_Element: { 1.538 + // Flush any text _now_, so that we'll get text nodes created 1.539 + // before popping the stack. 1.540 + FlushText(); 1.541 + 1.542 + // Pop the context stack and do prototype hookup. 1.543 + nsPrototypeArray* children = nullptr; 1.544 + rv = mContextStack.GetTopChildren(&children); 1.545 + if (NS_FAILED(rv)) return rv; 1.546 + 1.547 + nsXULPrototypeElement* element = 1.548 + static_cast<nsXULPrototypeElement*>(node.get()); 1.549 + 1.550 + int32_t count = children->Length(); 1.551 + if (count) { 1.552 + element->mChildren.SetCapacity(count); 1.553 + 1.554 + for (int32_t i = 0; i < count; ++i) 1.555 + element->mChildren.AppendElement(children->ElementAt(i)); 1.556 + 1.557 + } 1.558 + } 1.559 + break; 1.560 + 1.561 + case nsXULPrototypeNode::eType_Script: { 1.562 + nsXULPrototypeScript* script = 1.563 + static_cast<nsXULPrototypeScript*>(node.get()); 1.564 + 1.565 + // If given a src= attribute, we must ignore script tag content. 1.566 + if (!script->mSrcURI && !script->GetScriptObject()) { 1.567 + nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocument); 1.568 + 1.569 + script->mOutOfLine = false; 1.570 + if (doc) 1.571 + script->Compile(mText, mTextLength, mDocumentURL, 1.572 + script->mLineNo, doc, mPrototype); 1.573 + } 1.574 + 1.575 + FlushText(false); 1.576 + } 1.577 + break; 1.578 + 1.579 + default: 1.580 + NS_ERROR("didn't expect that"); 1.581 + break; 1.582 + } 1.583 + 1.584 + rv = mContextStack.Pop(&mState); 1.585 + NS_ASSERTION(NS_SUCCEEDED(rv), "context stack corrupted"); 1.586 + if (NS_FAILED(rv)) return rv; 1.587 + 1.588 + if (mContextStack.Depth() == 0) { 1.589 + // The root element should -always- be an element, because 1.590 + // it'll have been created via XULContentSinkImpl::OpenRoot(). 1.591 + NS_ASSERTION(node->mType == nsXULPrototypeNode::eType_Element, "root is not an element"); 1.592 + if (node->mType != nsXULPrototypeNode::eType_Element) 1.593 + return NS_ERROR_UNEXPECTED; 1.594 + 1.595 + // Now that we're done parsing, set the prototype document's 1.596 + // root element. This transfers ownership of the prototype 1.597 + // element tree to the prototype document. 1.598 + nsXULPrototypeElement* element = 1.599 + static_cast<nsXULPrototypeElement*>(node.get()); 1.600 + 1.601 + mPrototype->SetRootElement(element); 1.602 + mState = eInEpilog; 1.603 + } 1.604 + 1.605 + return NS_OK; 1.606 +} 1.607 + 1.608 +NS_IMETHODIMP 1.609 +XULContentSinkImpl::HandleComment(const char16_t *aName) 1.610 +{ 1.611 + FlushText(); 1.612 + return NS_OK; 1.613 +} 1.614 + 1.615 +NS_IMETHODIMP 1.616 +XULContentSinkImpl::HandleCDataSection(const char16_t *aData, uint32_t aLength) 1.617 +{ 1.618 + FlushText(); 1.619 + return AddText(aData, aLength); 1.620 +} 1.621 + 1.622 +NS_IMETHODIMP 1.623 +XULContentSinkImpl::HandleDoctypeDecl(const nsAString & aSubset, 1.624 + const nsAString & aName, 1.625 + const nsAString & aSystemId, 1.626 + const nsAString & aPublicId, 1.627 + nsISupports* aCatalogData) 1.628 +{ 1.629 + return NS_OK; 1.630 +} 1.631 + 1.632 +NS_IMETHODIMP 1.633 +XULContentSinkImpl::HandleCharacterData(const char16_t *aData, 1.634 + uint32_t aLength) 1.635 +{ 1.636 + if (aData && mState != eInProlog && mState != eInEpilog) { 1.637 + return AddText(aData, aLength); 1.638 + } 1.639 + return NS_OK; 1.640 +} 1.641 + 1.642 +NS_IMETHODIMP 1.643 +XULContentSinkImpl::HandleProcessingInstruction(const char16_t *aTarget, 1.644 + const char16_t *aData) 1.645 +{ 1.646 + FlushText(); 1.647 + 1.648 + const nsDependentString target(aTarget); 1.649 + const nsDependentString data(aData); 1.650 + 1.651 + // Note: the created nsXULPrototypePI has mRefCnt == 1 1.652 + nsRefPtr<nsXULPrototypePI> pi = new nsXULPrototypePI(); 1.653 + if (!pi) 1.654 + return NS_ERROR_OUT_OF_MEMORY; 1.655 + 1.656 + pi->mTarget = target; 1.657 + pi->mData = data; 1.658 + 1.659 + if (mState == eInProlog) { 1.660 + // Note: passing in already addrefed pi 1.661 + return mPrototype->AddProcessingInstruction(pi); 1.662 + } 1.663 + 1.664 + nsresult rv; 1.665 + nsPrototypeArray* children = nullptr; 1.666 + rv = mContextStack.GetTopChildren(&children); 1.667 + if (NS_FAILED(rv)) { 1.668 + return rv; 1.669 + } 1.670 + 1.671 + if (!children->AppendElement(pi)) { 1.672 + return NS_ERROR_OUT_OF_MEMORY; 1.673 + } 1.674 + 1.675 + return NS_OK; 1.676 +} 1.677 + 1.678 + 1.679 +NS_IMETHODIMP 1.680 +XULContentSinkImpl::HandleXMLDeclaration(const char16_t *aVersion, 1.681 + const char16_t *aEncoding, 1.682 + int32_t aStandalone) 1.683 +{ 1.684 + return NS_OK; 1.685 +} 1.686 + 1.687 + 1.688 +NS_IMETHODIMP 1.689 +XULContentSinkImpl::ReportError(const char16_t* aErrorText, 1.690 + const char16_t* aSourceText, 1.691 + nsIScriptError *aError, 1.692 + bool *_retval) 1.693 +{ 1.694 + NS_PRECONDITION(aError && aSourceText && aErrorText, "Check arguments!!!"); 1.695 + 1.696 + // The expat driver should report the error. 1.697 + *_retval = true; 1.698 + 1.699 + nsresult rv = NS_OK; 1.700 + 1.701 + // make sure to empty the context stack so that 1.702 + // <parsererror> could become the root element. 1.703 + mContextStack.Clear(); 1.704 + 1.705 + mState = eInProlog; 1.706 + 1.707 + // Clear any buffered-up text we have. It's enough to set the length to 0. 1.708 + // The buffer itself is allocated when we're created and deleted in our 1.709 + // destructor, so don't mess with it. 1.710 + mTextLength = 0; 1.711 + 1.712 + nsCOMPtr<nsIXULDocument> doc = do_QueryReferent(mDocument); 1.713 + if (doc && !doc->OnDocumentParserError()) { 1.714 + // The overlay was broken. Don't add a messy element to the master doc. 1.715 + return NS_OK; 1.716 + } 1.717 + 1.718 + const char16_t* noAtts[] = { 0, 0 }; 1.719 + 1.720 + NS_NAMED_LITERAL_STRING(errorNs, 1.721 + "http://www.mozilla.org/newlayout/xml/parsererror.xml"); 1.722 + 1.723 + nsAutoString parsererror(errorNs); 1.724 + parsererror.Append((char16_t)0xFFFF); 1.725 + parsererror.AppendLiteral("parsererror"); 1.726 + 1.727 + rv = HandleStartElement(parsererror.get(), noAtts, 0, -1, 0); 1.728 + NS_ENSURE_SUCCESS(rv,rv); 1.729 + 1.730 + rv = HandleCharacterData(aErrorText, NS_strlen(aErrorText)); 1.731 + NS_ENSURE_SUCCESS(rv,rv); 1.732 + 1.733 + nsAutoString sourcetext(errorNs); 1.734 + sourcetext.Append((char16_t)0xFFFF); 1.735 + sourcetext.AppendLiteral("sourcetext"); 1.736 + 1.737 + rv = HandleStartElement(sourcetext.get(), noAtts, 0, -1, 0); 1.738 + NS_ENSURE_SUCCESS(rv,rv); 1.739 + 1.740 + rv = HandleCharacterData(aSourceText, NS_strlen(aSourceText)); 1.741 + NS_ENSURE_SUCCESS(rv,rv); 1.742 + 1.743 + rv = HandleEndElement(sourcetext.get()); 1.744 + NS_ENSURE_SUCCESS(rv,rv); 1.745 + 1.746 + rv = HandleEndElement(parsererror.get()); 1.747 + NS_ENSURE_SUCCESS(rv,rv); 1.748 + 1.749 + return rv; 1.750 +} 1.751 + 1.752 +nsresult 1.753 +XULContentSinkImpl::OpenRoot(const char16_t** aAttributes, 1.754 + const uint32_t aAttrLen, 1.755 + nsINodeInfo *aNodeInfo) 1.756 +{ 1.757 + NS_ASSERTION(mState == eInProlog, "how'd we get here?"); 1.758 + if (mState != eInProlog) 1.759 + return NS_ERROR_UNEXPECTED; 1.760 + 1.761 + nsresult rv; 1.762 + 1.763 + if (aNodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_XHTML) || 1.764 + aNodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_XUL)) { 1.765 + PR_LOG(gContentSinkLog, PR_LOG_ERROR, 1.766 + ("xul: script tag not allowed as root content element")); 1.767 + 1.768 + return NS_ERROR_UNEXPECTED; 1.769 + } 1.770 + 1.771 + // Create the element 1.772 + nsXULPrototypeElement* element; 1.773 + rv = CreateElement(aNodeInfo, &element); 1.774 + 1.775 + if (NS_FAILED(rv)) { 1.776 +#ifdef PR_LOGGING 1.777 + if (PR_LOG_TEST(gContentSinkLog, PR_LOG_ERROR)) { 1.778 + nsAutoString anodeC; 1.779 + aNodeInfo->GetName(anodeC); 1.780 + PR_LOG(gContentSinkLog, PR_LOG_ERROR, 1.781 + ("xul: unable to create element '%s' at line %d", 1.782 + NS_ConvertUTF16toUTF8(anodeC).get(), 1.783 + -1)); // XXX pass in line number 1.784 + } 1.785 +#endif 1.786 + 1.787 + return rv; 1.788 + } 1.789 + 1.790 + // Push the element onto the context stack, so that child 1.791 + // containers will hook up to us as their parent. 1.792 + rv = mContextStack.Push(element, mState); 1.793 + if (NS_FAILED(rv)) { 1.794 + element->Release(); 1.795 + return rv; 1.796 + } 1.797 + 1.798 + // Add the attributes 1.799 + rv = AddAttributes(aAttributes, aAttrLen, element); 1.800 + if (NS_FAILED(rv)) return rv; 1.801 + 1.802 + mState = eInDocumentElement; 1.803 + return NS_OK; 1.804 +} 1.805 + 1.806 +nsresult 1.807 +XULContentSinkImpl::OpenTag(const char16_t** aAttributes, 1.808 + const uint32_t aAttrLen, 1.809 + const uint32_t aLineNumber, 1.810 + nsINodeInfo *aNodeInfo) 1.811 +{ 1.812 + nsresult rv; 1.813 + 1.814 + // Create the element 1.815 + nsXULPrototypeElement* element; 1.816 + rv = CreateElement(aNodeInfo, &element); 1.817 + 1.818 + if (NS_FAILED(rv)) { 1.819 +#ifdef PR_LOGGING 1.820 + if (PR_LOG_TEST(gContentSinkLog, PR_LOG_ERROR)) { 1.821 + nsAutoString anodeC; 1.822 + aNodeInfo->GetName(anodeC); 1.823 + PR_LOG(gContentSinkLog, PR_LOG_ERROR, 1.824 + ("xul: unable to create element '%s' at line %d", 1.825 + NS_ConvertUTF16toUTF8(anodeC).get(), 1.826 + aLineNumber)); 1.827 + } 1.828 +#endif 1.829 + 1.830 + return rv; 1.831 + } 1.832 + 1.833 + // Link this element to its parent. 1.834 + nsPrototypeArray* children = nullptr; 1.835 + rv = mContextStack.GetTopChildren(&children); 1.836 + if (NS_FAILED(rv)) { 1.837 + delete element; 1.838 + return rv; 1.839 + } 1.840 + 1.841 + // Add the attributes 1.842 + rv = AddAttributes(aAttributes, aAttrLen, element); 1.843 + if (NS_FAILED(rv)) return rv; 1.844 + 1.845 + children->AppendElement(element); 1.846 + 1.847 + if (aNodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_XHTML) || 1.848 + aNodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_XUL)) { 1.849 + // Do scripty things now 1.850 + rv = OpenScript(aAttributes, aLineNumber); 1.851 + NS_ENSURE_SUCCESS(rv, rv); 1.852 + 1.853 + NS_ASSERTION(mState == eInScript || mState == eInDocumentElement, 1.854 + "Unexpected state"); 1.855 + if (mState == eInScript) { 1.856 + // OpenScript has pushed the nsPrototypeScriptElement onto the 1.857 + // stack, so we're done. 1.858 + return NS_OK; 1.859 + } 1.860 + } 1.861 + 1.862 + // Push the element onto the context stack, so that child 1.863 + // containers will hook up to us as their parent. 1.864 + rv = mContextStack.Push(element, mState); 1.865 + if (NS_FAILED(rv)) return rv; 1.866 + 1.867 + mState = eInDocumentElement; 1.868 + return NS_OK; 1.869 +} 1.870 + 1.871 +nsresult 1.872 +XULContentSinkImpl::OpenScript(const char16_t** aAttributes, 1.873 + const uint32_t aLineNumber) 1.874 +{ 1.875 + uint32_t langID = nsIProgrammingLanguage::JAVASCRIPT; 1.876 + uint32_t version = JSVERSION_LATEST; 1.877 + nsresult rv; 1.878 + 1.879 + // Look for SRC attribute and look for a LANGUAGE attribute 1.880 + nsAutoString src; 1.881 + while (*aAttributes) { 1.882 + const nsDependentString key(aAttributes[0]); 1.883 + if (key.EqualsLiteral("src")) { 1.884 + src.Assign(aAttributes[1]); 1.885 + } 1.886 + else if (key.EqualsLiteral("type")) { 1.887 + nsDependentString str(aAttributes[1]); 1.888 + nsContentTypeParser parser(str); 1.889 + nsAutoString mimeType; 1.890 + rv = parser.GetType(mimeType); 1.891 + if (NS_FAILED(rv)) { 1.892 + if (rv == NS_ERROR_INVALID_ARG) { 1.893 + // Might as well bail out now instead of setting langID to 1.894 + // nsIProgrammingLanguage::UNKNOWN and bailing out later. 1.895 + return NS_OK; 1.896 + } 1.897 + // We do want the warning here 1.898 + NS_ENSURE_SUCCESS(rv, rv); 1.899 + } 1.900 + 1.901 + if (nsContentUtils::IsJavascriptMIMEType(mimeType)) { 1.902 + langID = nsIProgrammingLanguage::JAVASCRIPT; 1.903 + version = JSVERSION_LATEST; 1.904 + } else { 1.905 + langID = nsIProgrammingLanguage::UNKNOWN; 1.906 + } 1.907 + 1.908 + if (langID != nsIProgrammingLanguage::UNKNOWN) { 1.909 + // Get the version string, and ensure the language supports it. 1.910 + nsAutoString versionName; 1.911 + rv = parser.GetParameter("version", versionName); 1.912 + 1.913 + if (NS_SUCCEEDED(rv)) { 1.914 + version = nsContentUtils::ParseJavascriptVersion(versionName); 1.915 + } else if (rv != NS_ERROR_INVALID_ARG) { 1.916 + return rv; 1.917 + } 1.918 + } 1.919 + } 1.920 + else if (key.EqualsLiteral("language")) { 1.921 + // Language is deprecated, and the impl in nsScriptLoader ignores the 1.922 + // various version strings anyway. So we make no attempt to support 1.923 + // languages other than JS for language= 1.924 + nsAutoString lang(aAttributes[1]); 1.925 + if (nsContentUtils::IsJavaScriptLanguage(lang)) { 1.926 + version = JSVERSION_DEFAULT; 1.927 + langID = nsIProgrammingLanguage::JAVASCRIPT; 1.928 + } 1.929 + } 1.930 + aAttributes += 2; 1.931 + } 1.932 + 1.933 + // Not all script languages have a "sandbox" concept. At time of 1.934 + // writing, Python is the only other language, and it does not. 1.935 + // For such languages, neither any inline script nor remote script are 1.936 + // safe to execute from untrusted sources. 1.937 + // So for such languages, we only allow script when the document 1.938 + // itself is from chrome. We then don't bother to check the 1.939 + // "src=" tag - we trust chrome to do the right thing. 1.940 + // (See also similar code in nsScriptLoader.cpp) 1.941 + nsCOMPtr<nsIDocument> doc(do_QueryReferent(mDocument)); 1.942 + if (langID != nsIProgrammingLanguage::UNKNOWN && 1.943 + langID != nsIProgrammingLanguage::JAVASCRIPT && 1.944 + doc && !nsContentUtils::IsChromeDoc(doc)) { 1.945 + langID = nsIProgrammingLanguage::UNKNOWN; 1.946 + NS_WARNING("Non JS language called from non chrome - ignored"); 1.947 + } 1.948 + 1.949 + // Don't process scripts that aren't known 1.950 + if (langID != nsIProgrammingLanguage::UNKNOWN) { 1.951 + nsCOMPtr<nsIScriptGlobalObject> globalObject; 1.952 + if (doc) 1.953 + globalObject = do_QueryInterface(doc->GetWindow()); 1.954 + nsRefPtr<nsXULPrototypeScript> script = 1.955 + new nsXULPrototypeScript(aLineNumber, version); 1.956 + if (! script) 1.957 + return NS_ERROR_OUT_OF_MEMORY; 1.958 + 1.959 + // If there is a SRC attribute... 1.960 + if (! src.IsEmpty()) { 1.961 + // Use the SRC attribute value to load the URL 1.962 + rv = NS_NewURI(getter_AddRefs(script->mSrcURI), src, nullptr, mDocumentURL); 1.963 + 1.964 + // Check if this document is allowed to load a script from this source 1.965 + // NOTE: if we ever allow scripts added via the DOM to run, we need to 1.966 + // add a CheckLoadURI call for that as well. 1.967 + if (NS_SUCCEEDED(rv)) { 1.968 + if (!mSecMan) 1.969 + mSecMan = do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv); 1.970 + if (NS_SUCCEEDED(rv)) { 1.971 + nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocument, &rv); 1.972 + 1.973 + if (NS_SUCCEEDED(rv)) { 1.974 + rv = mSecMan-> 1.975 + CheckLoadURIWithPrincipal(doc->NodePrincipal(), 1.976 + script->mSrcURI, 1.977 + nsIScriptSecurityManager::ALLOW_CHROME); 1.978 + } 1.979 + } 1.980 + } 1.981 + 1.982 + if (NS_FAILED(rv)) { 1.983 + return rv; 1.984 + } 1.985 + 1.986 + // Attempt to deserialize an out-of-line script from the FastLoad 1.987 + // file right away. Otherwise we'll end up reloading the script and 1.988 + // corrupting the FastLoad file trying to serialize it, in the case 1.989 + // where it's already there. 1.990 + script->DeserializeOutOfLine(nullptr, mPrototype); 1.991 + } 1.992 + 1.993 + nsPrototypeArray* children = nullptr; 1.994 + rv = mContextStack.GetTopChildren(&children); 1.995 + if (NS_FAILED(rv)) { 1.996 + return rv; 1.997 + } 1.998 + 1.999 + children->AppendElement(script); 1.1000 + 1.1001 + mConstrainSize = false; 1.1002 + 1.1003 + mContextStack.Push(script, mState); 1.1004 + mState = eInScript; 1.1005 + } 1.1006 + 1.1007 + return NS_OK; 1.1008 +} 1.1009 + 1.1010 +nsresult 1.1011 +XULContentSinkImpl::AddAttributes(const char16_t** aAttributes, 1.1012 + const uint32_t aAttrLen, 1.1013 + nsXULPrototypeElement* aElement) 1.1014 +{ 1.1015 + // Add tag attributes to the element 1.1016 + nsresult rv; 1.1017 + 1.1018 + // Create storage for the attributes 1.1019 + nsXULPrototypeAttribute* attrs = nullptr; 1.1020 + if (aAttrLen > 0) { 1.1021 + attrs = new nsXULPrototypeAttribute[aAttrLen]; 1.1022 + if (! attrs) 1.1023 + return NS_ERROR_OUT_OF_MEMORY; 1.1024 + } 1.1025 + 1.1026 + aElement->mAttributes = attrs; 1.1027 + aElement->mNumAttributes = aAttrLen; 1.1028 + 1.1029 + // Copy the attributes into the prototype 1.1030 + uint32_t i; 1.1031 + for (i = 0; i < aAttrLen; ++i) { 1.1032 + rv = NormalizeAttributeString(aAttributes[i * 2], attrs[i].mName); 1.1033 + NS_ENSURE_SUCCESS(rv, rv); 1.1034 + 1.1035 + rv = aElement->SetAttrAt(i, nsDependentString(aAttributes[i * 2 + 1]), 1.1036 + mDocumentURL); 1.1037 + NS_ENSURE_SUCCESS(rv, rv); 1.1038 + 1.1039 +#ifdef PR_LOGGING 1.1040 + if (PR_LOG_TEST(gContentSinkLog, PR_LOG_DEBUG)) { 1.1041 + nsAutoString extraWhiteSpace; 1.1042 + int32_t cnt = mContextStack.Depth(); 1.1043 + while (--cnt >= 0) 1.1044 + extraWhiteSpace.AppendLiteral(" "); 1.1045 + nsAutoString qnameC,valueC; 1.1046 + qnameC.Assign(aAttributes[0]); 1.1047 + valueC.Assign(aAttributes[1]); 1.1048 + PR_LOG(gContentSinkLog, PR_LOG_DEBUG, 1.1049 + ("xul: %.5d. %s %s=%s", 1.1050 + -1, // XXX pass in line number 1.1051 + NS_ConvertUTF16toUTF8(extraWhiteSpace).get(), 1.1052 + NS_ConvertUTF16toUTF8(qnameC).get(), 1.1053 + NS_ConvertUTF16toUTF8(valueC).get())); 1.1054 + } 1.1055 +#endif 1.1056 + } 1.1057 + 1.1058 + return NS_OK; 1.1059 +} 1.1060 + 1.1061 +nsresult 1.1062 +XULContentSinkImpl::AddText(const char16_t* aText, 1.1063 + int32_t aLength) 1.1064 +{ 1.1065 + // Create buffer when we first need it 1.1066 + if (0 == mTextSize) { 1.1067 + mText = (char16_t *) moz_malloc(sizeof(char16_t) * 4096); 1.1068 + if (nullptr == mText) { 1.1069 + return NS_ERROR_OUT_OF_MEMORY; 1.1070 + } 1.1071 + mTextSize = 4096; 1.1072 + } 1.1073 + 1.1074 + // Copy data from string into our buffer; flush buffer when it fills up 1.1075 + int32_t offset = 0; 1.1076 + while (0 != aLength) { 1.1077 + int32_t amount = mTextSize - mTextLength; 1.1078 + if (amount > aLength) { 1.1079 + amount = aLength; 1.1080 + } 1.1081 + if (0 == amount) { 1.1082 + if (mConstrainSize) { 1.1083 + nsresult rv = FlushText(); 1.1084 + if (NS_OK != rv) { 1.1085 + return rv; 1.1086 + } 1.1087 + } 1.1088 + else { 1.1089 + mTextSize += aLength; 1.1090 + mText = (char16_t *) moz_realloc(mText, sizeof(char16_t) * mTextSize); 1.1091 + if (nullptr == mText) { 1.1092 + return NS_ERROR_OUT_OF_MEMORY; 1.1093 + } 1.1094 + } 1.1095 + } 1.1096 + memcpy(&mText[mTextLength],aText + offset, sizeof(char16_t) * amount); 1.1097 + 1.1098 + mTextLength += amount; 1.1099 + offset += amount; 1.1100 + aLength -= amount; 1.1101 + } 1.1102 + 1.1103 + return NS_OK; 1.1104 +}