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:
41
dom/base/crashtests/1370737.html
Normal file
41
dom/base/crashtests/1370737.html
Normal 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>
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user