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
Родитель 89aa3c7c0f
Коммит 7f656414b1
10 изменённых файлов: 112 добавлений и 12 удалений

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

@ -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 1369363.xul
load 1370072.html
pref(clipboard.autocopy,true) load 1370737.html
pref(dom.IntersectionObserver.enabled,true) load 1370968.html
load structured_clone_container_throws.html
HTTP(..) load xhr_abortinprogress.html

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

@ -186,6 +186,10 @@ protected:
AutoTArray<int32_t, 8> mStartOffsets;
AutoTArray<nsIContent*, 8> mEndNodes;
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;
// Used when context has already been serialized for
// table cell selections (where parent is <tr>)
@ -221,6 +225,7 @@ void nsDocumentEncoder::Initialize(bool aClearCachedSerializer)
mEndDepth = 0;
mStartRootIndex = 0;
mEndRootIndex = 0;
mNeedsPreformatScanning = false;
mHaltRangeHint = false;
mDisableContextSerialize = false;
mNodeIsContainer = false;
@ -351,6 +356,10 @@ nsDocumentEncoder::SerializeNodeStart(nsINode* aNode,
nsAString& aStr,
nsINode* aOriginalNode)
{
if (mNeedsPreformatScanning && aNode->IsElement()) {
mSerializer->ScanElementForPreformat(aNode->AsElement());
}
if (!IsVisibleNode(aNode))
return NS_OK;
@ -428,6 +437,10 @@ nsresult
nsDocumentEncoder::SerializeNodeEnd(nsINode* aNode,
nsAString& aStr)
{
if (mNeedsPreformatScanning && aNode->IsElement()) {
mSerializer->ForgetElementForPreformat(aNode->AsElement());
}
if (!IsVisibleNode(aNode))
return NS_OK;
@ -1075,7 +1088,9 @@ nsDocumentEncoder::EncodeToStringWithMaxLength(uint32_t aMaxLength,
nsresult rv = NS_OK;
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) {
nsCOMPtr<nsIDOMRange> range;

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

@ -30,7 +30,8 @@ class nsIContentSerializer : public nsISupports {
NS_IMETHOD Init(uint32_t flags, uint32_t aWrapColumn,
const char* aCharSet, bool aIsCopying,
bool aIsWholeDocument) = 0;
bool aIsWholeDocument,
bool* aNeedsPerformatScanning) = 0;
NS_IMETHOD AppendText(nsIContent* aText, int32_t aStartOffset,
int32_t aEndOffset, nsAString& aStr) = 0;
@ -66,6 +67,14 @@ class nsIContentSerializer : public nsISupports {
*/
NS_IMETHOD AppendDocumentStart(nsIDocument *aDocument,
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)

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

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

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

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

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

@ -59,8 +59,9 @@ nsXHTMLContentSerializer::~nsXHTMLContentSerializer()
NS_IMETHODIMP
nsXHTMLContentSerializer::Init(uint32_t aFlags, uint32_t aWrapColumn,
const char* aCharSet, bool aIsCopying,
bool aRewriteEncodingDeclaration)
const char* aCharSet, bool aIsCopying,
bool aRewriteEncodingDeclaration,
bool* aNeedsPreformatScanning)
{
// The previous version of the HTML serializer did implicit wrapping
// 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;
rv = nsXMLContentSerializer::Init(aFlags, aWrapColumn, aCharSet, aIsCopying, aRewriteEncodingDeclaration);
rv = nsXMLContentSerializer::Init(aFlags, aWrapColumn, aCharSet,
aIsCopying, aRewriteEncodingDeclaration,
aNeedsPreformatScanning);
NS_ENSURE_SUCCESS(rv, rv);
mRewriteEncodingDeclaration = aRewriteEncodingDeclaration;

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

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

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

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

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

@ -34,7 +34,8 @@ class nsXMLContentSerializer : public nsIContentSerializer {
NS_IMETHOD Init(uint32_t flags, uint32_t aWrapColumn,
const char* aCharSet, bool aIsCopying,
bool aRewriteEncodingDeclaration) override;
bool aRewriteEncodingDeclaration,
bool* aNeedsPreformatScanning) override;
NS_IMETHOD AppendText(nsIContent* aText, int32_t aStartOffset,
int32_t aEndOffset, nsAString& aStr) override;
@ -66,6 +67,15 @@ class nsXMLContentSerializer : public nsIContentSerializer {
NS_IMETHOD AppendDocumentStart(nsIDocument *aDocument,
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:
virtual ~nsXMLContentSerializer();