Bug 449219. Don't flush out textnodes unconditionally in the XML sink on packet boundaries. Instead, do smart coalescing like the HTML sink does. Also, always coalesce everything when doing XSLT. r+sr=sicking

This commit is contained in:
Boris Zbarsky 2008-10-15 17:29:35 -04:00
Родитель e11e4411a9
Коммит 4d26961c8f
4 изменённых файлов: 123 добавлений и 88 удалений

Просмотреть файл

@ -118,83 +118,82 @@ nsXBLContentSink::MaybeStartLayout(PRBool aIgnorePendingSheets)
}
nsresult
nsXBLContentSink::FlushText()
nsXBLContentSink::FlushText(PRBool aReleaseTextNode)
{
if (mTextLength == 0) {
return NS_OK;
}
const nsASingleFragmentString& text = Substring(mText, mText+mTextLength);
if (mState == eXBL_InHandlers) {
NS_ASSERTION(mBinding, "Must have binding here");
// Get the text and add it to the event handler.
if (mSecondaryState == eXBL_InHandler)
mHandler->AppendHandlerText(text);
mTextLength = 0;
return NS_OK;
}
else if (mState == eXBL_InImplementation) {
NS_ASSERTION(mBinding, "Must have binding here");
if (mSecondaryState == eXBL_InConstructor ||
mSecondaryState == eXBL_InDestructor) {
// Construct a method for the constructor/destructor.
nsXBLProtoImplMethod* method;
if (mSecondaryState == eXBL_InConstructor)
method = mBinding->GetConstructor();
else
method = mBinding->GetDestructor();
// Get the text and add it to the constructor/destructor.
method->AppendBodyText(text);
}
else if (mSecondaryState == eXBL_InGetter ||
mSecondaryState == eXBL_InSetter) {
// Get the text and add it to the getter/setter
if (mSecondaryState == eXBL_InGetter)
mProperty->AppendGetterText(text);
else
mProperty->AppendSetterText(text);
}
else if (mSecondaryState == eXBL_InBody) {
// Get the text and add it to the method
if (mMethod)
mMethod->AppendBodyText(text);
}
else if (mSecondaryState == eXBL_InField) {
// Get the text and add it to the method
mField->AppendFieldText(text);
}
mTextLength = 0;
return NS_OK;
}
nsIContent* content = GetCurrentContent();
if (content &&
(content->NodeInfo()->NamespaceEquals(kNameSpaceID_XBL) ||
(content->NodeInfo()->NamespaceEquals(kNameSpaceID_XUL) &&
content->Tag() != nsGkAtoms::label &&
content->Tag() != nsGkAtoms::description))) {
PRBool isWS = PR_TRUE;
if (mTextLength > 0) {
const PRUnichar* cp = mText;
const PRUnichar* end = mText + mTextLength;
while (cp < end) {
PRUnichar ch = *cp++;
if (!XP_IS_SPACE(ch)) {
isWS = PR_FALSE;
break;
}
}
}
if (isWS && mTextLength > 0) {
if (mTextLength != 0) {
const nsASingleFragmentString& text = Substring(mText, mText+mTextLength);
if (mState == eXBL_InHandlers) {
NS_ASSERTION(mBinding, "Must have binding here");
// Get the text and add it to the event handler.
if (mSecondaryState == eXBL_InHandler)
mHandler->AppendHandlerText(text);
mTextLength = 0;
return NS_OK;
}
else if (mState == eXBL_InImplementation) {
NS_ASSERTION(mBinding, "Must have binding here");
if (mSecondaryState == eXBL_InConstructor ||
mSecondaryState == eXBL_InDestructor) {
// Construct a method for the constructor/destructor.
nsXBLProtoImplMethod* method;
if (mSecondaryState == eXBL_InConstructor)
method = mBinding->GetConstructor();
else
method = mBinding->GetDestructor();
// Get the text and add it to the constructor/destructor.
method->AppendBodyText(text);
}
else if (mSecondaryState == eXBL_InGetter ||
mSecondaryState == eXBL_InSetter) {
// Get the text and add it to the getter/setter
if (mSecondaryState == eXBL_InGetter)
mProperty->AppendGetterText(text);
else
mProperty->AppendSetterText(text);
}
else if (mSecondaryState == eXBL_InBody) {
// Get the text and add it to the method
if (mMethod)
mMethod->AppendBodyText(text);
}
else if (mSecondaryState == eXBL_InField) {
// Get the text and add it to the method
mField->AppendFieldText(text);
}
mTextLength = 0;
return NS_OK;
}
nsIContent* content = GetCurrentContent();
if (content &&
(content->NodeInfo()->NamespaceEquals(kNameSpaceID_XBL) ||
(content->NodeInfo()->NamespaceEquals(kNameSpaceID_XUL) &&
content->Tag() != nsGkAtoms::label &&
content->Tag() != nsGkAtoms::description))) {
PRBool isWS = PR_TRUE;
if (mTextLength > 0) {
const PRUnichar* cp = mText;
const PRUnichar* end = mText + mTextLength;
while (cp < end) {
PRUnichar ch = *cp++;
if (!XP_IS_SPACE(ch)) {
isWS = PR_FALSE;
break;
}
}
}
if (isWS && mTextLength > 0) {
mTextLength = 0;
// Make sure to drop the textnode, if any
return nsXMLContentSink::FlushText(aReleaseTextNode);
}
}
}
return nsXMLContentSink::FlushText();
return nsXMLContentSink::FlushText(aReleaseTextNode);
}
NS_IMETHODIMP

Просмотреть файл

@ -146,7 +146,7 @@ protected:
// nsXMLContentSink overrides
nsresult FlushText();
nsresult FlushText(PRBool aReleaseTextNode = PR_TRUE);
// nsIExpatSink overrides
NS_IMETHOD ReportError(const PRUnichar* aErrorText,

Просмотреть файл

@ -827,22 +827,56 @@ nsXMLContentSink::GetTarget()
}
nsresult
nsXMLContentSink::FlushText()
nsXMLContentSink::FlushText(PRBool aReleaseTextNode)
{
if (mTextLength == 0) {
return NS_OK;
nsresult rv = NS_OK;
if (mTextLength != 0) {
if (mLastTextNode) {
if ((mLastTextNodeSize + mTextLength) > mTextSize && !mXSLTProcessor) {
mLastTextNodeSize = 0;
mLastTextNode = nsnull;
FlushText(aReleaseTextNode);
} else {
PRBool 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;
}
} else {
nsCOMPtr<nsIContent> textContent;
rv = NS_NewTextNode(getter_AddRefs(textContent),
mNodeInfoManager);
NS_ENSURE_SUCCESS(rv, rv);
mLastTextNode = textContent;
// Set the text in the text node
textContent->SetText(mText, mTextLength, PR_FALSE);
mLastTextNodeSize += mTextLength;
mTextLength = 0;
// Add text to its parent
rv = AddContentAsLeaf(textContent);
}
}
nsCOMPtr<nsIContent> textContent;
nsresult rv = NS_NewTextNode(getter_AddRefs(textContent), mNodeInfoManager);
NS_ENSURE_SUCCESS(rv, rv);
// Set the text in the text node
textContent->SetText(mText, mTextLength, PR_FALSE);
mTextLength = 0;
// Add text to its parent
return AddContentAsLeaf(textContent);
if (aReleaseTextNode) {
mLastTextNodeSize = 0;
mLastTextNode = nsnull;
}
return rv;
}
nsIContent*
@ -1581,7 +1615,7 @@ nsXMLContentSink::FlushPendingNotifications(mozFlushType aType)
FlushTags();
}
else {
FlushText();
FlushText(PR_FALSE);
}
if (aType >= Flush_Layout) {
// Make sure that layout has started so that the reflow flush
@ -1615,7 +1649,7 @@ nsXMLContentSink::FlushTags()
mBeganUpdate = PR_TRUE;
// Don't release last text node in case we need to add to it again
FlushText();
FlushText(PR_FALSE);
// Start from the base of the stack (growing downward) and do
// a notification from the node that is closest to the root of

Просмотреть файл

@ -142,7 +142,7 @@ protected:
// being closed
virtual nsresult CloseElement(nsIContent* aContent);
virtual nsresult FlushText();
virtual nsresult FlushText(PRBool aReleaseTextNode = PR_TRUE);
nsresult AddContentAsLeaf(nsIContent *aContent);
@ -199,6 +199,8 @@ protected:
PRInt32 mTextSize;
PRInt32 mNotifyLevel;
nsCOMPtr<nsIContent> mLastTextNode;
PRInt32 mLastTextNodeSize;
PRUint8 mConstrainSize : 1;
PRUint8 mPrettyPrintXML : 1;