tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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 }