txStylesheetCompiler.cpp (26632B)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6 #include "txStylesheetCompiler.h" 7 8 #include <utility> 9 10 #include "mozilla/UniquePtr.h" 11 #include "nsGkAtoms.h" 12 #include "nsServiceManagerUtils.h" 13 #include "nsTArray.h" 14 #include "nsWhitespaceTokenizer.h" 15 #include "txExprParser.h" 16 #include "txInstructions.h" 17 #include "txLog.h" 18 #include "txPatternParser.h" 19 #include "txStringUtils.h" 20 #include "txStylesheet.h" 21 #include "txStylesheetCompileHandlers.h" 22 #include "txToplevelItems.h" 23 #include "txURIUtils.h" 24 #include "txXSLTFunctions.h" 25 26 using namespace mozilla; 27 using mozilla::dom::ReferrerPolicy; 28 29 txStylesheetCompiler::txStylesheetCompiler(const nsAString& aStylesheetURI, 30 ReferrerPolicy aReferrerPolicy, 31 txACompileObserver* aObserver) 32 : txStylesheetCompilerState(aObserver) { 33 mStatus = init(aStylesheetURI, aReferrerPolicy, nullptr, nullptr); 34 } 35 36 txStylesheetCompiler::txStylesheetCompiler(const nsAString& aStylesheetURI, 37 txStylesheet* aStylesheet, 38 txListIterator* aInsertPosition, 39 ReferrerPolicy aReferrerPolicy, 40 txACompileObserver* aObserver) 41 : txStylesheetCompilerState(aObserver) { 42 mStatus = init(aStylesheetURI, aReferrerPolicy, aStylesheet, aInsertPosition); 43 } 44 45 void txStylesheetCompiler::setBaseURI(const nsString& aBaseURI) { 46 NS_ASSERTION(mObjectStack.size() == 1 && !mObjectStack.peek(), 47 "Execution already started"); 48 49 if (NS_FAILED(mStatus)) { 50 return; 51 } 52 53 mElementContext->mBaseURI = aBaseURI; 54 } 55 56 nsresult txStylesheetCompiler::startElement(int32_t aNamespaceID, 57 nsAtom* aLocalName, nsAtom* aPrefix, 58 txStylesheetAttr* aAttributes, 59 int32_t aAttrCount) { 60 if (NS_FAILED(mStatus)) { 61 // ignore content after failure 62 // XXX reevaluate once expat stops on failure 63 return NS_OK; 64 } 65 66 nsresult rv = flushCharacters(); 67 NS_ENSURE_SUCCESS(rv, rv); 68 69 // look for new namespace mappings 70 bool hasOwnNamespaceMap = false; 71 int32_t i; 72 for (i = 0; i < aAttrCount; ++i) { 73 txStylesheetAttr* attr = aAttributes + i; 74 if (attr->mNamespaceID == kNameSpaceID_XMLNS) { 75 rv = ensureNewElementContext(); 76 NS_ENSURE_SUCCESS(rv, rv); 77 78 if (!hasOwnNamespaceMap) { 79 mElementContext->mMappings = 80 new txNamespaceMap(*mElementContext->mMappings); 81 hasOwnNamespaceMap = true; 82 } 83 84 if (attr->mLocalName == nsGkAtoms::xmlns) { 85 mElementContext->mMappings->mapNamespace(nullptr, attr->mValue); 86 } else { 87 mElementContext->mMappings->mapNamespace(attr->mLocalName, 88 attr->mValue); 89 } 90 } 91 } 92 93 return startElementInternal(aNamespaceID, aLocalName, aPrefix, aAttributes, 94 aAttrCount); 95 } 96 97 nsresult txStylesheetCompiler::startElement(const char16_t* aName, 98 const char16_t** aAttrs, 99 int32_t aAttrCount) { 100 if (NS_FAILED(mStatus)) { 101 // ignore content after failure 102 // XXX reevaluate once expat stops on failure 103 return NS_OK; 104 } 105 106 nsresult rv = flushCharacters(); 107 NS_ENSURE_SUCCESS(rv, rv); 108 109 UniquePtr<txStylesheetAttr[]> atts; 110 if (aAttrCount > 0) { 111 atts = MakeUnique<txStylesheetAttr[]>(aAttrCount); 112 } 113 114 bool hasOwnNamespaceMap = false; 115 int32_t i; 116 for (i = 0; i < aAttrCount; ++i) { 117 rv = XMLUtils::splitExpatName( 118 aAttrs[i * 2], getter_AddRefs(atts[i].mPrefix), 119 getter_AddRefs(atts[i].mLocalName), &atts[i].mNamespaceID); 120 NS_ENSURE_SUCCESS(rv, rv); 121 atts[i].mValue.Append(aAttrs[i * 2 + 1]); 122 123 RefPtr<nsAtom> prefixToBind; 124 if (atts[i].mPrefix == nsGkAtoms::xmlns) { 125 prefixToBind = atts[i].mLocalName; 126 } else if (atts[i].mNamespaceID == kNameSpaceID_XMLNS) { 127 prefixToBind = nsGkAtoms::_empty; 128 } 129 130 if (prefixToBind) { 131 rv = ensureNewElementContext(); 132 NS_ENSURE_SUCCESS(rv, rv); 133 134 if (!hasOwnNamespaceMap) { 135 mElementContext->mMappings = 136 new txNamespaceMap(*mElementContext->mMappings); 137 hasOwnNamespaceMap = true; 138 } 139 140 rv = mElementContext->mMappings->mapNamespace(prefixToBind, 141 atts[i].mValue); 142 NS_ENSURE_SUCCESS(rv, rv); 143 } 144 } 145 146 RefPtr<nsAtom> prefix, localname; 147 int32_t namespaceID; 148 rv = XMLUtils::splitExpatName(aName, getter_AddRefs(prefix), 149 getter_AddRefs(localname), &namespaceID); 150 NS_ENSURE_SUCCESS(rv, rv); 151 152 return startElementInternal(namespaceID, localname, prefix, atts.get(), 153 aAttrCount); 154 } 155 156 nsresult txStylesheetCompiler::startElementInternal( 157 int32_t aNamespaceID, nsAtom* aLocalName, nsAtom* aPrefix, 158 txStylesheetAttr* aAttributes, int32_t aAttrCount) { 159 nsresult rv = NS_OK; 160 int32_t i; 161 for (i = mInScopeVariables.Length() - 1; i >= 0; --i) { 162 ++mInScopeVariables[i].mLevel; 163 } 164 165 // Update the elementcontext if we have special attributes 166 for (i = 0; i < aAttrCount; ++i) { 167 txStylesheetAttr* attr = aAttributes + i; 168 169 // id 170 if (mEmbedStatus == eNeedEmbed && attr->mLocalName == nsGkAtoms::id && 171 attr->mNamespaceID == kNameSpaceID_None && 172 attr->mValue.Equals(mTarget)) { 173 // We found the right ID, signal to compile the 174 // embedded stylesheet. 175 mEmbedStatus = eInEmbed; 176 } 177 178 // xml:space 179 if (attr->mNamespaceID == kNameSpaceID_XML && 180 attr->mLocalName == nsGkAtoms::space) { 181 rv = ensureNewElementContext(); 182 NS_ENSURE_SUCCESS(rv, rv); 183 184 if (TX_StringEqualsAtom(attr->mValue, nsGkAtoms::preserve)) { 185 mElementContext->mPreserveWhitespace = true; 186 } else if (TX_StringEqualsAtom(attr->mValue, nsGkAtoms::_default)) { 187 mElementContext->mPreserveWhitespace = false; 188 } else { 189 return NS_ERROR_XSLT_PARSE_FAILURE; 190 } 191 } 192 193 // extension-element-prefixes 194 if ((attr->mNamespaceID == kNameSpaceID_XSLT && 195 attr->mLocalName == nsGkAtoms::extensionElementPrefixes && 196 aNamespaceID != kNameSpaceID_XSLT) || 197 (attr->mNamespaceID == kNameSpaceID_None && 198 attr->mLocalName == nsGkAtoms::extensionElementPrefixes && 199 aNamespaceID == kNameSpaceID_XSLT && 200 (aLocalName == nsGkAtoms::stylesheet || 201 aLocalName == nsGkAtoms::transform))) { 202 rv = ensureNewElementContext(); 203 NS_ENSURE_SUCCESS(rv, rv); 204 205 nsWhitespaceTokenizer tok(attr->mValue); 206 while (tok.hasMoreTokens()) { 207 int32_t namespaceID = 208 mElementContext->mMappings->lookupNamespaceWithDefault( 209 tok.nextToken()); 210 211 if (namespaceID == kNameSpaceID_Unknown) 212 return NS_ERROR_XSLT_PARSE_FAILURE; 213 214 mElementContext->mInstructionNamespaces.AppendElement(namespaceID); 215 } 216 217 attr->mLocalName = nullptr; 218 } 219 220 // version 221 if ((attr->mNamespaceID == kNameSpaceID_XSLT && 222 attr->mLocalName == nsGkAtoms::version && 223 aNamespaceID != kNameSpaceID_XSLT) || 224 (attr->mNamespaceID == kNameSpaceID_None && 225 attr->mLocalName == nsGkAtoms::version && 226 aNamespaceID == kNameSpaceID_XSLT && 227 (aLocalName == nsGkAtoms::stylesheet || 228 aLocalName == nsGkAtoms::transform))) { 229 rv = ensureNewElementContext(); 230 NS_ENSURE_SUCCESS(rv, rv); 231 232 if (attr->mValue.EqualsLiteral("1.0")) { 233 mElementContext->mForwardsCompatibleParsing = false; 234 } else { 235 mElementContext->mForwardsCompatibleParsing = true; 236 } 237 } 238 } 239 240 // Find the right elementhandler and execute it 241 bool isInstruction = false; 242 int32_t count = mElementContext->mInstructionNamespaces.Length(); 243 for (i = 0; i < count; ++i) { 244 if (mElementContext->mInstructionNamespaces[i] == aNamespaceID) { 245 isInstruction = true; 246 break; 247 } 248 } 249 250 const txElementHandler* handler; 251 do { 252 handler = isInstruction ? mHandlerTable->find(aNamespaceID, aLocalName) 253 : mHandlerTable->mLREHandler; 254 255 rv = (handler->mStartFunction)(aNamespaceID, aLocalName, aPrefix, 256 aAttributes, aAttrCount, *this); 257 } while (rv == NS_XSLT_GET_NEW_HANDLER); 258 259 NS_ENSURE_SUCCESS(rv, rv); 260 261 if (!fcp()) { 262 for (i = 0; i < aAttrCount; ++i) { 263 txStylesheetAttr& attr = aAttributes[i]; 264 if (attr.mLocalName && (attr.mNamespaceID == kNameSpaceID_XSLT || 265 (aNamespaceID == kNameSpaceID_XSLT && 266 attr.mNamespaceID == kNameSpaceID_None))) { 267 // XXX ErrorReport: unknown attribute 268 return NS_ERROR_XSLT_PARSE_FAILURE; 269 } 270 } 271 } 272 273 pushPtr(const_cast<txElementHandler*>(handler), eElementHandler); 274 275 mElementContext->mDepth++; 276 277 return NS_OK; 278 } 279 280 nsresult txStylesheetCompiler::endElement() { 281 if (NS_FAILED(mStatus)) { 282 // ignore content after failure 283 // XXX reevaluate once expat stops on failure 284 return NS_OK; 285 } 286 287 nsresult rv = flushCharacters(); 288 NS_ENSURE_SUCCESS(rv, rv); 289 290 int32_t i; 291 for (i = mInScopeVariables.Length() - 1; i >= 0; --i) { 292 txInScopeVariable& var = mInScopeVariables[i]; 293 if (!--(var.mLevel)) { 294 addInstruction(MakeUnique<txRemoveVariable>(var.mName)); 295 296 mInScopeVariables.RemoveElementAt(i); 297 } 298 } 299 300 const txElementHandler* handler = const_cast<const txElementHandler*>( 301 static_cast<txElementHandler*>(popPtr(eElementHandler))); 302 (handler->mEndFunction)(*this); 303 304 if (!--mElementContext->mDepth) { 305 // this will delete the old object 306 mElementContext = WrapUnique(static_cast<txElementContext*>(popObject())); 307 } 308 309 return NS_OK; 310 } 311 312 nsresult txStylesheetCompiler::characters(const nsAString& aStr) { 313 if (NS_FAILED(mStatus)) { 314 // ignore content after failure 315 // XXX reevaluate once expat stops on failure 316 return NS_OK; 317 } 318 319 mCharacters.Append(aStr); 320 321 return NS_OK; 322 } 323 324 nsresult txStylesheetCompiler::doneLoading() { 325 MOZ_LOG(txLog::xslt, LogLevel::Info, 326 ("Compiler::doneLoading: %s\n", 327 NS_LossyConvertUTF16toASCII(mStylesheetURI).get())); 328 if (NS_FAILED(mStatus)) { 329 return mStatus; 330 } 331 332 mDoneWithThisStylesheet = true; 333 334 return maybeDoneCompiling(); 335 } 336 337 void txStylesheetCompiler::cancel(nsresult aError, const char16_t* aErrorText, 338 const char16_t* aParam) { 339 MOZ_LOG(txLog::xslt, LogLevel::Info, 340 ("Compiler::cancel: %s, module: %d, code %d\n", 341 NS_LossyConvertUTF16toASCII(mStylesheetURI).get(), 342 NS_ERROR_GET_MODULE(aError), NS_ERROR_GET_CODE(aError))); 343 if (NS_SUCCEEDED(mStatus)) { 344 mStatus = aError; 345 } 346 347 if (mObserver) { 348 mObserver->onDoneCompiling(this, mStatus, aErrorText, aParam); 349 // This will ensure that we don't call onDoneCompiling twice. Also 350 // ensures that we don't keep the observer alive longer then necessary. 351 mObserver = nullptr; 352 } 353 } 354 355 txStylesheet* txStylesheetCompiler::getStylesheet() { return mStylesheet; } 356 357 nsresult txStylesheetCompiler::loadURI(const nsAString& aUri, 358 const nsAString& aReferrerUri, 359 ReferrerPolicy aReferrerPolicy, 360 txStylesheetCompiler* aCompiler) { 361 MOZ_LOG(txLog::xslt, LogLevel::Info, 362 ("Compiler::loadURI forwards %s thru %s\n", 363 NS_LossyConvertUTF16toASCII(aUri).get(), 364 NS_LossyConvertUTF16toASCII(mStylesheetURI).get())); 365 if (mStylesheetURI.Equals(aUri)) { 366 return NS_ERROR_XSLT_LOAD_RECURSION; 367 } 368 return mObserver ? mObserver->loadURI(aUri, aReferrerUri, aReferrerPolicy, 369 aCompiler) 370 : NS_ERROR_FAILURE; 371 } 372 373 void txStylesheetCompiler::onDoneCompiling(txStylesheetCompiler* aCompiler, 374 nsresult aResult, 375 const char16_t* aErrorText, 376 const char16_t* aParam) { 377 if (NS_FAILED(aResult)) { 378 cancel(aResult, aErrorText, aParam); 379 return; 380 } 381 382 mChildCompilerList.RemoveElement(aCompiler); 383 384 maybeDoneCompiling(); 385 } 386 387 nsresult txStylesheetCompiler::flushCharacters() { 388 // Bail if we don't have any characters. The handler will detect 389 // ignoreable whitespace 390 if (mCharacters.IsEmpty()) { 391 return NS_OK; 392 } 393 394 nsresult rv = NS_OK; 395 396 do { 397 rv = (mHandlerTable->mTextHandler)(mCharacters, *this); 398 } while (rv == NS_XSLT_GET_NEW_HANDLER); 399 400 NS_ENSURE_SUCCESS(rv, rv); 401 402 mCharacters.Truncate(); 403 404 return NS_OK; 405 } 406 407 nsresult txStylesheetCompiler::ensureNewElementContext() { 408 // Do we already have a new context? 409 if (!mElementContext->mDepth) { 410 return NS_OK; 411 } 412 413 UniquePtr<txElementContext> context(new txElementContext(*mElementContext)); 414 pushObject(mElementContext.release()); 415 mElementContext = std::move(context); 416 417 return NS_OK; 418 } 419 420 nsresult txStylesheetCompiler::maybeDoneCompiling() { 421 if (!mDoneWithThisStylesheet || !mChildCompilerList.IsEmpty()) { 422 return NS_OK; 423 } 424 425 if (mIsTopCompiler) { 426 nsresult rv = mStylesheet->doneCompiling(); 427 if (NS_FAILED(rv)) { 428 cancel(rv); 429 return rv; 430 } 431 } 432 433 if (mObserver) { 434 mObserver->onDoneCompiling(this, mStatus); 435 // This will ensure that we don't call onDoneCompiling twice. Also 436 // ensures that we don't keep the observer alive longer then necessary. 437 mObserver = nullptr; 438 } 439 440 return NS_OK; 441 } 442 443 /** 444 * txStylesheetCompilerState 445 */ 446 447 txStylesheetCompilerState::txStylesheetCompilerState( 448 txACompileObserver* aObserver) 449 : mHandlerTable(nullptr), 450 mSorter(nullptr), 451 mDOE(false), 452 mSearchingForFallback(false), 453 mDisAllowed(0), 454 mObserver(aObserver), 455 mEmbedStatus(eNoEmbed), 456 mIsTopCompiler(false), 457 mDoneWithThisStylesheet(false), 458 mNextInstrPtr(nullptr), 459 mToplevelIterator(nullptr), 460 mReferrerPolicy(ReferrerPolicy::_empty) { 461 // Embedded stylesheets have another handler, which is set in 462 // txStylesheetCompiler::init if the baseURI has a fragment identifier. 463 mHandlerTable = gTxRootHandler; 464 } 465 466 nsresult txStylesheetCompilerState::init(const nsAString& aStylesheetURI, 467 ReferrerPolicy aReferrerPolicy, 468 txStylesheet* aStylesheet, 469 txListIterator* aInsertPosition) { 470 NS_ASSERTION(!aStylesheet || aInsertPosition, 471 "must provide insertposition if loading subsheet"); 472 mStylesheetURI = aStylesheetURI; 473 mReferrerPolicy = aReferrerPolicy; 474 // Check for fragment identifier of an embedded stylesheet. 475 int32_t fragment = aStylesheetURI.FindChar('#') + 1; 476 if (fragment > 0) { 477 int32_t fragmentLength = aStylesheetURI.Length() - fragment; 478 if (fragmentLength > 0) { 479 // This is really an embedded stylesheet, not just a 480 // "url#". We may want to unescape the fragment. 481 mTarget = Substring(aStylesheetURI, (uint32_t)fragment, fragmentLength); 482 mEmbedStatus = eNeedEmbed; 483 mHandlerTable = gTxEmbedHandler; 484 } 485 } 486 nsresult rv = NS_OK; 487 if (aStylesheet) { 488 mStylesheet = aStylesheet; 489 mToplevelIterator = *aInsertPosition; 490 mIsTopCompiler = false; 491 } else { 492 mStylesheet = new txStylesheet; 493 rv = mStylesheet->init(); 494 NS_ENSURE_SUCCESS(rv, rv); 495 496 mToplevelIterator = 497 txListIterator(&mStylesheet->mRootFrame->mToplevelItems); 498 mToplevelIterator.next(); // go to the end of the list 499 mIsTopCompiler = true; 500 } 501 502 mElementContext = MakeUnique<txElementContext>(aStylesheetURI); 503 504 // Push the "old" txElementContext 505 pushObject(nullptr); 506 507 return NS_OK; 508 } 509 510 txStylesheetCompilerState::~txStylesheetCompilerState() { 511 while (!mObjectStack.isEmpty()) { 512 delete popObject(); 513 } 514 } 515 516 void txStylesheetCompilerState::pushHandlerTable(txHandlerTable* aTable) { 517 pushPtr(mHandlerTable, eHandlerTable); 518 mHandlerTable = aTable; 519 } 520 521 void txStylesheetCompilerState::popHandlerTable() { 522 mHandlerTable = static_cast<txHandlerTable*>(popPtr(eHandlerTable)); 523 } 524 525 void txStylesheetCompilerState::pushSorter(txPushNewContext* aSorter) { 526 pushPtr(mSorter, ePushNewContext); 527 mSorter = aSorter; 528 } 529 530 void txStylesheetCompilerState::popSorter() { 531 mSorter = static_cast<txPushNewContext*>(popPtr(ePushNewContext)); 532 } 533 534 void txStylesheetCompilerState::pushChooseGotoList() { 535 pushObject(mChooseGotoList.release()); 536 mChooseGotoList = MakeUnique<txList>(); 537 } 538 539 void txStylesheetCompilerState::popChooseGotoList() { 540 // this will delete the old value 541 mChooseGotoList = WrapUnique(static_cast<txList*>(popObject())); 542 } 543 544 void txStylesheetCompilerState::pushObject(txObject* aObject) { 545 mObjectStack.push(aObject); 546 } 547 548 txObject* txStylesheetCompilerState::popObject() { 549 return static_cast<txObject*>(mObjectStack.pop()); 550 } 551 552 void txStylesheetCompilerState::pushPtr(void* aPtr, enumStackType aType) { 553 #ifdef TX_DEBUG_STACK 554 MOZ_LOG(txLog::xslt, LogLevel::Debug, 555 ("pushPtr: 0x%x type %u\n", aPtr, aType)); 556 #endif 557 mTypeStack.AppendElement(aType); 558 mOtherStack.push(aPtr); 559 } 560 561 void* txStylesheetCompilerState::popPtr(enumStackType aType) { 562 if (mTypeStack.IsEmpty()) { 563 MOZ_CRASH("Attempt to pop when type stack is empty"); 564 } 565 566 enumStackType type = mTypeStack.PopLastElement(); 567 void* value = mOtherStack.pop(); 568 569 #ifdef TX_DEBUG_STACK 570 MOZ_LOG(txLog::xslt, LogLevel::Debug, 571 ("popPtr: 0x%x type %u requested %u\n", value, type, aType)); 572 #endif 573 574 if (type != aType) { 575 MOZ_CRASH("Expected type does not match top element type"); 576 } 577 578 return value; 579 } 580 581 void txStylesheetCompilerState::addToplevelItem(txToplevelItem* aItem) { 582 mToplevelIterator.addBefore(aItem); 583 } 584 585 nsresult txStylesheetCompilerState::openInstructionContainer( 586 txInstructionContainer* aContainer) { 587 MOZ_ASSERT(!mNextInstrPtr, "can't nest instruction-containers"); 588 589 mNextInstrPtr = &aContainer->mFirstInstruction; 590 return NS_OK; 591 } 592 593 void txStylesheetCompilerState::closeInstructionContainer() { 594 NS_ASSERTION(mGotoTargetPointers.IsEmpty(), 595 "GotoTargets still exists, did you forget to add txReturn?"); 596 mNextInstrPtr = 0; 597 } 598 599 txInstruction* txStylesheetCompilerState::addInstruction( 600 UniquePtr<txInstruction>&& aInstruction) { 601 MOZ_ASSERT(mNextInstrPtr, "adding instruction outside container"); 602 603 txInstruction* newInstr = aInstruction.get(); 604 605 *mNextInstrPtr = std::move(aInstruction); 606 mNextInstrPtr = &newInstr->mNext; 607 608 uint32_t i, count = mGotoTargetPointers.Length(); 609 for (i = 0; i < count; ++i) { 610 *mGotoTargetPointers[i] = newInstr; 611 } 612 mGotoTargetPointers.Clear(); 613 614 return newInstr; 615 } 616 617 nsresult txStylesheetCompilerState::loadIncludedStylesheet( 618 const nsAString& aURI) { 619 MOZ_LOG(txLog::xslt, LogLevel::Info, 620 ("CompilerState::loadIncludedStylesheet: %s\n", 621 NS_LossyConvertUTF16toASCII(aURI).get())); 622 if (mStylesheetURI.Equals(aURI)) { 623 return NS_ERROR_XSLT_LOAD_RECURSION; 624 } 625 NS_ENSURE_TRUE(mObserver, NS_ERROR_NOT_IMPLEMENTED); 626 627 UniquePtr<txToplevelItem> item(new txDummyItem); 628 629 mToplevelIterator.addBefore(item.release()); 630 631 // step back to the dummy-item 632 mToplevelIterator.previous(); 633 634 txACompileObserver* observer = static_cast<txStylesheetCompiler*>(this); 635 636 RefPtr<txStylesheetCompiler> compiler = new txStylesheetCompiler( 637 aURI, mStylesheet, &mToplevelIterator, mReferrerPolicy, observer); 638 639 // step forward before calling the observer in case of syncronous loading 640 mToplevelIterator.next(); 641 642 mChildCompilerList.AppendElement(compiler); 643 644 nsresult rv = 645 mObserver->loadURI(aURI, mStylesheetURI, mReferrerPolicy, compiler); 646 if (NS_FAILED(rv)) { 647 mChildCompilerList.RemoveElement(compiler); 648 } 649 650 return rv; 651 } 652 653 nsresult txStylesheetCompilerState::loadImportedStylesheet( 654 const nsAString& aURI, txStylesheet::ImportFrame* aFrame) { 655 MOZ_LOG(txLog::xslt, LogLevel::Info, 656 ("CompilerState::loadImportedStylesheet: %s\n", 657 NS_LossyConvertUTF16toASCII(aURI).get())); 658 if (mStylesheetURI.Equals(aURI)) { 659 return NS_ERROR_XSLT_LOAD_RECURSION; 660 } 661 NS_ENSURE_TRUE(mObserver, NS_ERROR_NOT_IMPLEMENTED); 662 663 txListIterator iter(&aFrame->mToplevelItems); 664 iter.next(); // go to the end of the list 665 666 txACompileObserver* observer = static_cast<txStylesheetCompiler*>(this); 667 668 RefPtr<txStylesheetCompiler> compiler = new txStylesheetCompiler( 669 aURI, mStylesheet, &iter, mReferrerPolicy, observer); 670 671 mChildCompilerList.AppendElement(compiler); 672 673 nsresult rv = 674 mObserver->loadURI(aURI, mStylesheetURI, mReferrerPolicy, compiler); 675 if (NS_FAILED(rv)) { 676 mChildCompilerList.RemoveElement(compiler); 677 } 678 679 return rv; 680 } 681 682 void txStylesheetCompilerState::addGotoTarget(txInstruction** aTargetPointer) { 683 mGotoTargetPointers.AppendElement(aTargetPointer); 684 } 685 686 void txStylesheetCompilerState::addVariable(const txExpandedName& aName) { 687 mInScopeVariables.AppendElement(aName); 688 } 689 690 int32_t txStylesheetCompilerState::resolveNamespacePrefix(nsAtom* aPrefix) { 691 NS_ASSERTION(aPrefix && aPrefix != nsGkAtoms::_empty, 692 "caller should handle default namespace ''"); 693 return mElementContext->mMappings->lookupNamespace(aPrefix); 694 } 695 696 /** 697 * Error Function to be used for unknown extension functions. 698 * 699 */ 700 class txErrorFunctionCall : public FunctionCall { 701 public: 702 explicit txErrorFunctionCall(nsAtom* aName) : mName(aName) {} 703 704 TX_DECL_FUNCTION 705 706 private: 707 RefPtr<nsAtom> mName; 708 }; 709 710 nsresult txErrorFunctionCall::evaluate(txIEvalContext* aContext, 711 txAExprResult** aResult) { 712 *aResult = nullptr; 713 714 return NS_ERROR_XPATH_BAD_EXTENSION_FUNCTION; 715 } 716 717 Expr::ResultType txErrorFunctionCall::getReturnType() { 718 // It doesn't really matter what we return here, but it might 719 // be a good idea to try to keep this as unoptimizable as possible 720 return ANY_RESULT; 721 } 722 723 bool txErrorFunctionCall::isSensitiveTo(ContextSensitivity aContext) { 724 // It doesn't really matter what we return here, but it might 725 // be a good idea to try to keep this as unoptimizable as possible 726 return true; 727 } 728 729 #ifdef TX_TO_STRING 730 void txErrorFunctionCall::appendName(nsAString& aDest) { 731 aDest.Append(mName->GetUTF16String()); 732 } 733 #endif 734 735 static nsresult TX_ConstructXSLTFunction(nsAtom* aName, 736 txStylesheetCompilerState* aState, 737 FunctionCall** aFunction) { 738 if (aName == nsGkAtoms::document) { 739 *aFunction = new DocumentFunctionCall(aState->mElementContext->mBaseURI); 740 } else if (aName == nsGkAtoms::key) { 741 if (!aState->allowed(txIParseContext::KEY_FUNCTION)) { 742 return NS_ERROR_XSLT_CALL_TO_KEY_NOT_ALLOWED; 743 } 744 *aFunction = new txKeyFunctionCall(aState->mElementContext->mMappings); 745 } else if (aName == nsGkAtoms::formatNumber) { 746 *aFunction = new txFormatNumberFunctionCall( 747 aState->mStylesheet, aState->mElementContext->mMappings); 748 } else if (aName == nsGkAtoms::current) { 749 *aFunction = new CurrentFunctionCall(); 750 } else if (aName == nsGkAtoms::unparsedEntityUri) { 751 return NS_ERROR_NOT_IMPLEMENTED; 752 } else if (aName == nsGkAtoms::generateId) { 753 *aFunction = new GenerateIdFunctionCall(); 754 } else if (aName == nsGkAtoms::systemProperty) { 755 *aFunction = new txXSLTEnvironmentFunctionCall( 756 txXSLTEnvironmentFunctionCall::SYSTEM_PROPERTY, 757 aState->mElementContext->mMappings); 758 } else if (aName == nsGkAtoms::elementAvailable) { 759 *aFunction = new txXSLTEnvironmentFunctionCall( 760 txXSLTEnvironmentFunctionCall::ELEMENT_AVAILABLE, 761 aState->mElementContext->mMappings); 762 } else if (aName == nsGkAtoms::functionAvailable) { 763 *aFunction = new txXSLTEnvironmentFunctionCall( 764 txXSLTEnvironmentFunctionCall::FUNCTION_AVAILABLE, 765 aState->mElementContext->mMappings); 766 } else { 767 return NS_ERROR_XPATH_UNKNOWN_FUNCTION; 768 } 769 770 MOZ_ASSERT(*aFunction); 771 return NS_OK; 772 } 773 774 extern nsresult TX_ConstructEXSLTFunction(nsAtom* aName, int32_t aNamespaceID, 775 txStylesheetCompilerState* aState, 776 FunctionCall** aResult); 777 778 static nsresult findFunction(nsAtom* aName, int32_t aNamespaceID, 779 txStylesheetCompilerState* aState, 780 FunctionCall** aResult) { 781 if (aNamespaceID == kNameSpaceID_None) { 782 return TX_ConstructXSLTFunction(aName, aState, aResult); 783 } 784 785 return TX_ConstructEXSLTFunction(aName, aNamespaceID, aState, aResult); 786 } 787 788 extern bool TX_XSLTFunctionAvailable(nsAtom* aName, int32_t aNameSpaceID) { 789 RefPtr<txStylesheetCompiler> compiler = 790 new txStylesheetCompiler(u""_ns, ReferrerPolicy::_empty, nullptr); 791 NS_ENSURE_TRUE(compiler, false); 792 793 UniquePtr<FunctionCall> fnCall; 794 795 return NS_SUCCEEDED( 796 findFunction(aName, aNameSpaceID, compiler, getter_Transfers(fnCall))); 797 } 798 799 nsresult txStylesheetCompilerState::resolveFunctionCall( 800 nsAtom* aName, int32_t aID, FunctionCall** aFunction) { 801 *aFunction = nullptr; 802 803 nsresult rv = findFunction(aName, aID, this, aFunction); 804 if (rv == NS_ERROR_XPATH_UNKNOWN_FUNCTION && 805 (aID != kNameSpaceID_None || fcp())) { 806 *aFunction = new txErrorFunctionCall(aName); 807 rv = NS_OK; 808 } 809 810 return rv; 811 } 812 813 bool txStylesheetCompilerState::caseInsensitiveNameTests() { return false; } 814 815 void txStylesheetCompilerState::SetErrorOffset(uint32_t aOffset) { 816 // XXX implement me 817 } 818 819 txElementContext::txElementContext(const nsAString& aBaseURI) 820 : mPreserveWhitespace(false), 821 mForwardsCompatibleParsing(true), 822 mBaseURI(aBaseURI), 823 mMappings(new txNamespaceMap), 824 mDepth(0) { 825 mInstructionNamespaces.AppendElement(kNameSpaceID_XSLT); 826 } 827 828 txElementContext::txElementContext(const txElementContext& aOther) 829 : mPreserveWhitespace(aOther.mPreserveWhitespace), 830 mForwardsCompatibleParsing(aOther.mForwardsCompatibleParsing), 831 mBaseURI(aOther.mBaseURI), 832 mMappings(aOther.mMappings), 833 mDepth(0) { 834 mInstructionNamespaces = aOther.mInstructionNamespaces.Clone(); 835 }