зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
e11e4411a9
Коммит
4d26961c8f
|
@ -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;
|
||||
|
|
Загрузка…
Ссылка в новой задаче