content/xul/document/src/nsXULContentSink.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
michael@0 2 /* vim: set ts=8 sts=4 et sw=4 tw=80: */
michael@0 3 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 /*
michael@0 8 * An implementation for a Gecko-style content sink that knows how
michael@0 9 * to build a content model (the "prototype" document) from XUL.
michael@0 10 *
michael@0 11 * For more information on XUL,
michael@0 12 * see http://developer.mozilla.org/en/docs/XUL
michael@0 13 */
michael@0 14
michael@0 15 #include "nsXULContentSink.h"
michael@0 16
michael@0 17 #include "jsfriendapi.h"
michael@0 18
michael@0 19 #include "nsCOMPtr.h"
michael@0 20 #include "nsForwardReference.h"
michael@0 21 #include "nsHTMLStyleSheet.h"
michael@0 22 #include "nsIContentSink.h"
michael@0 23 #include "nsIDocument.h"
michael@0 24 #include "nsIDOMEventListener.h"
michael@0 25 #include "nsIDOMHTMLFormElement.h"
michael@0 26 #include "nsIDOMXULDocument.h"
michael@0 27 #include "nsIFormControl.h"
michael@0 28 #include "nsINodeInfo.h"
michael@0 29 #include "nsIScriptContext.h"
michael@0 30 #include "nsIScriptGlobalObject.h"
michael@0 31 #include "nsIServiceManager.h"
michael@0 32 #include "nsIURL.h"
michael@0 33 #include "nsNameSpaceManager.h"
michael@0 34 #include "nsParserBase.h"
michael@0 35 #include "nsViewManager.h"
michael@0 36 #include "nsIXULDocument.h"
michael@0 37 #include "nsIScriptSecurityManager.h"
michael@0 38 #include "nsLayoutCID.h"
michael@0 39 #include "nsNetUtil.h"
michael@0 40 #include "nsRDFCID.h"
michael@0 41 #include "nsXPIDLString.h"
michael@0 42 #include "nsReadableUtils.h"
michael@0 43 #include "nsXULElement.h"
michael@0 44 #include "prlog.h"
michael@0 45 #include "prmem.h"
michael@0 46 #include "nsCRT.h"
michael@0 47
michael@0 48 #include "nsXULPrototypeDocument.h" // XXXbe temporary
michael@0 49 #include "mozilla/css/Loader.h"
michael@0 50
michael@0 51 #include "nsUnicharUtils.h"
michael@0 52 #include "nsGkAtoms.h"
michael@0 53 #include "nsContentUtils.h"
michael@0 54 #include "nsAttrName.h"
michael@0 55 #include "nsXMLContentSink.h"
michael@0 56 #include "nsIConsoleService.h"
michael@0 57 #include "nsIScriptError.h"
michael@0 58 #include "nsContentTypeParser.h"
michael@0 59
michael@0 60 #ifdef PR_LOGGING
michael@0 61 static PRLogModuleInfo* gContentSinkLog;
michael@0 62 #endif
michael@0 63
michael@0 64 //----------------------------------------------------------------------
michael@0 65
michael@0 66 XULContentSinkImpl::ContextStack::ContextStack()
michael@0 67 : mTop(nullptr), mDepth(0)
michael@0 68 {
michael@0 69 }
michael@0 70
michael@0 71 XULContentSinkImpl::ContextStack::~ContextStack()
michael@0 72 {
michael@0 73 while (mTop) {
michael@0 74 Entry* doomed = mTop;
michael@0 75 mTop = mTop->mNext;
michael@0 76 delete doomed;
michael@0 77 }
michael@0 78 }
michael@0 79
michael@0 80 nsresult
michael@0 81 XULContentSinkImpl::ContextStack::Push(nsXULPrototypeNode* aNode, State aState)
michael@0 82 {
michael@0 83 Entry* entry = new Entry;
michael@0 84 if (! entry)
michael@0 85 return NS_ERROR_OUT_OF_MEMORY;
michael@0 86
michael@0 87 entry->mNode = aNode;
michael@0 88 entry->mState = aState;
michael@0 89 entry->mNext = mTop;
michael@0 90 mTop = entry;
michael@0 91
michael@0 92 ++mDepth;
michael@0 93 return NS_OK;
michael@0 94 }
michael@0 95
michael@0 96 nsresult
michael@0 97 XULContentSinkImpl::ContextStack::Pop(State* aState)
michael@0 98 {
michael@0 99 if (mDepth == 0)
michael@0 100 return NS_ERROR_UNEXPECTED;
michael@0 101
michael@0 102 Entry* entry = mTop;
michael@0 103 mTop = mTop->mNext;
michael@0 104 --mDepth;
michael@0 105
michael@0 106 *aState = entry->mState;
michael@0 107 delete entry;
michael@0 108
michael@0 109 return NS_OK;
michael@0 110 }
michael@0 111
michael@0 112
michael@0 113 nsresult
michael@0 114 XULContentSinkImpl::ContextStack::GetTopNode(nsRefPtr<nsXULPrototypeNode>& aNode)
michael@0 115 {
michael@0 116 if (mDepth == 0)
michael@0 117 return NS_ERROR_UNEXPECTED;
michael@0 118
michael@0 119 aNode = mTop->mNode;
michael@0 120 return NS_OK;
michael@0 121 }
michael@0 122
michael@0 123
michael@0 124 nsresult
michael@0 125 XULContentSinkImpl::ContextStack::GetTopChildren(nsPrototypeArray** aChildren)
michael@0 126 {
michael@0 127 if (mDepth == 0)
michael@0 128 return NS_ERROR_UNEXPECTED;
michael@0 129
michael@0 130 *aChildren = &(mTop->mChildren);
michael@0 131 return NS_OK;
michael@0 132 }
michael@0 133
michael@0 134 void
michael@0 135 XULContentSinkImpl::ContextStack::Clear()
michael@0 136 {
michael@0 137 Entry *cur = mTop;
michael@0 138 while (cur) {
michael@0 139 // Release the root element (and its descendants).
michael@0 140 Entry *next = cur->mNext;
michael@0 141 delete cur;
michael@0 142 cur = next;
michael@0 143 }
michael@0 144
michael@0 145 mTop = nullptr;
michael@0 146 mDepth = 0;
michael@0 147 }
michael@0 148
michael@0 149 void
michael@0 150 XULContentSinkImpl::ContextStack::Traverse(nsCycleCollectionTraversalCallback& aCb)
michael@0 151 {
michael@0 152 nsCycleCollectionTraversalCallback& cb = aCb;
michael@0 153 for (ContextStack::Entry* tmp = mTop; tmp; tmp = tmp->mNext) {
michael@0 154 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNode)
michael@0 155 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChildren)
michael@0 156 }
michael@0 157 }
michael@0 158
michael@0 159 //----------------------------------------------------------------------
michael@0 160
michael@0 161
michael@0 162 XULContentSinkImpl::XULContentSinkImpl()
michael@0 163 : mText(nullptr),
michael@0 164 mTextLength(0),
michael@0 165 mTextSize(0),
michael@0 166 mConstrainSize(true),
michael@0 167 mState(eInProlog),
michael@0 168 mParser(nullptr)
michael@0 169 {
michael@0 170
michael@0 171 #ifdef PR_LOGGING
michael@0 172 if (! gContentSinkLog)
michael@0 173 gContentSinkLog = PR_NewLogModule("nsXULContentSink");
michael@0 174 #endif
michael@0 175 }
michael@0 176
michael@0 177
michael@0 178 XULContentSinkImpl::~XULContentSinkImpl()
michael@0 179 {
michael@0 180 NS_IF_RELEASE(mParser); // XXX should've been released by now, unless error.
michael@0 181
michael@0 182 // The context stack _should_ be empty, unless something has gone wrong.
michael@0 183 NS_ASSERTION(mContextStack.Depth() == 0, "Context stack not empty?");
michael@0 184 mContextStack.Clear();
michael@0 185
michael@0 186 moz_free(mText);
michael@0 187 }
michael@0 188
michael@0 189 //----------------------------------------------------------------------
michael@0 190 // nsISupports interface
michael@0 191
michael@0 192 NS_IMPL_CYCLE_COLLECTION_CLASS(XULContentSinkImpl)
michael@0 193
michael@0 194 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(XULContentSinkImpl)
michael@0 195 NS_IMPL_CYCLE_COLLECTION_UNLINK(mNodeInfoManager)
michael@0 196 tmp->mContextStack.Clear();
michael@0 197 NS_IMPL_CYCLE_COLLECTION_UNLINK(mPrototype)
michael@0 198 NS_IF_RELEASE(tmp->mParser);
michael@0 199 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
michael@0 200
michael@0 201 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(XULContentSinkImpl)
michael@0 202 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNodeInfoManager)
michael@0 203 tmp->mContextStack.Traverse(cb);
michael@0 204 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPrototype)
michael@0 205 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_RAWPTR(mParser)
michael@0 206 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
michael@0 207
michael@0 208 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(XULContentSinkImpl)
michael@0 209 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXMLContentSink)
michael@0 210 NS_INTERFACE_MAP_ENTRY(nsIXMLContentSink)
michael@0 211 NS_INTERFACE_MAP_ENTRY(nsIExpatSink)
michael@0 212 NS_INTERFACE_MAP_ENTRY(nsIContentSink)
michael@0 213 NS_INTERFACE_MAP_END
michael@0 214
michael@0 215 NS_IMPL_CYCLE_COLLECTING_ADDREF(XULContentSinkImpl)
michael@0 216 NS_IMPL_CYCLE_COLLECTING_RELEASE(XULContentSinkImpl)
michael@0 217
michael@0 218 //----------------------------------------------------------------------
michael@0 219 // nsIContentSink interface
michael@0 220
michael@0 221 NS_IMETHODIMP
michael@0 222 XULContentSinkImpl::WillBuildModel(nsDTDMode aDTDMode)
michael@0 223 {
michael@0 224 #if FIXME
michael@0 225 if (! mParentContentSink) {
michael@0 226 // If we're _not_ an overlay, then notify the document that
michael@0 227 // the load is beginning.
michael@0 228 mDocument->BeginLoad();
michael@0 229 }
michael@0 230 #endif
michael@0 231
michael@0 232 return NS_OK;
michael@0 233 }
michael@0 234
michael@0 235 NS_IMETHODIMP
michael@0 236 XULContentSinkImpl::DidBuildModel(bool aTerminated)
michael@0 237 {
michael@0 238 nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocument);
michael@0 239 if (doc) {
michael@0 240 doc->EndLoad();
michael@0 241 mDocument = nullptr;
michael@0 242 }
michael@0 243
michael@0 244 // Drop our reference to the parser to get rid of a circular
michael@0 245 // reference.
michael@0 246 NS_IF_RELEASE(mParser);
michael@0 247 return NS_OK;
michael@0 248 }
michael@0 249
michael@0 250 NS_IMETHODIMP
michael@0 251 XULContentSinkImpl::WillInterrupt(void)
michael@0 252 {
michael@0 253 // XXX Notify the docshell, if necessary
michael@0 254 return NS_OK;
michael@0 255 }
michael@0 256
michael@0 257 NS_IMETHODIMP
michael@0 258 XULContentSinkImpl::WillResume(void)
michael@0 259 {
michael@0 260 // XXX Notify the docshell, if necessary
michael@0 261 return NS_OK;
michael@0 262 }
michael@0 263
michael@0 264 NS_IMETHODIMP
michael@0 265 XULContentSinkImpl::SetParser(nsParserBase* aParser)
michael@0 266 {
michael@0 267 NS_IF_RELEASE(mParser);
michael@0 268 mParser = aParser;
michael@0 269 NS_IF_ADDREF(mParser);
michael@0 270 return NS_OK;
michael@0 271 }
michael@0 272
michael@0 273 NS_IMETHODIMP
michael@0 274 XULContentSinkImpl::SetDocumentCharset(nsACString& aCharset)
michael@0 275 {
michael@0 276 nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocument);
michael@0 277 if (doc) {
michael@0 278 doc->SetDocumentCharacterSet(aCharset);
michael@0 279 }
michael@0 280
michael@0 281 return NS_OK;
michael@0 282 }
michael@0 283
michael@0 284 nsISupports *
michael@0 285 XULContentSinkImpl::GetTarget()
michael@0 286 {
michael@0 287 nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocument);
michael@0 288 return doc;
michael@0 289 }
michael@0 290
michael@0 291 //----------------------------------------------------------------------
michael@0 292
michael@0 293 nsresult
michael@0 294 XULContentSinkImpl::Init(nsIDocument* aDocument,
michael@0 295 nsXULPrototypeDocument* aPrototype)
michael@0 296 {
michael@0 297 NS_PRECONDITION(aDocument != nullptr, "null ptr");
michael@0 298 if (! aDocument)
michael@0 299 return NS_ERROR_NULL_POINTER;
michael@0 300
michael@0 301 nsresult rv;
michael@0 302
michael@0 303 mDocument = do_GetWeakReference(aDocument);
michael@0 304 mPrototype = aPrototype;
michael@0 305
michael@0 306 mDocumentURL = mPrototype->GetURI();
michael@0 307
michael@0 308 // XXX this presumes HTTP header info is already set in document
michael@0 309 // XXX if it isn't we need to set it here...
michael@0 310 // XXXbz not like GetHeaderData on the proto doc _does_ anything....
michael@0 311 nsAutoString preferredStyle;
michael@0 312 rv = mPrototype->GetHeaderData(nsGkAtoms::headerDefaultStyle,
michael@0 313 preferredStyle);
michael@0 314 if (NS_FAILED(rv)) return rv;
michael@0 315
michael@0 316 if (!preferredStyle.IsEmpty()) {
michael@0 317 aDocument->SetHeaderData(nsGkAtoms::headerDefaultStyle,
michael@0 318 preferredStyle);
michael@0 319 }
michael@0 320
michael@0 321 // Set the right preferred style on the document's CSSLoader.
michael@0 322 aDocument->CSSLoader()->SetPreferredSheet(preferredStyle);
michael@0 323
michael@0 324 mNodeInfoManager = aPrototype->GetNodeInfoManager();
michael@0 325 if (! mNodeInfoManager)
michael@0 326 return NS_ERROR_UNEXPECTED;
michael@0 327
michael@0 328 mState = eInProlog;
michael@0 329 return NS_OK;
michael@0 330 }
michael@0 331
michael@0 332
michael@0 333 //----------------------------------------------------------------------
michael@0 334 //
michael@0 335 // Text buffering
michael@0 336 //
michael@0 337
michael@0 338 bool
michael@0 339 XULContentSinkImpl::IsDataInBuffer(char16_t* buffer, int32_t length)
michael@0 340 {
michael@0 341 for (int32_t i = 0; i < length; ++i) {
michael@0 342 if (buffer[i] == ' ' ||
michael@0 343 buffer[i] == '\t' ||
michael@0 344 buffer[i] == '\n' ||
michael@0 345 buffer[i] == '\r')
michael@0 346 continue;
michael@0 347
michael@0 348 return true;
michael@0 349 }
michael@0 350 return false;
michael@0 351 }
michael@0 352
michael@0 353
michael@0 354 nsresult
michael@0 355 XULContentSinkImpl::FlushText(bool aCreateTextNode)
michael@0 356 {
michael@0 357 nsresult rv;
michael@0 358
michael@0 359 do {
michael@0 360 // Don't do anything if there's no text to create a node from, or
michael@0 361 // if they've told us not to create a text node
michael@0 362 if (! mTextLength)
michael@0 363 break;
michael@0 364
michael@0 365 if (! aCreateTextNode)
michael@0 366 break;
michael@0 367
michael@0 368 nsRefPtr<nsXULPrototypeNode> node;
michael@0 369 rv = mContextStack.GetTopNode(node);
michael@0 370 if (NS_FAILED(rv)) return rv;
michael@0 371
michael@0 372 bool stripWhitespace = false;
michael@0 373 if (node->mType == nsXULPrototypeNode::eType_Element) {
michael@0 374 nsINodeInfo *nodeInfo =
michael@0 375 static_cast<nsXULPrototypeElement*>(node.get())->mNodeInfo;
michael@0 376
michael@0 377 if (nodeInfo->NamespaceEquals(kNameSpaceID_XUL))
michael@0 378 stripWhitespace = !nodeInfo->Equals(nsGkAtoms::label) &&
michael@0 379 !nodeInfo->Equals(nsGkAtoms::description);
michael@0 380 }
michael@0 381
michael@0 382 // Don't bother if there's nothing but whitespace.
michael@0 383 if (stripWhitespace && ! IsDataInBuffer(mText, mTextLength))
michael@0 384 break;
michael@0 385
michael@0 386 // Don't bother if we're not in XUL document body
michael@0 387 if (mState != eInDocumentElement || mContextStack.Depth() == 0)
michael@0 388 break;
michael@0 389
michael@0 390 nsXULPrototypeText* text = new nsXULPrototypeText();
michael@0 391 if (! text)
michael@0 392 return NS_ERROR_OUT_OF_MEMORY;
michael@0 393
michael@0 394 text->mValue.Assign(mText, mTextLength);
michael@0 395 if (stripWhitespace)
michael@0 396 text->mValue.Trim(" \t\n\r");
michael@0 397
michael@0 398 // hook it up
michael@0 399 nsPrototypeArray* children = nullptr;
michael@0 400 rv = mContextStack.GetTopChildren(&children);
michael@0 401 if (NS_FAILED(rv)) return rv;
michael@0 402
michael@0 403 // transfer ownership of 'text' to the children array
michael@0 404 children->AppendElement(text);
michael@0 405 } while (0);
michael@0 406
michael@0 407 // Reset our text buffer
michael@0 408 mTextLength = 0;
michael@0 409 return NS_OK;
michael@0 410 }
michael@0 411
michael@0 412 //----------------------------------------------------------------------
michael@0 413
michael@0 414 nsresult
michael@0 415 XULContentSinkImpl::NormalizeAttributeString(const char16_t *aExpatName,
michael@0 416 nsAttrName &aName)
michael@0 417 {
michael@0 418 int32_t nameSpaceID;
michael@0 419 nsCOMPtr<nsIAtom> prefix, localName;
michael@0 420 nsContentUtils::SplitExpatName(aExpatName, getter_AddRefs(prefix),
michael@0 421 getter_AddRefs(localName), &nameSpaceID);
michael@0 422
michael@0 423 if (nameSpaceID == kNameSpaceID_None) {
michael@0 424 aName.SetTo(localName);
michael@0 425
michael@0 426 return NS_OK;
michael@0 427 }
michael@0 428
michael@0 429 nsCOMPtr<nsINodeInfo> ni;
michael@0 430 ni = mNodeInfoManager->GetNodeInfo(localName, prefix,
michael@0 431 nameSpaceID,
michael@0 432 nsIDOMNode::ATTRIBUTE_NODE);
michael@0 433 aName.SetTo(ni);
michael@0 434
michael@0 435 return NS_OK;
michael@0 436 }
michael@0 437
michael@0 438 nsresult
michael@0 439 XULContentSinkImpl::CreateElement(nsINodeInfo *aNodeInfo,
michael@0 440 nsXULPrototypeElement** aResult)
michael@0 441 {
michael@0 442 nsXULPrototypeElement* element = new nsXULPrototypeElement();
michael@0 443 if (! element)
michael@0 444 return NS_ERROR_OUT_OF_MEMORY;
michael@0 445
michael@0 446 element->mNodeInfo = aNodeInfo;
michael@0 447
michael@0 448 *aResult = element;
michael@0 449 return NS_OK;
michael@0 450 }
michael@0 451
michael@0 452 /**** BEGIN NEW APIs ****/
michael@0 453
michael@0 454
michael@0 455 NS_IMETHODIMP
michael@0 456 XULContentSinkImpl::HandleStartElement(const char16_t *aName,
michael@0 457 const char16_t **aAtts,
michael@0 458 uint32_t aAttsCount,
michael@0 459 int32_t aIndex,
michael@0 460 uint32_t aLineNumber)
michael@0 461 {
michael@0 462 // XXX Hopefully the parser will flag this before we get here. If
michael@0 463 // we're in the epilog, there should be no new elements
michael@0 464 NS_PRECONDITION(mState != eInEpilog, "tag in XUL doc epilog");
michael@0 465 NS_PRECONDITION(aIndex >= -1, "Bogus aIndex");
michael@0 466 NS_PRECONDITION(aAttsCount % 2 == 0, "incorrect aAttsCount");
michael@0 467 // Adjust aAttsCount so it's the actual number of attributes
michael@0 468 aAttsCount /= 2;
michael@0 469
michael@0 470 if (mState == eInEpilog)
michael@0 471 return NS_ERROR_UNEXPECTED;
michael@0 472
michael@0 473 if (mState != eInScript) {
michael@0 474 FlushText();
michael@0 475 }
michael@0 476
michael@0 477 int32_t nameSpaceID;
michael@0 478 nsCOMPtr<nsIAtom> prefix, localName;
michael@0 479 nsContentUtils::SplitExpatName(aName, getter_AddRefs(prefix),
michael@0 480 getter_AddRefs(localName), &nameSpaceID);
michael@0 481
michael@0 482 nsCOMPtr<nsINodeInfo> nodeInfo;
michael@0 483 nodeInfo = mNodeInfoManager->GetNodeInfo(localName, prefix, nameSpaceID,
michael@0 484 nsIDOMNode::ELEMENT_NODE);
michael@0 485
michael@0 486 nsresult rv = NS_OK;
michael@0 487 switch (mState) {
michael@0 488 case eInProlog:
michael@0 489 // We're the root document element
michael@0 490 rv = OpenRoot(aAtts, aAttsCount, nodeInfo);
michael@0 491 break;
michael@0 492
michael@0 493 case eInDocumentElement:
michael@0 494 rv = OpenTag(aAtts, aAttsCount, aLineNumber, nodeInfo);
michael@0 495 break;
michael@0 496
michael@0 497 case eInEpilog:
michael@0 498 case eInScript:
michael@0 499 PR_LOG(gContentSinkLog, PR_LOG_WARNING,
michael@0 500 ("xul: warning: unexpected tags in epilog at line %d",
michael@0 501 aLineNumber));
michael@0 502 rv = NS_ERROR_UNEXPECTED; // XXX
michael@0 503 break;
michael@0 504 }
michael@0 505
michael@0 506 // Set the ID attribute atom on the node info object for this node
michael@0 507 if (aIndex != -1 && NS_SUCCEEDED(rv)) {
michael@0 508 nsCOMPtr<nsIAtom> IDAttr = do_GetAtom(aAtts[aIndex]);
michael@0 509
michael@0 510 if (IDAttr) {
michael@0 511 nodeInfo->SetIDAttributeAtom(IDAttr);
michael@0 512 }
michael@0 513 }
michael@0 514
michael@0 515 return rv;
michael@0 516 }
michael@0 517
michael@0 518 NS_IMETHODIMP
michael@0 519 XULContentSinkImpl::HandleEndElement(const char16_t *aName)
michael@0 520 {
michael@0 521 // Never EVER return anything but NS_OK or
michael@0 522 // NS_ERROR_HTMLPARSER_BLOCK from this method. Doing so will blow
michael@0 523 // the parser's little mind all over the planet.
michael@0 524 nsresult rv;
michael@0 525
michael@0 526 nsRefPtr<nsXULPrototypeNode> node;
michael@0 527 rv = mContextStack.GetTopNode(node);
michael@0 528
michael@0 529 if (NS_FAILED(rv)) {
michael@0 530 return NS_OK;
michael@0 531 }
michael@0 532
michael@0 533 switch (node->mType) {
michael@0 534 case nsXULPrototypeNode::eType_Element: {
michael@0 535 // Flush any text _now_, so that we'll get text nodes created
michael@0 536 // before popping the stack.
michael@0 537 FlushText();
michael@0 538
michael@0 539 // Pop the context stack and do prototype hookup.
michael@0 540 nsPrototypeArray* children = nullptr;
michael@0 541 rv = mContextStack.GetTopChildren(&children);
michael@0 542 if (NS_FAILED(rv)) return rv;
michael@0 543
michael@0 544 nsXULPrototypeElement* element =
michael@0 545 static_cast<nsXULPrototypeElement*>(node.get());
michael@0 546
michael@0 547 int32_t count = children->Length();
michael@0 548 if (count) {
michael@0 549 element->mChildren.SetCapacity(count);
michael@0 550
michael@0 551 for (int32_t i = 0; i < count; ++i)
michael@0 552 element->mChildren.AppendElement(children->ElementAt(i));
michael@0 553
michael@0 554 }
michael@0 555 }
michael@0 556 break;
michael@0 557
michael@0 558 case nsXULPrototypeNode::eType_Script: {
michael@0 559 nsXULPrototypeScript* script =
michael@0 560 static_cast<nsXULPrototypeScript*>(node.get());
michael@0 561
michael@0 562 // If given a src= attribute, we must ignore script tag content.
michael@0 563 if (!script->mSrcURI && !script->GetScriptObject()) {
michael@0 564 nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocument);
michael@0 565
michael@0 566 script->mOutOfLine = false;
michael@0 567 if (doc)
michael@0 568 script->Compile(mText, mTextLength, mDocumentURL,
michael@0 569 script->mLineNo, doc, mPrototype);
michael@0 570 }
michael@0 571
michael@0 572 FlushText(false);
michael@0 573 }
michael@0 574 break;
michael@0 575
michael@0 576 default:
michael@0 577 NS_ERROR("didn't expect that");
michael@0 578 break;
michael@0 579 }
michael@0 580
michael@0 581 rv = mContextStack.Pop(&mState);
michael@0 582 NS_ASSERTION(NS_SUCCEEDED(rv), "context stack corrupted");
michael@0 583 if (NS_FAILED(rv)) return rv;
michael@0 584
michael@0 585 if (mContextStack.Depth() == 0) {
michael@0 586 // The root element should -always- be an element, because
michael@0 587 // it'll have been created via XULContentSinkImpl::OpenRoot().
michael@0 588 NS_ASSERTION(node->mType == nsXULPrototypeNode::eType_Element, "root is not an element");
michael@0 589 if (node->mType != nsXULPrototypeNode::eType_Element)
michael@0 590 return NS_ERROR_UNEXPECTED;
michael@0 591
michael@0 592 // Now that we're done parsing, set the prototype document's
michael@0 593 // root element. This transfers ownership of the prototype
michael@0 594 // element tree to the prototype document.
michael@0 595 nsXULPrototypeElement* element =
michael@0 596 static_cast<nsXULPrototypeElement*>(node.get());
michael@0 597
michael@0 598 mPrototype->SetRootElement(element);
michael@0 599 mState = eInEpilog;
michael@0 600 }
michael@0 601
michael@0 602 return NS_OK;
michael@0 603 }
michael@0 604
michael@0 605 NS_IMETHODIMP
michael@0 606 XULContentSinkImpl::HandleComment(const char16_t *aName)
michael@0 607 {
michael@0 608 FlushText();
michael@0 609 return NS_OK;
michael@0 610 }
michael@0 611
michael@0 612 NS_IMETHODIMP
michael@0 613 XULContentSinkImpl::HandleCDataSection(const char16_t *aData, uint32_t aLength)
michael@0 614 {
michael@0 615 FlushText();
michael@0 616 return AddText(aData, aLength);
michael@0 617 }
michael@0 618
michael@0 619 NS_IMETHODIMP
michael@0 620 XULContentSinkImpl::HandleDoctypeDecl(const nsAString & aSubset,
michael@0 621 const nsAString & aName,
michael@0 622 const nsAString & aSystemId,
michael@0 623 const nsAString & aPublicId,
michael@0 624 nsISupports* aCatalogData)
michael@0 625 {
michael@0 626 return NS_OK;
michael@0 627 }
michael@0 628
michael@0 629 NS_IMETHODIMP
michael@0 630 XULContentSinkImpl::HandleCharacterData(const char16_t *aData,
michael@0 631 uint32_t aLength)
michael@0 632 {
michael@0 633 if (aData && mState != eInProlog && mState != eInEpilog) {
michael@0 634 return AddText(aData, aLength);
michael@0 635 }
michael@0 636 return NS_OK;
michael@0 637 }
michael@0 638
michael@0 639 NS_IMETHODIMP
michael@0 640 XULContentSinkImpl::HandleProcessingInstruction(const char16_t *aTarget,
michael@0 641 const char16_t *aData)
michael@0 642 {
michael@0 643 FlushText();
michael@0 644
michael@0 645 const nsDependentString target(aTarget);
michael@0 646 const nsDependentString data(aData);
michael@0 647
michael@0 648 // Note: the created nsXULPrototypePI has mRefCnt == 1
michael@0 649 nsRefPtr<nsXULPrototypePI> pi = new nsXULPrototypePI();
michael@0 650 if (!pi)
michael@0 651 return NS_ERROR_OUT_OF_MEMORY;
michael@0 652
michael@0 653 pi->mTarget = target;
michael@0 654 pi->mData = data;
michael@0 655
michael@0 656 if (mState == eInProlog) {
michael@0 657 // Note: passing in already addrefed pi
michael@0 658 return mPrototype->AddProcessingInstruction(pi);
michael@0 659 }
michael@0 660
michael@0 661 nsresult rv;
michael@0 662 nsPrototypeArray* children = nullptr;
michael@0 663 rv = mContextStack.GetTopChildren(&children);
michael@0 664 if (NS_FAILED(rv)) {
michael@0 665 return rv;
michael@0 666 }
michael@0 667
michael@0 668 if (!children->AppendElement(pi)) {
michael@0 669 return NS_ERROR_OUT_OF_MEMORY;
michael@0 670 }
michael@0 671
michael@0 672 return NS_OK;
michael@0 673 }
michael@0 674
michael@0 675
michael@0 676 NS_IMETHODIMP
michael@0 677 XULContentSinkImpl::HandleXMLDeclaration(const char16_t *aVersion,
michael@0 678 const char16_t *aEncoding,
michael@0 679 int32_t aStandalone)
michael@0 680 {
michael@0 681 return NS_OK;
michael@0 682 }
michael@0 683
michael@0 684
michael@0 685 NS_IMETHODIMP
michael@0 686 XULContentSinkImpl::ReportError(const char16_t* aErrorText,
michael@0 687 const char16_t* aSourceText,
michael@0 688 nsIScriptError *aError,
michael@0 689 bool *_retval)
michael@0 690 {
michael@0 691 NS_PRECONDITION(aError && aSourceText && aErrorText, "Check arguments!!!");
michael@0 692
michael@0 693 // The expat driver should report the error.
michael@0 694 *_retval = true;
michael@0 695
michael@0 696 nsresult rv = NS_OK;
michael@0 697
michael@0 698 // make sure to empty the context stack so that
michael@0 699 // <parsererror> could become the root element.
michael@0 700 mContextStack.Clear();
michael@0 701
michael@0 702 mState = eInProlog;
michael@0 703
michael@0 704 // Clear any buffered-up text we have. It's enough to set the length to 0.
michael@0 705 // The buffer itself is allocated when we're created and deleted in our
michael@0 706 // destructor, so don't mess with it.
michael@0 707 mTextLength = 0;
michael@0 708
michael@0 709 nsCOMPtr<nsIXULDocument> doc = do_QueryReferent(mDocument);
michael@0 710 if (doc && !doc->OnDocumentParserError()) {
michael@0 711 // The overlay was broken. Don't add a messy element to the master doc.
michael@0 712 return NS_OK;
michael@0 713 }
michael@0 714
michael@0 715 const char16_t* noAtts[] = { 0, 0 };
michael@0 716
michael@0 717 NS_NAMED_LITERAL_STRING(errorNs,
michael@0 718 "http://www.mozilla.org/newlayout/xml/parsererror.xml");
michael@0 719
michael@0 720 nsAutoString parsererror(errorNs);
michael@0 721 parsererror.Append((char16_t)0xFFFF);
michael@0 722 parsererror.AppendLiteral("parsererror");
michael@0 723
michael@0 724 rv = HandleStartElement(parsererror.get(), noAtts, 0, -1, 0);
michael@0 725 NS_ENSURE_SUCCESS(rv,rv);
michael@0 726
michael@0 727 rv = HandleCharacterData(aErrorText, NS_strlen(aErrorText));
michael@0 728 NS_ENSURE_SUCCESS(rv,rv);
michael@0 729
michael@0 730 nsAutoString sourcetext(errorNs);
michael@0 731 sourcetext.Append((char16_t)0xFFFF);
michael@0 732 sourcetext.AppendLiteral("sourcetext");
michael@0 733
michael@0 734 rv = HandleStartElement(sourcetext.get(), noAtts, 0, -1, 0);
michael@0 735 NS_ENSURE_SUCCESS(rv,rv);
michael@0 736
michael@0 737 rv = HandleCharacterData(aSourceText, NS_strlen(aSourceText));
michael@0 738 NS_ENSURE_SUCCESS(rv,rv);
michael@0 739
michael@0 740 rv = HandleEndElement(sourcetext.get());
michael@0 741 NS_ENSURE_SUCCESS(rv,rv);
michael@0 742
michael@0 743 rv = HandleEndElement(parsererror.get());
michael@0 744 NS_ENSURE_SUCCESS(rv,rv);
michael@0 745
michael@0 746 return rv;
michael@0 747 }
michael@0 748
michael@0 749 nsresult
michael@0 750 XULContentSinkImpl::OpenRoot(const char16_t** aAttributes,
michael@0 751 const uint32_t aAttrLen,
michael@0 752 nsINodeInfo *aNodeInfo)
michael@0 753 {
michael@0 754 NS_ASSERTION(mState == eInProlog, "how'd we get here?");
michael@0 755 if (mState != eInProlog)
michael@0 756 return NS_ERROR_UNEXPECTED;
michael@0 757
michael@0 758 nsresult rv;
michael@0 759
michael@0 760 if (aNodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_XHTML) ||
michael@0 761 aNodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_XUL)) {
michael@0 762 PR_LOG(gContentSinkLog, PR_LOG_ERROR,
michael@0 763 ("xul: script tag not allowed as root content element"));
michael@0 764
michael@0 765 return NS_ERROR_UNEXPECTED;
michael@0 766 }
michael@0 767
michael@0 768 // Create the element
michael@0 769 nsXULPrototypeElement* element;
michael@0 770 rv = CreateElement(aNodeInfo, &element);
michael@0 771
michael@0 772 if (NS_FAILED(rv)) {
michael@0 773 #ifdef PR_LOGGING
michael@0 774 if (PR_LOG_TEST(gContentSinkLog, PR_LOG_ERROR)) {
michael@0 775 nsAutoString anodeC;
michael@0 776 aNodeInfo->GetName(anodeC);
michael@0 777 PR_LOG(gContentSinkLog, PR_LOG_ERROR,
michael@0 778 ("xul: unable to create element '%s' at line %d",
michael@0 779 NS_ConvertUTF16toUTF8(anodeC).get(),
michael@0 780 -1)); // XXX pass in line number
michael@0 781 }
michael@0 782 #endif
michael@0 783
michael@0 784 return rv;
michael@0 785 }
michael@0 786
michael@0 787 // Push the element onto the context stack, so that child
michael@0 788 // containers will hook up to us as their parent.
michael@0 789 rv = mContextStack.Push(element, mState);
michael@0 790 if (NS_FAILED(rv)) {
michael@0 791 element->Release();
michael@0 792 return rv;
michael@0 793 }
michael@0 794
michael@0 795 // Add the attributes
michael@0 796 rv = AddAttributes(aAttributes, aAttrLen, element);
michael@0 797 if (NS_FAILED(rv)) return rv;
michael@0 798
michael@0 799 mState = eInDocumentElement;
michael@0 800 return NS_OK;
michael@0 801 }
michael@0 802
michael@0 803 nsresult
michael@0 804 XULContentSinkImpl::OpenTag(const char16_t** aAttributes,
michael@0 805 const uint32_t aAttrLen,
michael@0 806 const uint32_t aLineNumber,
michael@0 807 nsINodeInfo *aNodeInfo)
michael@0 808 {
michael@0 809 nsresult rv;
michael@0 810
michael@0 811 // Create the element
michael@0 812 nsXULPrototypeElement* element;
michael@0 813 rv = CreateElement(aNodeInfo, &element);
michael@0 814
michael@0 815 if (NS_FAILED(rv)) {
michael@0 816 #ifdef PR_LOGGING
michael@0 817 if (PR_LOG_TEST(gContentSinkLog, PR_LOG_ERROR)) {
michael@0 818 nsAutoString anodeC;
michael@0 819 aNodeInfo->GetName(anodeC);
michael@0 820 PR_LOG(gContentSinkLog, PR_LOG_ERROR,
michael@0 821 ("xul: unable to create element '%s' at line %d",
michael@0 822 NS_ConvertUTF16toUTF8(anodeC).get(),
michael@0 823 aLineNumber));
michael@0 824 }
michael@0 825 #endif
michael@0 826
michael@0 827 return rv;
michael@0 828 }
michael@0 829
michael@0 830 // Link this element to its parent.
michael@0 831 nsPrototypeArray* children = nullptr;
michael@0 832 rv = mContextStack.GetTopChildren(&children);
michael@0 833 if (NS_FAILED(rv)) {
michael@0 834 delete element;
michael@0 835 return rv;
michael@0 836 }
michael@0 837
michael@0 838 // Add the attributes
michael@0 839 rv = AddAttributes(aAttributes, aAttrLen, element);
michael@0 840 if (NS_FAILED(rv)) return rv;
michael@0 841
michael@0 842 children->AppendElement(element);
michael@0 843
michael@0 844 if (aNodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_XHTML) ||
michael@0 845 aNodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_XUL)) {
michael@0 846 // Do scripty things now
michael@0 847 rv = OpenScript(aAttributes, aLineNumber);
michael@0 848 NS_ENSURE_SUCCESS(rv, rv);
michael@0 849
michael@0 850 NS_ASSERTION(mState == eInScript || mState == eInDocumentElement,
michael@0 851 "Unexpected state");
michael@0 852 if (mState == eInScript) {
michael@0 853 // OpenScript has pushed the nsPrototypeScriptElement onto the
michael@0 854 // stack, so we're done.
michael@0 855 return NS_OK;
michael@0 856 }
michael@0 857 }
michael@0 858
michael@0 859 // Push the element onto the context stack, so that child
michael@0 860 // containers will hook up to us as their parent.
michael@0 861 rv = mContextStack.Push(element, mState);
michael@0 862 if (NS_FAILED(rv)) return rv;
michael@0 863
michael@0 864 mState = eInDocumentElement;
michael@0 865 return NS_OK;
michael@0 866 }
michael@0 867
michael@0 868 nsresult
michael@0 869 XULContentSinkImpl::OpenScript(const char16_t** aAttributes,
michael@0 870 const uint32_t aLineNumber)
michael@0 871 {
michael@0 872 uint32_t langID = nsIProgrammingLanguage::JAVASCRIPT;
michael@0 873 uint32_t version = JSVERSION_LATEST;
michael@0 874 nsresult rv;
michael@0 875
michael@0 876 // Look for SRC attribute and look for a LANGUAGE attribute
michael@0 877 nsAutoString src;
michael@0 878 while (*aAttributes) {
michael@0 879 const nsDependentString key(aAttributes[0]);
michael@0 880 if (key.EqualsLiteral("src")) {
michael@0 881 src.Assign(aAttributes[1]);
michael@0 882 }
michael@0 883 else if (key.EqualsLiteral("type")) {
michael@0 884 nsDependentString str(aAttributes[1]);
michael@0 885 nsContentTypeParser parser(str);
michael@0 886 nsAutoString mimeType;
michael@0 887 rv = parser.GetType(mimeType);
michael@0 888 if (NS_FAILED(rv)) {
michael@0 889 if (rv == NS_ERROR_INVALID_ARG) {
michael@0 890 // Might as well bail out now instead of setting langID to
michael@0 891 // nsIProgrammingLanguage::UNKNOWN and bailing out later.
michael@0 892 return NS_OK;
michael@0 893 }
michael@0 894 // We do want the warning here
michael@0 895 NS_ENSURE_SUCCESS(rv, rv);
michael@0 896 }
michael@0 897
michael@0 898 if (nsContentUtils::IsJavascriptMIMEType(mimeType)) {
michael@0 899 langID = nsIProgrammingLanguage::JAVASCRIPT;
michael@0 900 version = JSVERSION_LATEST;
michael@0 901 } else {
michael@0 902 langID = nsIProgrammingLanguage::UNKNOWN;
michael@0 903 }
michael@0 904
michael@0 905 if (langID != nsIProgrammingLanguage::UNKNOWN) {
michael@0 906 // Get the version string, and ensure the language supports it.
michael@0 907 nsAutoString versionName;
michael@0 908 rv = parser.GetParameter("version", versionName);
michael@0 909
michael@0 910 if (NS_SUCCEEDED(rv)) {
michael@0 911 version = nsContentUtils::ParseJavascriptVersion(versionName);
michael@0 912 } else if (rv != NS_ERROR_INVALID_ARG) {
michael@0 913 return rv;
michael@0 914 }
michael@0 915 }
michael@0 916 }
michael@0 917 else if (key.EqualsLiteral("language")) {
michael@0 918 // Language is deprecated, and the impl in nsScriptLoader ignores the
michael@0 919 // various version strings anyway. So we make no attempt to support
michael@0 920 // languages other than JS for language=
michael@0 921 nsAutoString lang(aAttributes[1]);
michael@0 922 if (nsContentUtils::IsJavaScriptLanguage(lang)) {
michael@0 923 version = JSVERSION_DEFAULT;
michael@0 924 langID = nsIProgrammingLanguage::JAVASCRIPT;
michael@0 925 }
michael@0 926 }
michael@0 927 aAttributes += 2;
michael@0 928 }
michael@0 929
michael@0 930 // Not all script languages have a "sandbox" concept. At time of
michael@0 931 // writing, Python is the only other language, and it does not.
michael@0 932 // For such languages, neither any inline script nor remote script are
michael@0 933 // safe to execute from untrusted sources.
michael@0 934 // So for such languages, we only allow script when the document
michael@0 935 // itself is from chrome. We then don't bother to check the
michael@0 936 // "src=" tag - we trust chrome to do the right thing.
michael@0 937 // (See also similar code in nsScriptLoader.cpp)
michael@0 938 nsCOMPtr<nsIDocument> doc(do_QueryReferent(mDocument));
michael@0 939 if (langID != nsIProgrammingLanguage::UNKNOWN &&
michael@0 940 langID != nsIProgrammingLanguage::JAVASCRIPT &&
michael@0 941 doc && !nsContentUtils::IsChromeDoc(doc)) {
michael@0 942 langID = nsIProgrammingLanguage::UNKNOWN;
michael@0 943 NS_WARNING("Non JS language called from non chrome - ignored");
michael@0 944 }
michael@0 945
michael@0 946 // Don't process scripts that aren't known
michael@0 947 if (langID != nsIProgrammingLanguage::UNKNOWN) {
michael@0 948 nsCOMPtr<nsIScriptGlobalObject> globalObject;
michael@0 949 if (doc)
michael@0 950 globalObject = do_QueryInterface(doc->GetWindow());
michael@0 951 nsRefPtr<nsXULPrototypeScript> script =
michael@0 952 new nsXULPrototypeScript(aLineNumber, version);
michael@0 953 if (! script)
michael@0 954 return NS_ERROR_OUT_OF_MEMORY;
michael@0 955
michael@0 956 // If there is a SRC attribute...
michael@0 957 if (! src.IsEmpty()) {
michael@0 958 // Use the SRC attribute value to load the URL
michael@0 959 rv = NS_NewURI(getter_AddRefs(script->mSrcURI), src, nullptr, mDocumentURL);
michael@0 960
michael@0 961 // Check if this document is allowed to load a script from this source
michael@0 962 // NOTE: if we ever allow scripts added via the DOM to run, we need to
michael@0 963 // add a CheckLoadURI call for that as well.
michael@0 964 if (NS_SUCCEEDED(rv)) {
michael@0 965 if (!mSecMan)
michael@0 966 mSecMan = do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
michael@0 967 if (NS_SUCCEEDED(rv)) {
michael@0 968 nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocument, &rv);
michael@0 969
michael@0 970 if (NS_SUCCEEDED(rv)) {
michael@0 971 rv = mSecMan->
michael@0 972 CheckLoadURIWithPrincipal(doc->NodePrincipal(),
michael@0 973 script->mSrcURI,
michael@0 974 nsIScriptSecurityManager::ALLOW_CHROME);
michael@0 975 }
michael@0 976 }
michael@0 977 }
michael@0 978
michael@0 979 if (NS_FAILED(rv)) {
michael@0 980 return rv;
michael@0 981 }
michael@0 982
michael@0 983 // Attempt to deserialize an out-of-line script from the FastLoad
michael@0 984 // file right away. Otherwise we'll end up reloading the script and
michael@0 985 // corrupting the FastLoad file trying to serialize it, in the case
michael@0 986 // where it's already there.
michael@0 987 script->DeserializeOutOfLine(nullptr, mPrototype);
michael@0 988 }
michael@0 989
michael@0 990 nsPrototypeArray* children = nullptr;
michael@0 991 rv = mContextStack.GetTopChildren(&children);
michael@0 992 if (NS_FAILED(rv)) {
michael@0 993 return rv;
michael@0 994 }
michael@0 995
michael@0 996 children->AppendElement(script);
michael@0 997
michael@0 998 mConstrainSize = false;
michael@0 999
michael@0 1000 mContextStack.Push(script, mState);
michael@0 1001 mState = eInScript;
michael@0 1002 }
michael@0 1003
michael@0 1004 return NS_OK;
michael@0 1005 }
michael@0 1006
michael@0 1007 nsresult
michael@0 1008 XULContentSinkImpl::AddAttributes(const char16_t** aAttributes,
michael@0 1009 const uint32_t aAttrLen,
michael@0 1010 nsXULPrototypeElement* aElement)
michael@0 1011 {
michael@0 1012 // Add tag attributes to the element
michael@0 1013 nsresult rv;
michael@0 1014
michael@0 1015 // Create storage for the attributes
michael@0 1016 nsXULPrototypeAttribute* attrs = nullptr;
michael@0 1017 if (aAttrLen > 0) {
michael@0 1018 attrs = new nsXULPrototypeAttribute[aAttrLen];
michael@0 1019 if (! attrs)
michael@0 1020 return NS_ERROR_OUT_OF_MEMORY;
michael@0 1021 }
michael@0 1022
michael@0 1023 aElement->mAttributes = attrs;
michael@0 1024 aElement->mNumAttributes = aAttrLen;
michael@0 1025
michael@0 1026 // Copy the attributes into the prototype
michael@0 1027 uint32_t i;
michael@0 1028 for (i = 0; i < aAttrLen; ++i) {
michael@0 1029 rv = NormalizeAttributeString(aAttributes[i * 2], attrs[i].mName);
michael@0 1030 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1031
michael@0 1032 rv = aElement->SetAttrAt(i, nsDependentString(aAttributes[i * 2 + 1]),
michael@0 1033 mDocumentURL);
michael@0 1034 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1035
michael@0 1036 #ifdef PR_LOGGING
michael@0 1037 if (PR_LOG_TEST(gContentSinkLog, PR_LOG_DEBUG)) {
michael@0 1038 nsAutoString extraWhiteSpace;
michael@0 1039 int32_t cnt = mContextStack.Depth();
michael@0 1040 while (--cnt >= 0)
michael@0 1041 extraWhiteSpace.AppendLiteral(" ");
michael@0 1042 nsAutoString qnameC,valueC;
michael@0 1043 qnameC.Assign(aAttributes[0]);
michael@0 1044 valueC.Assign(aAttributes[1]);
michael@0 1045 PR_LOG(gContentSinkLog, PR_LOG_DEBUG,
michael@0 1046 ("xul: %.5d. %s %s=%s",
michael@0 1047 -1, // XXX pass in line number
michael@0 1048 NS_ConvertUTF16toUTF8(extraWhiteSpace).get(),
michael@0 1049 NS_ConvertUTF16toUTF8(qnameC).get(),
michael@0 1050 NS_ConvertUTF16toUTF8(valueC).get()));
michael@0 1051 }
michael@0 1052 #endif
michael@0 1053 }
michael@0 1054
michael@0 1055 return NS_OK;
michael@0 1056 }
michael@0 1057
michael@0 1058 nsresult
michael@0 1059 XULContentSinkImpl::AddText(const char16_t* aText,
michael@0 1060 int32_t aLength)
michael@0 1061 {
michael@0 1062 // Create buffer when we first need it
michael@0 1063 if (0 == mTextSize) {
michael@0 1064 mText = (char16_t *) moz_malloc(sizeof(char16_t) * 4096);
michael@0 1065 if (nullptr == mText) {
michael@0 1066 return NS_ERROR_OUT_OF_MEMORY;
michael@0 1067 }
michael@0 1068 mTextSize = 4096;
michael@0 1069 }
michael@0 1070
michael@0 1071 // Copy data from string into our buffer; flush buffer when it fills up
michael@0 1072 int32_t offset = 0;
michael@0 1073 while (0 != aLength) {
michael@0 1074 int32_t amount = mTextSize - mTextLength;
michael@0 1075 if (amount > aLength) {
michael@0 1076 amount = aLength;
michael@0 1077 }
michael@0 1078 if (0 == amount) {
michael@0 1079 if (mConstrainSize) {
michael@0 1080 nsresult rv = FlushText();
michael@0 1081 if (NS_OK != rv) {
michael@0 1082 return rv;
michael@0 1083 }
michael@0 1084 }
michael@0 1085 else {
michael@0 1086 mTextSize += aLength;
michael@0 1087 mText = (char16_t *) moz_realloc(mText, sizeof(char16_t) * mTextSize);
michael@0 1088 if (nullptr == mText) {
michael@0 1089 return NS_ERROR_OUT_OF_MEMORY;
michael@0 1090 }
michael@0 1091 }
michael@0 1092 }
michael@0 1093 memcpy(&mText[mTextLength],aText + offset, sizeof(char16_t) * amount);
michael@0 1094
michael@0 1095 mTextLength += amount;
michael@0 1096 offset += amount;
michael@0 1097 aLength -= amount;
michael@0 1098 }
michael@0 1099
michael@0 1100 return NS_OK;
michael@0 1101 }

mercurial