From b083a35419ad901caf0dfa0c72d3268632665c29 Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Mon, 12 Oct 2015 13:07:51 -0400 Subject: [PATCH] Bug 890284. Stop splitting textnodes in the XML content sink. r=peterv --- dom/xml/nsXMLContentSink.cpp | 79 ++++++++++-------------------------- dom/xml/nsXMLContentSink.h | 9 ++-- 2 files changed, 26 insertions(+), 62 deletions(-) diff --git a/dom/xml/nsXMLContentSink.cpp b/dom/xml/nsXMLContentSink.cpp index e325f8f6faa..395d7589544 100644 --- a/dom/xml/nsXMLContentSink.cpp +++ b/dom/xml/nsXMLContentSink.cpp @@ -96,16 +96,12 @@ NS_NewXMLContentSink(nsIXMLContentSink** aResult, } nsXMLContentSink::nsXMLContentSink() - : mConstrainSize(true), - mPrettyPrintXML(true) + : mPrettyPrintXML(true) { } nsXMLContentSink::~nsXMLContentSink() { - if (mText) { - PR_Free(mText); // Doesn't null out, unlike PR_FREEIF - } } nsresult @@ -475,7 +471,6 @@ nsXMLContentSink::CreateElement(const char16_t** aAtts, uint32_t aAttsCount, nsCOMPtr sele = do_QueryInterface(content); sele->SetScriptLineNumber(aLineNumber); sele->SetCreatorParser(GetParser()); - mConstrainSize = false; } // XHTML needs some special attention @@ -552,7 +547,6 @@ nsXMLContentSink::CloseElement(nsIContent* aContent) if (nodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_XHTML) || nodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_SVG) ) { - mConstrainSize = true; nsCOMPtr sele = do_QueryInterface(aContent); if (mPreventScriptExecution) { @@ -778,26 +772,19 @@ nsXMLContentSink::FlushText(bool aReleaseTextNode) if (mTextLength != 0) { if (mLastTextNode) { - if ((mLastTextNodeSize + mTextLength) > mTextSize && !mXSLTProcessor) { - mLastTextNodeSize = 0; - mLastTextNode = nullptr; - FlushText(aReleaseTextNode); - } else { - bool notify = HaveNotifiedForCurrentContent(); - // We could probably always increase mInNotification here since - // if AppendText doesn't notify it shouldn't trigger evil code. - // But just in case it does, we don't want to mask any notifications. - if (notify) { - ++mInNotification; - } - rv = mLastTextNode->AppendText(mText, mTextLength, notify); - if (notify) { - --mInNotification; - } - - mLastTextNodeSize += mTextLength; - mTextLength = 0; + bool notify = HaveNotifiedForCurrentContent(); + // We could probably always increase mInNotification here since + // if AppendText doesn't notify it shouldn't trigger evil code. + // But just in case it does, we don't want to mask any notifications. + if (notify) { + ++mInNotification; } + rv = mLastTextNode->AppendText(mText, mTextLength, notify); + if (notify) { + --mInNotification; + } + + mTextLength = 0; } else { nsRefPtr textContent = new nsTextNode(mNodeInfoManager); @@ -805,7 +792,6 @@ nsXMLContentSink::FlushText(bool aReleaseTextNode) // Set the text in the text node textContent->SetText(mText, mTextLength, false); - mLastTextNodeSize += mTextLength; mTextLength = 0; // Add text to its parent @@ -814,7 +800,6 @@ nsXMLContentSink::FlushText(bool aReleaseTextNode) } if (aReleaseTextNode) { - mLastTextNodeSize = 0; mLastTextNode = nullptr; } @@ -1437,41 +1422,19 @@ nsresult nsXMLContentSink::AddText(const char16_t* aText, int32_t aLength) { - // Create buffer when we first need it - if (0 == mTextSize) { - mText = (char16_t *) PR_MALLOC(sizeof(char16_t) * NS_ACCUMULATION_BUFFER_SIZE); - if (nullptr == mText) { - return NS_ERROR_OUT_OF_MEMORY; - } - mTextSize = NS_ACCUMULATION_BUFFER_SIZE; - } - - // Copy data from string into our buffer; flush buffer when it fills up + // Copy data from string into our buffer; flush buffer when it fills up. int32_t offset = 0; while (0 != aLength) { - int32_t amount = mTextSize - mTextLength; + int32_t amount = NS_ACCUMULATION_BUFFER_SIZE - mTextLength; if (0 == amount) { - // XSLT wants adjacent textnodes merged. - if (mConstrainSize && !mXSLTProcessor) { - nsresult rv = FlushText(); - if (NS_OK != rv) { - return rv; - } - - amount = mTextSize - mTextLength; - } - else { - mTextSize += aLength; - mText = (char16_t *) PR_REALLOC(mText, sizeof(char16_t) * mTextSize); - if (nullptr == mText) { - mTextSize = 0; - - return NS_ERROR_OUT_OF_MEMORY; - } - - amount = aLength; + nsresult rv = FlushText(false); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; } + MOZ_ASSERT(mTextLength == 0); + amount = NS_ACCUMULATION_BUFFER_SIZE; } + if (amount > aLength) { amount = aLength; } diff --git a/dom/xml/nsXMLContentSink.h b/dom/xml/nsXMLContentSink.h index 7ec23dba21d..953232d044f 100644 --- a/dom/xml/nsXMLContentSink.h +++ b/dom/xml/nsXMLContentSink.h @@ -171,18 +171,15 @@ protected: nsCOMPtr mDocElement; nsCOMPtr mCurrentHead; // When set, we're in an XHTML - char16_t* mText; XMLContentSinkState mState; + // The length of the valid data in mText. int32_t mTextLength; - int32_t mTextSize; int32_t mNotifyLevel; nsCOMPtr mLastTextNode; - int32_t mLastTextNodeSize; - uint8_t mConstrainSize : 1; uint8_t mPrettyPrintXML : 1; uint8_t mPrettyPrintHasSpecialRoot : 1; uint8_t mPrettyPrintHasFactoredElements : 1; @@ -194,6 +191,10 @@ protected: nsTArray mContentStack; nsCOMPtr mXSLTProcessor; + + static const int NS_ACCUMULATION_BUFFER_SIZE = 4096; + // Our currently accumulated text that we have not flushed to a textnode yet. + char16_t mText[NS_ACCUMULATION_BUFFER_SIZE]; }; #endif // nsXMLContentSink_h__