Bug 1370737 - Track seen preformatted elements in the document encoder to maintain stack balance correctly irrespective of element visibility; r=bzbarsky

This commit is contained in:
Ehsan Akhgari
2017-06-12 15:20:44 -04:00
parent de1f843eff
commit 373ada68c3
10 changed files with 112 additions and 12 deletions

View File

@@ -0,0 +1,41 @@
<html class="reftest-wait">
<script>
document.addEventListener("DOMContentLoaded", function(){
let n=document.getElementById('a');
n.parentNode.removeChild(n);
let o=document.getElementById('b');
let p=document.getElementById('c');
p.id=[o.id, o.id=p.id][0];
let l=['d'];
let s=window.getSelection();
for(let i=0; i<l.length; i++){
let e=document.getElementById(l[i]);
let r=document.createRange();
r.selectNode(e);
s.addRange(r);
}
n=document.getElementById('b');
n.parentNode.removeChild(n);
window.getSelection().modify('extend','right','word');
n.setAttribute('id','e');
document.getElementById('f').appendChild(n);
l=['e'];
for(let i=0; i<l.length; i++){
let e=document.getElementById(l[i]);
let r=document.createRange();
r.selectNode(e);
s.addRange(r);
}
document.documentElement.removeAttribute("class");
});
</script>
<table>
<tbody hidden>
<th id='c'>
<i id='d'>
<bdo id='b'></bdo>
<td></td>
<tbody id='f'>
<td id='a' contenteditable='true'>
<td>
</html>

View File

@@ -212,6 +212,7 @@ pref(dom.webcomponents.enabled,true) load 1341693.html
pref(dom.IntersectionObserver.enabled,true) load 1353529.xul pref(dom.IntersectionObserver.enabled,true) load 1353529.xul
pref(dom.IntersectionObserver.enabled,true) load 1369363.xul pref(dom.IntersectionObserver.enabled,true) load 1369363.xul
load 1370072.html load 1370072.html
pref(clipboard.autocopy,true) load 1370737.html
pref(dom.IntersectionObserver.enabled,true) load 1370968.html pref(dom.IntersectionObserver.enabled,true) load 1370968.html
load structured_clone_container_throws.html load structured_clone_container_throws.html
HTTP(..) load xhr_abortinprogress.html HTTP(..) load xhr_abortinprogress.html

View File

@@ -186,6 +186,10 @@ protected:
AutoTArray<int32_t, 8> mStartOffsets; AutoTArray<int32_t, 8> mStartOffsets;
AutoTArray<nsIContent*, 8> mEndNodes; AutoTArray<nsIContent*, 8> mEndNodes;
AutoTArray<int32_t, 8> mEndOffsets; AutoTArray<int32_t, 8> mEndOffsets;
// Whether the serializer cares about being notified to scan elements to
// keep track of whether they are preformatted. This stores the out
// argument of nsIContentSerializer::Init().
bool mNeedsPreformatScanning;
bool mHaltRangeHint; bool mHaltRangeHint;
// Used when context has already been serialized for // Used when context has already been serialized for
// table cell selections (where parent is <tr>) // table cell selections (where parent is <tr>)
@@ -221,6 +225,7 @@ void nsDocumentEncoder::Initialize(bool aClearCachedSerializer)
mEndDepth = 0; mEndDepth = 0;
mStartRootIndex = 0; mStartRootIndex = 0;
mEndRootIndex = 0; mEndRootIndex = 0;
mNeedsPreformatScanning = false;
mHaltRangeHint = false; mHaltRangeHint = false;
mDisableContextSerialize = false; mDisableContextSerialize = false;
mNodeIsContainer = false; mNodeIsContainer = false;
@@ -351,6 +356,10 @@ nsDocumentEncoder::SerializeNodeStart(nsINode* aNode,
nsAString& aStr, nsAString& aStr,
nsINode* aOriginalNode) nsINode* aOriginalNode)
{ {
if (mNeedsPreformatScanning && aNode->IsElement()) {
mSerializer->ScanElementForPreformat(aNode->AsElement());
}
if (!IsVisibleNode(aNode)) if (!IsVisibleNode(aNode))
return NS_OK; return NS_OK;
@@ -428,6 +437,10 @@ nsresult
nsDocumentEncoder::SerializeNodeEnd(nsINode* aNode, nsDocumentEncoder::SerializeNodeEnd(nsINode* aNode,
nsAString& aStr) nsAString& aStr)
{ {
if (mNeedsPreformatScanning && aNode->IsElement()) {
mSerializer->ForgetElementForPreformat(aNode->AsElement());
}
if (!IsVisibleNode(aNode)) if (!IsVisibleNode(aNode))
return NS_OK; return NS_OK;
@@ -1075,7 +1088,9 @@ nsDocumentEncoder::EncodeToStringWithMaxLength(uint32_t aMaxLength,
nsresult rv = NS_OK; nsresult rv = NS_OK;
bool rewriteEncodingDeclaration = !(mSelection || mRange || mNode) && !(mFlags & OutputDontRewriteEncodingDeclaration); bool rewriteEncodingDeclaration = !(mSelection || mRange || mNode) && !(mFlags & OutputDontRewriteEncodingDeclaration);
mSerializer->Init(mFlags, mWrapColumn, mCharset.get(), mIsCopying, rewriteEncodingDeclaration); mSerializer->Init(mFlags, mWrapColumn, mCharset.get(),
mIsCopying, rewriteEncodingDeclaration,
&mNeedsPreformatScanning);
if (mSelection) { if (mSelection) {
nsCOMPtr<nsIDOMRange> range; nsCOMPtr<nsIDOMRange> range;

View File

@@ -30,7 +30,8 @@ class nsIContentSerializer : public nsISupports {
NS_IMETHOD Init(uint32_t flags, uint32_t aWrapColumn, NS_IMETHOD Init(uint32_t flags, uint32_t aWrapColumn,
const char* aCharSet, bool aIsCopying, const char* aCharSet, bool aIsCopying,
bool aIsWholeDocument) = 0; bool aIsWholeDocument,
bool* aNeedsPerformatScanning) = 0;
NS_IMETHOD AppendText(nsIContent* aText, int32_t aStartOffset, NS_IMETHOD AppendText(nsIContent* aText, int32_t aStartOffset,
int32_t aEndOffset, nsAString& aStr) = 0; int32_t aEndOffset, nsAString& aStr) = 0;
@@ -66,6 +67,14 @@ class nsIContentSerializer : public nsISupports {
*/ */
NS_IMETHOD AppendDocumentStart(nsIDocument *aDocument, NS_IMETHOD AppendDocumentStart(nsIDocument *aDocument,
nsAString& aStr) = 0; nsAString& aStr) = 0;
// If Init() sets *aNeedsPerformatScanning to true, then these methods are
// called when elements are started and ended, before AppendElementStart
// and AppendElementEnd, respectively. They are supposed to be used to
// allow the implementer to keep track of whether the element is
// preformatted.
NS_IMETHOD ScanElementForPreformat(mozilla::dom::Element* aElement) = 0;
NS_IMETHOD ForgetElementForPreformat(mozilla::dom::Element* aElement) = 0;
}; };
NS_DEFINE_STATIC_IID_ACCESSOR(nsIContentSerializer, NS_ICONTENTSERIALIZER_IID) NS_DEFINE_STATIC_IID_ACCESSOR(nsIContentSerializer, NS_ICONTENTSERIALIZER_IID)

View File

@@ -139,7 +139,8 @@ nsPlainTextSerializer::~nsPlainTextSerializer()
NS_IMETHODIMP NS_IMETHODIMP
nsPlainTextSerializer::Init(uint32_t aFlags, uint32_t aWrapColumn, nsPlainTextSerializer::Init(uint32_t aFlags, uint32_t aWrapColumn,
const char* aCharSet, bool aIsCopying, const char* aCharSet, bool aIsCopying,
bool aIsWholeDocument) bool aIsWholeDocument,
bool* aNeedsPreformatScanning)
{ {
#ifdef DEBUG #ifdef DEBUG
// Check if the major control flags are set correctly. // Check if the major control flags are set correctly.
@@ -155,6 +156,7 @@ nsPlainTextSerializer::Init(uint32_t aFlags, uint32_t aWrapColumn,
} }
#endif #endif
*aNeedsPreformatScanning = true;
mFlags = aFlags; mFlags = aFlags;
mWrapColumn = aWrapColumn; mWrapColumn = aWrapColumn;
@@ -370,6 +372,20 @@ nsPlainTextSerializer::AppendCDATASection(nsIContent* aCDATASection,
return AppendText(aCDATASection, aStartOffset, aEndOffset, aStr); return AppendText(aCDATASection, aStartOffset, aEndOffset, aStr);
} }
NS_IMETHODIMP
nsPlainTextSerializer::ScanElementForPreformat(Element* aElement)
{
mPreformatStack.push(IsElementPreformatted(aElement));
return NS_OK;
}
NS_IMETHODIMP
nsPlainTextSerializer::ForgetElementForPreformat(Element* aElement)
{
mPreformatStack.pop();
return NS_OK;
}
NS_IMETHODIMP NS_IMETHODIMP
nsPlainTextSerializer::AppendElementStart(Element* aElement, nsPlainTextSerializer::AppendElementStart(Element* aElement,
Element* aOriginalElement, Element* aOriginalElement,
@@ -388,7 +404,6 @@ nsPlainTextSerializer::AppendElementStart(Element* aElement,
if (isContainer) { if (isContainer) {
rv = DoOpenContainer(id); rv = DoOpenContainer(id);
mPreformatStack.push(IsElementPreformatted(mElement));
} }
else { else {
rv = DoAddLeaf(id); rv = DoAddLeaf(id);
@@ -422,7 +437,6 @@ nsPlainTextSerializer::AppendElementEnd(Element* aElement,
rv = NS_OK; rv = NS_OK;
if (isContainer) { if (isContainer) {
rv = DoCloseContainer(id); rv = DoCloseContainer(id);
mPreformatStack.pop();
} }
mElement = nullptr; mElement = nullptr;

View File

@@ -44,7 +44,8 @@ public:
// nsIContentSerializer // nsIContentSerializer
NS_IMETHOD Init(uint32_t flags, uint32_t aWrapColumn, NS_IMETHOD Init(uint32_t flags, uint32_t aWrapColumn,
const char* aCharSet, bool aIsCopying, const char* aCharSet, bool aIsCopying,
bool aIsWholeDocument) override; bool aIsWholeDocument,
bool* aNeedsPreformatScanning) override;
NS_IMETHOD AppendText(nsIContent* aText, int32_t aStartOffset, NS_IMETHOD AppendText(nsIContent* aText, int32_t aStartOffset,
int32_t aEndOffset, nsAString& aStr) override; int32_t aEndOffset, nsAString& aStr) override;
@@ -69,6 +70,9 @@ public:
NS_IMETHOD AppendDocumentStart(nsIDocument *aDocument, NS_IMETHOD AppendDocumentStart(nsIDocument *aDocument,
nsAString& aStr) override; nsAString& aStr) override;
NS_IMETHOD ScanElementForPreformat(mozilla::dom::Element* aElement) override;
NS_IMETHOD ForgetElementForPreformat(mozilla::dom::Element* aElement) override;
private: private:
~nsPlainTextSerializer(); ~nsPlainTextSerializer();

View File

@@ -60,7 +60,8 @@ nsXHTMLContentSerializer::~nsXHTMLContentSerializer()
NS_IMETHODIMP NS_IMETHODIMP
nsXHTMLContentSerializer::Init(uint32_t aFlags, uint32_t aWrapColumn, nsXHTMLContentSerializer::Init(uint32_t aFlags, uint32_t aWrapColumn,
const char* aCharSet, bool aIsCopying, const char* aCharSet, bool aIsCopying,
bool aRewriteEncodingDeclaration) bool aRewriteEncodingDeclaration,
bool* aNeedsPreformatScanning)
{ {
// The previous version of the HTML serializer did implicit wrapping // The previous version of the HTML serializer did implicit wrapping
// when there is no flags, so we keep wrapping in order to keep // when there is no flags, so we keep wrapping in order to keep
@@ -71,7 +72,9 @@ nsXHTMLContentSerializer::Init(uint32_t aFlags, uint32_t aWrapColumn,
} }
nsresult rv; nsresult rv;
rv = nsXMLContentSerializer::Init(aFlags, aWrapColumn, aCharSet, aIsCopying, aRewriteEncodingDeclaration); rv = nsXMLContentSerializer::Init(aFlags, aWrapColumn, aCharSet,
aIsCopying, aRewriteEncodingDeclaration,
aNeedsPreformatScanning);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
mRewriteEncodingDeclaration = aRewriteEncodingDeclaration; mRewriteEncodingDeclaration = aRewriteEncodingDeclaration;

View File

@@ -29,7 +29,8 @@ class nsXHTMLContentSerializer : public nsXMLContentSerializer {
NS_IMETHOD Init(uint32_t flags, uint32_t aWrapColumn, NS_IMETHOD Init(uint32_t flags, uint32_t aWrapColumn,
const char* aCharSet, bool aIsCopying, const char* aCharSet, bool aIsCopying,
bool aRewriteEncodingDeclaration) override; bool aRewriteEncodingDeclaration,
bool* aNeedsPreformatScanning) override;
NS_IMETHOD AppendText(nsIContent* aText, NS_IMETHOD AppendText(nsIContent* aText,
int32_t aStartOffset, int32_t aStartOffset,

View File

@@ -76,8 +76,10 @@ NS_IMPL_ISUPPORTS(nsXMLContentSerializer, nsIContentSerializer)
NS_IMETHODIMP NS_IMETHODIMP
nsXMLContentSerializer::Init(uint32_t aFlags, uint32_t aWrapColumn, nsXMLContentSerializer::Init(uint32_t aFlags, uint32_t aWrapColumn,
const char* aCharSet, bool aIsCopying, const char* aCharSet, bool aIsCopying,
bool aRewriteEncodingDeclaration) bool aRewriteEncodingDeclaration,
bool* aNeedsPreformatScanning)
{ {
*aNeedsPreformatScanning = false;
mPrefixIndex = 0; mPrefixIndex = 0;
mColPos = 0; mColPos = 0;
mIndentOverflow = 0; mIndentOverflow = 0;

View File

@@ -34,7 +34,8 @@ class nsXMLContentSerializer : public nsIContentSerializer {
NS_IMETHOD Init(uint32_t flags, uint32_t aWrapColumn, NS_IMETHOD Init(uint32_t flags, uint32_t aWrapColumn,
const char* aCharSet, bool aIsCopying, const char* aCharSet, bool aIsCopying,
bool aRewriteEncodingDeclaration) override; bool aRewriteEncodingDeclaration,
bool* aNeedsPreformatScanning) override;
NS_IMETHOD AppendText(nsIContent* aText, int32_t aStartOffset, NS_IMETHOD AppendText(nsIContent* aText, int32_t aStartOffset,
int32_t aEndOffset, nsAString& aStr) override; int32_t aEndOffset, nsAString& aStr) override;
@@ -66,6 +67,15 @@ class nsXMLContentSerializer : public nsIContentSerializer {
NS_IMETHOD AppendDocumentStart(nsIDocument *aDocument, NS_IMETHOD AppendDocumentStart(nsIDocument *aDocument,
nsAString& aStr) override; nsAString& aStr) override;
NS_IMETHOD ScanElementForPreformat(mozilla::dom::Element* aElement) override
{
return NS_OK;
}
NS_IMETHOD ForgetElementForPreformat(mozilla::dom::Element* aElement) override
{
return NS_OK;
}
protected: protected:
virtual ~nsXMLContentSerializer(); virtual ~nsXMLContentSerializer();