diff options
Diffstat (limited to 'dom/xslt/xslt/txBufferingHandler.cpp')
-rw-r--r-- | dom/xslt/xslt/txBufferingHandler.cpp | 385 |
1 files changed, 385 insertions, 0 deletions
diff --git a/dom/xslt/xslt/txBufferingHandler.cpp b/dom/xslt/xslt/txBufferingHandler.cpp new file mode 100644 index 0000000000..a0c7a39f73 --- /dev/null +++ b/dom/xslt/xslt/txBufferingHandler.cpp @@ -0,0 +1,385 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "txBufferingHandler.h" + +using mozilla::MakeUnique; + +class txOutputTransaction { + public: + enum txTransactionType { + eAttributeTransaction, + eAttributeAtomTransaction, + eCharacterTransaction, + eCharacterNoOETransaction, + eCommentTransaction, + eEndDocumentTransaction, + eEndElementTransaction, + ePITransaction, + eStartDocumentTransaction, + eStartElementAtomTransaction, + eStartElementTransaction + }; + explicit txOutputTransaction(txTransactionType aType) : mType(aType) { + MOZ_COUNT_CTOR(txOutputTransaction); + } + MOZ_COUNTED_DTOR_VIRTUAL(txOutputTransaction) + txTransactionType mType; +}; + +class txCharacterTransaction : public txOutputTransaction { + public: + txCharacterTransaction(txTransactionType aType, uint32_t aLength) + : txOutputTransaction(aType), mLength(aLength) { + MOZ_COUNT_CTOR_INHERITED(txCharacterTransaction, txOutputTransaction); + } + virtual ~txCharacterTransaction() { + MOZ_COUNT_DTOR_INHERITED(txCharacterTransaction, txOutputTransaction); + } + uint32_t mLength; +}; + +class txCommentTransaction : public txOutputTransaction { + public: + explicit txCommentTransaction(const nsAString& aValue) + : txOutputTransaction(eCommentTransaction), mValue(aValue) { + MOZ_COUNT_CTOR_INHERITED(txCommentTransaction, txOutputTransaction); + } + virtual ~txCommentTransaction() { + MOZ_COUNT_DTOR_INHERITED(txCommentTransaction, txOutputTransaction); + } + nsString mValue; +}; + +class txPITransaction : public txOutputTransaction { + public: + txPITransaction(const nsAString& aTarget, const nsAString& aData) + : txOutputTransaction(ePITransaction), mTarget(aTarget), mData(aData) { + MOZ_COUNT_CTOR_INHERITED(txPITransaction, txOutputTransaction); + } + virtual ~txPITransaction() { + MOZ_COUNT_DTOR_INHERITED(txPITransaction, txOutputTransaction); + } + nsString mTarget; + nsString mData; +}; + +class txStartElementAtomTransaction : public txOutputTransaction { + public: + txStartElementAtomTransaction(nsAtom* aPrefix, nsAtom* aLocalName, + nsAtom* aLowercaseLocalName, int32_t aNsID) + : txOutputTransaction(eStartElementAtomTransaction), + mPrefix(aPrefix), + mLocalName(aLocalName), + mLowercaseLocalName(aLowercaseLocalName), + mNsID(aNsID) { + MOZ_COUNT_CTOR_INHERITED(txStartElementAtomTransaction, + txOutputTransaction); + } + virtual ~txStartElementAtomTransaction() { + MOZ_COUNT_DTOR_INHERITED(txStartElementAtomTransaction, + txOutputTransaction); + } + RefPtr<nsAtom> mPrefix; + RefPtr<nsAtom> mLocalName; + RefPtr<nsAtom> mLowercaseLocalName; + int32_t mNsID; +}; + +class txStartElementTransaction : public txOutputTransaction { + public: + txStartElementTransaction(nsAtom* aPrefix, const nsAString& aLocalName, + int32_t aNsID) + : txOutputTransaction(eStartElementTransaction), + mPrefix(aPrefix), + mLocalName(aLocalName), + mNsID(aNsID) { + MOZ_COUNT_CTOR_INHERITED(txStartElementTransaction, txOutputTransaction); + } + virtual ~txStartElementTransaction() { + MOZ_COUNT_DTOR_INHERITED(txStartElementTransaction, txOutputTransaction); + } + RefPtr<nsAtom> mPrefix; + nsString mLocalName; + int32_t mNsID; +}; + +class txAttributeTransaction : public txOutputTransaction { + public: + txAttributeTransaction(nsAtom* aPrefix, const nsAString& aLocalName, + int32_t aNsID, const nsString& aValue) + : txOutputTransaction(eAttributeTransaction), + mPrefix(aPrefix), + mLocalName(aLocalName), + mNsID(aNsID), + mValue(aValue) { + MOZ_COUNT_CTOR_INHERITED(txAttributeTransaction, txOutputTransaction); + } + virtual ~txAttributeTransaction() { + MOZ_COUNT_DTOR_INHERITED(txAttributeTransaction, txOutputTransaction); + } + RefPtr<nsAtom> mPrefix; + nsString mLocalName; + int32_t mNsID; + nsString mValue; +}; + +class txAttributeAtomTransaction : public txOutputTransaction { + public: + txAttributeAtomTransaction(nsAtom* aPrefix, nsAtom* aLocalName, + nsAtom* aLowercaseLocalName, int32_t aNsID, + const nsString& aValue) + : txOutputTransaction(eAttributeAtomTransaction), + mPrefix(aPrefix), + mLocalName(aLocalName), + mLowercaseLocalName(aLowercaseLocalName), + mNsID(aNsID), + mValue(aValue) { + MOZ_COUNT_CTOR_INHERITED(txAttributeAtomTransaction, txOutputTransaction); + } + virtual ~txAttributeAtomTransaction() { + MOZ_COUNT_DTOR_INHERITED(txAttributeAtomTransaction, txOutputTransaction); + } + RefPtr<nsAtom> mPrefix; + RefPtr<nsAtom> mLocalName; + RefPtr<nsAtom> mLowercaseLocalName; + int32_t mNsID; + nsString mValue; +}; + +txBufferingHandler::txBufferingHandler() : mCanAddAttribute(false) { + MOZ_COUNT_CTOR(txBufferingHandler); + mBuffer = MakeUnique<txResultBuffer>(); +} + +txBufferingHandler::~txBufferingHandler() { + MOZ_COUNT_DTOR(txBufferingHandler); +} + +nsresult txBufferingHandler::attribute(nsAtom* aPrefix, nsAtom* aLocalName, + nsAtom* aLowercaseLocalName, + int32_t aNsID, const nsString& aValue) { + NS_ENSURE_TRUE(mBuffer, NS_ERROR_OUT_OF_MEMORY); + + if (!mCanAddAttribute) { + // XXX ErrorReport: Can't add attributes without element + return NS_OK; + } + + txOutputTransaction* transaction = new txAttributeAtomTransaction( + aPrefix, aLocalName, aLowercaseLocalName, aNsID, aValue); + return mBuffer->addTransaction(transaction); +} + +nsresult txBufferingHandler::attribute(nsAtom* aPrefix, + const nsAString& aLocalName, + const int32_t aNsID, + const nsString& aValue) { + NS_ENSURE_TRUE(mBuffer, NS_ERROR_OUT_OF_MEMORY); + + if (!mCanAddAttribute) { + // XXX ErrorReport: Can't add attributes without element + return NS_OK; + } + + txOutputTransaction* transaction = + new txAttributeTransaction(aPrefix, aLocalName, aNsID, aValue); + return mBuffer->addTransaction(transaction); +} + +nsresult txBufferingHandler::characters(const nsAString& aData, bool aDOE) { + NS_ENSURE_TRUE(mBuffer, NS_ERROR_OUT_OF_MEMORY); + + mCanAddAttribute = false; + + txOutputTransaction::txTransactionType type = + aDOE ? txOutputTransaction::eCharacterNoOETransaction + : txOutputTransaction::eCharacterTransaction; + + txOutputTransaction* transaction = mBuffer->getLastTransaction(); + if (transaction && transaction->mType == type) { + mBuffer->mStringValue.Append(aData); + static_cast<txCharacterTransaction*>(transaction)->mLength += + aData.Length(); + return NS_OK; + } + + transaction = new txCharacterTransaction(type, aData.Length()); + mBuffer->mStringValue.Append(aData); + return mBuffer->addTransaction(transaction); +} + +nsresult txBufferingHandler::comment(const nsString& aData) { + NS_ENSURE_TRUE(mBuffer, NS_ERROR_OUT_OF_MEMORY); + + mCanAddAttribute = false; + + txOutputTransaction* transaction = new txCommentTransaction(aData); + return mBuffer->addTransaction(transaction); +} + +nsresult txBufferingHandler::endDocument(nsresult aResult) { + NS_ENSURE_TRUE(mBuffer, NS_ERROR_OUT_OF_MEMORY); + + txOutputTransaction* transaction = + new txOutputTransaction(txOutputTransaction::eEndDocumentTransaction); + return mBuffer->addTransaction(transaction); +} + +nsresult txBufferingHandler::endElement() { + NS_ENSURE_TRUE(mBuffer, NS_ERROR_OUT_OF_MEMORY); + + mCanAddAttribute = false; + + txOutputTransaction* transaction = + new txOutputTransaction(txOutputTransaction::eEndElementTransaction); + return mBuffer->addTransaction(transaction); +} + +nsresult txBufferingHandler::processingInstruction(const nsString& aTarget, + const nsString& aData) { + NS_ENSURE_TRUE(mBuffer, NS_ERROR_OUT_OF_MEMORY); + + mCanAddAttribute = false; + + txOutputTransaction* transaction = new txPITransaction(aTarget, aData); + return mBuffer->addTransaction(transaction); +} + +nsresult txBufferingHandler::startDocument() { + NS_ENSURE_TRUE(mBuffer, NS_ERROR_OUT_OF_MEMORY); + + txOutputTransaction* transaction = + new txOutputTransaction(txOutputTransaction::eStartDocumentTransaction); + return mBuffer->addTransaction(transaction); +} + +nsresult txBufferingHandler::startElement(nsAtom* aPrefix, nsAtom* aLocalName, + nsAtom* aLowercaseLocalName, + int32_t aNsID) { + NS_ENSURE_TRUE(mBuffer, NS_ERROR_OUT_OF_MEMORY); + + mCanAddAttribute = true; + + txOutputTransaction* transaction = new txStartElementAtomTransaction( + aPrefix, aLocalName, aLowercaseLocalName, aNsID); + return mBuffer->addTransaction(transaction); +} + +nsresult txBufferingHandler::startElement(nsAtom* aPrefix, + const nsAString& aLocalName, + const int32_t aNsID) { + NS_ENSURE_TRUE(mBuffer, NS_ERROR_OUT_OF_MEMORY); + + mCanAddAttribute = true; + + txOutputTransaction* transaction = + new txStartElementTransaction(aPrefix, aLocalName, aNsID); + return mBuffer->addTransaction(transaction); +} + +txResultBuffer::txResultBuffer() { MOZ_COUNT_CTOR(txResultBuffer); } + +txResultBuffer::~txResultBuffer() { + MOZ_COUNT_DTOR(txResultBuffer); + for (uint32_t i = 0, len = mTransactions.Length(); i < len; ++i) { + delete mTransactions[i]; + } +} + +nsresult txResultBuffer::addTransaction(txOutputTransaction* aTransaction) { + // XXX(Bug 1631371) Check if this should use a fallible operation as it + // pretended earlier, or change the return type to void. + mTransactions.AppendElement(aTransaction); + return NS_OK; +} + +static nsresult flushTransaction(txOutputTransaction* aTransaction, + txAXMLEventHandler* aHandler, + nsString::const_char_iterator& aIter) { + switch (aTransaction->mType) { + case txOutputTransaction::eAttributeAtomTransaction: { + txAttributeAtomTransaction* transaction = + static_cast<txAttributeAtomTransaction*>(aTransaction); + return aHandler->attribute(transaction->mPrefix, transaction->mLocalName, + transaction->mLowercaseLocalName, + transaction->mNsID, transaction->mValue); + } + case txOutputTransaction::eAttributeTransaction: { + txAttributeTransaction* attrTransaction = + static_cast<txAttributeTransaction*>(aTransaction); + return aHandler->attribute( + attrTransaction->mPrefix, attrTransaction->mLocalName, + attrTransaction->mNsID, attrTransaction->mValue); + } + case txOutputTransaction::eCharacterTransaction: + case txOutputTransaction::eCharacterNoOETransaction: { + txCharacterTransaction* charTransaction = + static_cast<txCharacterTransaction*>(aTransaction); + nsString::const_char_iterator start = aIter; + nsString::const_char_iterator end = start + charTransaction->mLength; + aIter = end; + return aHandler->characters( + Substring(start, end), + aTransaction->mType == + txOutputTransaction::eCharacterNoOETransaction); + } + case txOutputTransaction::eCommentTransaction: { + txCommentTransaction* commentTransaction = + static_cast<txCommentTransaction*>(aTransaction); + return aHandler->comment(commentTransaction->mValue); + } + case txOutputTransaction::eEndElementTransaction: { + return aHandler->endElement(); + } + case txOutputTransaction::ePITransaction: { + txPITransaction* piTransaction = + static_cast<txPITransaction*>(aTransaction); + return aHandler->processingInstruction(piTransaction->mTarget, + piTransaction->mData); + } + case txOutputTransaction::eStartDocumentTransaction: { + return aHandler->startDocument(); + } + case txOutputTransaction::eStartElementAtomTransaction: { + txStartElementAtomTransaction* transaction = + static_cast<txStartElementAtomTransaction*>(aTransaction); + return aHandler->startElement( + transaction->mPrefix, transaction->mLocalName, + transaction->mLowercaseLocalName, transaction->mNsID); + } + case txOutputTransaction::eStartElementTransaction: { + txStartElementTransaction* transaction = + static_cast<txStartElementTransaction*>(aTransaction); + return aHandler->startElement( + transaction->mPrefix, transaction->mLocalName, transaction->mNsID); + } + default: { + MOZ_ASSERT_UNREACHABLE("Unexpected transaction type"); + } + } + + return NS_ERROR_UNEXPECTED; +} + +nsresult txResultBuffer::flushToHandler(txAXMLEventHandler* aHandler) { + nsString::const_char_iterator iter; + mStringValue.BeginReading(iter); + + for (uint32_t i = 0, len = mTransactions.Length(); i < len; ++i) { + nsresult rv = flushTransaction(mTransactions[i], aHandler, iter); + NS_ENSURE_SUCCESS(rv, rv); + } + + return NS_OK; +} + +txOutputTransaction* txResultBuffer::getLastTransaction() { + int32_t last = mTransactions.Length() - 1; + if (last < 0) { + return nullptr; + } + return mTransactions[last]; +} |