Bug 1375701 - Atomize class attribute value in the parser in the innerHTML case. r=Ehsan

MozReview-Commit-ID: CKyGlzYS15e

--HG--
extra : rebase_source : a66d3d1659aec509c50f3ca641c0eb1d87151104
This commit is contained in:
Henri Sivonen 2017-08-11 09:22:57 +03:00
parent a2357cf0c9
commit 6815b2d2c7
14 changed files with 292 additions and 162 deletions

View File

@ -2405,12 +2405,45 @@ Element::OnlyNotifySameValueSet(int32_t aNamespaceID, nsIAtom* aName,
return true;
}
nsresult
Element::SetSingleClassFromParser(nsIAtom* aSingleClassName)
{
// Keep this in sync with SetAttr and SetParsedAttr below.
if (!mAttrsAndChildren.CanFitMoreAttrs()) {
return NS_ERROR_FAILURE;
}
nsAttrValue value(aSingleClassName);
nsIDocument* document = GetComposedDoc();
mozAutoDocUpdate updateBatch(document, UPDATE_CONTENT_MODEL, false);
// In principle, BeforeSetAttr should be called here if a node type
// existed that wanted to do something special for class, but there
// is no such node type, so calling SetMayHaveClass() directly.
SetMayHaveClass();
return SetAttrAndNotify(kNameSpaceID_None,
nsGkAtoms::_class,
nullptr, // prefix
nullptr, // old value
value,
static_cast<uint8_t>(nsIDOMMutationEvent::ADDITION),
false, // hasListeners
false, // notify
kCallAfterSetAttr,
document,
updateBatch);
}
nsresult
Element::SetAttr(int32_t aNamespaceID, nsIAtom* aName,
nsIAtom* aPrefix, const nsAString& aValue,
bool aNotify)
{
// Keep this in sync with SetParsedAttr below
// Keep this in sync with SetParsedAttr below and SetSingleClassFromParser
// above.
NS_ENSURE_ARG_POINTER(aName);
NS_ASSERTION(aNamespaceID != kNameSpaceID_Unknown,
@ -2475,7 +2508,7 @@ Element::SetParsedAttr(int32_t aNamespaceID, nsIAtom* aName,
nsIAtom* aPrefix, nsAttrValue& aParsedValue,
bool aNotify)
{
// Keep this in sync with SetAttr above
// Keep this in sync with SetAttr and SetSingleClassFromParser above
NS_ENSURE_ARG_POINTER(aName);
NS_ASSERTION(aNamespaceID != kNameSpaceID_Unknown,
@ -2709,6 +2742,10 @@ Element::BeforeSetAttr(int32_t aNamespaceID, nsIAtom* aName,
// If it is ever made to be exact, we probably need to handle this
// similarly to how ids are handled in PreIdMaybeChange and
// PostIdMaybeChange.
// Note that SetSingleClassFromParser inlines BeforeSetAttr and
// calls SetMayHaveClass directly. Making a subclass take action
// on the class attribute in a BeforeSetAttr override would
// require revising SetSingleClassFromParser.
SetMayHaveClass();
}
}

View File

@ -706,6 +706,13 @@ public:
uint8_t* aModType, bool* aHasListeners,
bool* aOldValueSet);
/**
* Sets the class attribute to a value that contains no whitespace.
* Assumes that we are not notifying and that the attribute hasn't been
* set previously.
*/
nsresult SetSingleClassFromParser(nsIAtom* aSingleClassName);
virtual nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName, nsIAtom* aPrefix,
const nsAString& aValue, bool aNotify) override;
// aParsedValue receives the old value of the attribute. That's useful if

View File

@ -797,13 +797,13 @@ public abstract class MetaScanner {
}
if (contentIndex == CONTENT.length && content == null) {
content = Portability.newStringFromBuffer(strBuf, 0, strBufLen
// CPPONLY: , treeBuilder
// CPPONLY: , treeBuilder, false
);
return;
}
if (charsetIndex == CHARSET.length && charset == null) {
charset = Portability.newStringFromBuffer(strBuf, 0, strBufLen
// CPPONLY: , treeBuilder
// CPPONLY: , treeBuilder, false
);
return;
}

View File

@ -40,7 +40,7 @@ public final class Portability {
}
public static String newStringFromBuffer(@NoLength char[] buf, int offset, int length
// CPPONLY: , TreeBuilder treeBuilder
// CPPONLY: , TreeBuilder treeBuilder, boolean maybeAtomize
) {
return new String(buf, offset, length);
}

View File

@ -897,7 +897,7 @@ public class Tokenizer implements Locator {
*/
protected String strBufToString() {
String str = Portability.newStringFromBuffer(strBuf, 0, strBufLen
// CPPONLY: , tokenHandler
// CPPONLY: , tokenHandler, !newAttributesEachTime && attributeName == AttributeName.CLASS
);
clearStrBufAfterUse();
return str;

View File

@ -3293,7 +3293,7 @@ public abstract class TreeBuilder<T> implements TokenHandler,
}
charset = Portability.newStringFromBuffer(buffer, start, end
- start
// CPPONLY: , tb
// CPPONLY: , tb, false
);
}
return charset;

View File

@ -755,11 +755,13 @@ nsHtml5MetaScanner::handleAttributeValue()
return;
}
if (contentIndex == CONTENT.length && !content) {
content = nsHtml5Portability::newStringFromBuffer(strBuf, 0, strBufLen, treeBuilder);
content = nsHtml5Portability::newStringFromBuffer(
strBuf, 0, strBufLen, treeBuilder, false);
return;
}
if (charsetIndex == CHARSET.length && !charset) {
charset = nsHtml5Portability::newStringFromBuffer(strBuf, 0, strBufLen, treeBuilder);
charset = nsHtml5Portability::newStringFromBuffer(
strBuf, 0, strBufLen, treeBuilder, false);
return;
}
if (httpEquivIndex == HTTP_EQUIV.length &&

View File

@ -16,12 +16,30 @@ nsHtml5Portability::newLocalNameFromBuffer(char16_t* buf, int32_t offset, int32_
return interner->GetAtom(nsDependentSubstring(buf, buf + length));
}
static bool
ContainsWhiteSpace(mozilla::Span<char16_t> aSpan)
{
for (char16_t c : aSpan) {
if (nsContentUtils::IsHTMLWhitespace(c)) {
return true;
}
}
return false;
}
nsHtml5String
nsHtml5Portability::newStringFromBuffer(char16_t* buf,
int32_t offset,
int32_t length,
nsHtml5TreeBuilder* treeBuilder)
nsHtml5TreeBuilder* treeBuilder,
bool maybeAtomize)
{
if (!length) {
return nsHtml5String::EmptyString();
}
if (maybeAtomize && !ContainsWhiteSpace(mozilla::MakeSpan(buf + offset, length))) {
return nsHtml5String::FromAtom(NS_AtomizeMainThread(nsDependentSubstring(buf + offset, length)));
}
return nsHtml5String::FromBuffer(buf + offset, length, treeBuilder);
}

View File

@ -61,7 +61,8 @@ class nsHtml5Portability
static nsHtml5String newStringFromBuffer(char16_t* buf,
int32_t offset,
int32_t length,
nsHtml5TreeBuilder* treeBuilder);
nsHtml5TreeBuilder* treeBuilder,
bool maybeAtomize);
static nsHtml5String newEmptyString();
static nsHtml5String newStringFromLiteral(const char* literal);
static nsHtml5String newStringFromString(nsHtml5String string);

View File

@ -7,82 +7,49 @@
#include "nsUTF8Utils.h"
#include "nsHtml5TreeBuilder.h"
nsHtml5String::nsHtml5String(already_AddRefed<nsStringBuffer> aBuffer,
uint32_t aLength)
: mBuffer(aBuffer.take())
, mLength(aLength)
{
if (mBuffer) {
MOZ_ASSERT(aLength);
} else {
MOZ_ASSERT(!aLength || aLength == UINT32_MAX);
}
}
void
nsHtml5String::ToString(nsAString& aString)
{
if (mBuffer) {
mBuffer->ToString(mLength, aString);
} else {
aString.Truncate();
if (mLength) {
switch (GetKind()) {
case eStringBuffer:
return AsStringBuffer()->ToString(Length(), aString);
case eAtom:
return AsAtom()->ToString(aString);
case eEmpty:
aString.Truncate();
return;
default:
aString.Truncate();
aString.SetIsVoid(true);
}
return;
}
}
void
nsHtml5String::CopyToBuffer(char16_t* aBuffer)
nsHtml5String::CopyToBuffer(char16_t* aBuffer) const
{
if (mBuffer) {
memcpy(aBuffer, mBuffer->Data(), mLength * sizeof(char16_t));
}
memcpy(aBuffer, AsPtr(), Length() * sizeof(char16_t));
}
bool
nsHtml5String::LowerCaseEqualsASCII(const char* aLowerCaseLiteral)
nsHtml5String::LowerCaseEqualsASCII(const char* aLowerCaseLiteral) const
{
if (!mBuffer) {
if (mLength) {
// This string is null
return false;
}
// this string is empty
return !(*aLowerCaseLiteral);
}
return !nsCharTraits<char16_t>::compareLowerCaseToASCIINullTerminated(
reinterpret_cast<char16_t*>(mBuffer->Data()), Length(), aLowerCaseLiteral);
AsPtr(), Length(), aLowerCaseLiteral);
}
bool
nsHtml5String::EqualsASCII(const char* aLiteral)
nsHtml5String::EqualsASCII(const char* aLiteral) const
{
if (!mBuffer) {
if (mLength) {
// This string is null
return false;
}
// this string is empty
return !(*aLiteral);
}
return !nsCharTraits<char16_t>::compareASCIINullTerminated(
reinterpret_cast<char16_t*>(mBuffer->Data()), Length(), aLiteral);
AsPtr(), Length(), aLiteral);
}
bool
nsHtml5String::LowerCaseStartsWithASCII(const char* aLowerCaseLiteral)
nsHtml5String::LowerCaseStartsWithASCII(const char* aLowerCaseLiteral) const
{
if (!mBuffer) {
if (mLength) {
// This string is null
return false;
}
// this string is empty
return !(*aLowerCaseLiteral);
}
const char* litPtr = aLowerCaseLiteral;
const char16_t* strPtr = reinterpret_cast<char16_t*>(mBuffer->Data());
const char16_t* strPtr = AsPtr();
const char16_t* end = strPtr + Length();
char16_t litChar;
while ((litChar = *litPtr) && (strPtr != end)) {
@ -102,37 +69,47 @@ nsHtml5String::LowerCaseStartsWithASCII(const char* aLowerCaseLiteral)
}
bool
nsHtml5String::Equals(nsHtml5String aOther)
nsHtml5String::Equals(nsHtml5String aOther) const
{
MOZ_ASSERT(operator bool());
MOZ_ASSERT(aOther);
if (mLength != aOther.mLength) {
if (Length() != aOther.Length()) {
return false;
}
if (!mBuffer) {
return true;
}
MOZ_ASSERT(aOther.mBuffer);
return !memcmp(
mBuffer->Data(), aOther.mBuffer->Data(), Length() * sizeof(char16_t));
AsPtr(), aOther.AsPtr(), Length() * sizeof(char16_t));
}
nsHtml5String
nsHtml5String::Clone()
{
MOZ_ASSERT(operator bool());
RefPtr<nsStringBuffer> ref(mBuffer);
return nsHtml5String(ref.forget(), mLength);
switch (GetKind()) {
case eStringBuffer:
AsStringBuffer()->AddRef();
break;
case eAtom:
AsAtom()->AddRef();
break;
default:
break;
}
return nsHtml5String(mBits);
}
void
nsHtml5String::Release()
{
if (mBuffer) {
mBuffer->Release();
mBuffer = nullptr;
switch (GetKind()) {
case eStringBuffer:
AsStringBuffer()->Release();
break;
case eAtom:
AsAtom()->Release();
break;
default:
break;
}
mLength = UINT32_MAX;
mBits = eNull;
}
// static
@ -142,7 +119,7 @@ nsHtml5String::FromBuffer(char16_t* aBuffer,
nsHtml5TreeBuilder* aTreeBuilder)
{
if (!aLength) {
return nsHtml5String(nullptr, 0U);
return nsHtml5String(eEmpty);
}
// Work with nsStringBuffer directly to make sure that storage is actually
// nsStringBuffer and to make sure the allocation strategy matches
@ -163,12 +140,12 @@ nsHtml5String::FromBuffer(char16_t* aBuffer,
char16_t* data = reinterpret_cast<char16_t*>(buffer->Data());
data[0] = 0xFFFD;
data[1] = 0;
return nsHtml5String(buffer.forget(), 1);
return nsHtml5String(reinterpret_cast<uintptr_t>(buffer.forget().take()) | eStringBuffer);
}
char16_t* data = reinterpret_cast<char16_t*>(buffer->Data());
memcpy(data, aBuffer, aLength * sizeof(char16_t));
data[aLength] = 0;
return nsHtml5String(buffer.forget(), aLength);
return nsHtml5String(reinterpret_cast<uintptr_t>(buffer.forget().take()) | eStringBuffer);
}
// static
@ -177,7 +154,7 @@ nsHtml5String::FromLiteral(const char* aLiteral)
{
size_t length = std::strlen(aLiteral);
if (!length) {
return nsHtml5String(nullptr, 0U);
return nsHtml5String(eEmpty);
}
// Work with nsStringBuffer directly to make sure that storage is actually
// nsStringBuffer and to make sure the allocation strategy matches
@ -192,7 +169,7 @@ nsHtml5String::FromLiteral(const char* aLiteral)
LossyConvertEncoding8to16 converter(data);
converter.write(aLiteral, length);
data[length] = 0;
return nsHtml5String(buffer.forget(), length);
return nsHtml5String(reinterpret_cast<uintptr_t>(buffer.forget().take()) | eStringBuffer);
}
// static
@ -201,11 +178,11 @@ nsHtml5String::FromString(const nsAString& aString)
{
auto length = aString.Length();
if (!length) {
return nsHtml5String(nullptr, 0U);
return nsHtml5String(eEmpty);
}
RefPtr<nsStringBuffer> buffer = nsStringBuffer::FromString(aString);
if (buffer) {
return nsHtml5String(buffer.forget(), length);
if (buffer && (length == buffer->StorageSize()/sizeof(char16_t) - 1)) {
return nsHtml5String(reinterpret_cast<uintptr_t>(buffer.forget().take()) | eStringBuffer);
}
buffer = nsStringBuffer::Alloc((length + 1) * sizeof(char16_t));
if (!buffer) {
@ -214,12 +191,19 @@ nsHtml5String::FromString(const nsAString& aString)
char16_t* data = reinterpret_cast<char16_t*>(buffer->Data());
memcpy(data, aString.BeginReading(), length * sizeof(char16_t));
data[length] = 0;
return nsHtml5String(buffer.forget(), length);
return nsHtml5String(reinterpret_cast<uintptr_t>(buffer.forget().take()) | eStringBuffer);
}
// static
nsHtml5String
nsHtml5String::FromAtom(already_AddRefed<nsIAtom> aAtom)
{
return nsHtml5String(reinterpret_cast<uintptr_t>(aAtom.take()) | eAtom);
}
// static
nsHtml5String
nsHtml5String::EmptyString()
{
return nsHtml5String(nullptr, 0U);
return nsHtml5String(eEmpty);
}

View File

@ -6,24 +6,61 @@
#define nsHtml5String_h
#include "nsString.h"
#include "nsIAtom.h"
class nsHtml5TreeBuilder;
/**
* A pass-by-value type that combines an unsafe `nsStringBuffer*` with its
* logical length (`uint32_t`). (`nsStringBuffer` knows its capacity but not
* its logical length, i.e. how much of the capacity is in use.)
* A pass-by-value type that can represent
* * nullptr
* * empty string
* * Non-empty string as exactly-sized (capacity is length) `nsStringBuffer*`
* * Non-empty string as an nsIAtom*
*
* Holding or passing this type is as unsafe as holding or passing
* `nsStringBuffer*`.
*
* Empty strings and null strings are distinct. Since an empty nsString does
* not have a an `nsStringBuffer`, both empty and null `nsHtml5String` have
* `nullptr` as `mBuffer`. If `mBuffer` is `nullptr`, the empty case is marked
* with `mLength` being zero and the null case with `mLength` being non-zero.
* `nsStringBuffer*`/`nsIAtom*`.
*/
class nsHtml5String final
{
private:
static const uintptr_t kKindMask = uintptr_t(3);
static const uintptr_t kPtrMask = ~kKindMask;
enum Kind : uintptr_t {
eNull = 0,
eEmpty = 1,
eStringBuffer = 2,
eAtom = 3,
};
inline Kind GetKind() const { return (Kind)(mBits & kKindMask); }
inline nsStringBuffer* AsStringBuffer() const
{
MOZ_ASSERT(GetKind() == eStringBuffer);
return reinterpret_cast<nsStringBuffer*>(mBits & kPtrMask);
}
inline nsIAtom* AsAtom() const
{
MOZ_ASSERT(GetKind() == eAtom);
return reinterpret_cast<nsIAtom*>(mBits & kPtrMask);
}
inline const char16_t* AsPtr() const
{
switch (GetKind()) {
case eStringBuffer:
return reinterpret_cast<char16_t*>(AsStringBuffer()->Data());
case eAtom:
return AsAtom()->GetUTF16String();
default:
return nullptr;
}
}
public:
/**
* Default constructor.
@ -37,29 +74,50 @@ public:
* Constructor from nullptr.
*/
inline MOZ_IMPLICIT nsHtml5String(decltype(nullptr))
: mBuffer(nullptr)
, mLength(UINT32_MAX)
: mBits(eNull)
{
}
inline uint32_t Length() const { return mBuffer ? mLength : 0; }
inline uint32_t Length() const
{
switch (GetKind()) {
case eStringBuffer:
return (AsStringBuffer()->StorageSize()/sizeof(char16_t) - 1);
case eAtom:
return AsAtom()->GetLength();
default:
return 0;
}
}
/**
* False iff the string is logically null
*/
inline MOZ_IMPLICIT operator bool() const { return !(!mBuffer && mLength); }
inline MOZ_IMPLICIT operator bool() const { return mBits; }
/**
* Get the underlying nsIAtom* or nullptr if this nsHtml5String
* does not hold an atom.
*/
inline nsIAtom* MaybeAsAtom()
{
if (GetKind() == eAtom) {
return AsAtom();
}
return nullptr;
}
void ToString(nsAString& aString);
void CopyToBuffer(char16_t* aBuffer);
void CopyToBuffer(char16_t* aBuffer) const;
bool LowerCaseEqualsASCII(const char* aLowerCaseLiteral);
bool LowerCaseEqualsASCII(const char* aLowerCaseLiteral) const;
bool EqualsASCII(const char* aLiteral);
bool EqualsASCII(const char* aLiteral) const;
bool LowerCaseStartsWithASCII(const char* aLowerCaseLiteral);
bool LowerCaseStartsWithASCII(const char* aLowerCaseLiteral) const;
bool Equals(nsHtml5String aOther);
bool Equals(nsHtml5String aOther) const;
nsHtml5String Clone();
@ -73,23 +131,23 @@ public:
static nsHtml5String FromString(const nsAString& aString);
static nsHtml5String FromAtom(already_AddRefed<nsIAtom> aAtom);
static nsHtml5String EmptyString();
private:
/**
* Constructor from raw parts.
*/
nsHtml5String(already_AddRefed<nsStringBuffer> aBuffer, uint32_t aLength);
/**
* nullptr if the string is logically null or logically empty
* Constructor from raw bits.
*/
nsStringBuffer* mBuffer;
nsHtml5String(uintptr_t aBits) : mBits(aBits) {};
/**
* The length of the string. non-zero if the string is logically null.
* Zero if null, one if empty, otherwise tagged pointer
* to either nsIAtom or nsStringBuffer. The two least-significant
* bits are tag bits.
*/
uint32_t mLength;
uintptr_t mBits;
};
#endif // nsHtml5String_h

View File

@ -231,8 +231,13 @@ nsHtml5Tokenizer::emitOrAppendCharRefBuf(int32_t returnState)
nsHtml5String
nsHtml5Tokenizer::strBufToString()
{
nsHtml5String str =
nsHtml5Portability::newStringFromBuffer(strBuf, 0, strBufLen, tokenHandler);
nsHtml5String str = nsHtml5Portability::newStringFromBuffer(
strBuf,
0,
strBufLen,
tokenHandler,
!newAttributesEachTime &&
attributeName == nsHtml5AttributeName::ATTR_CLASS);
clearStrBufAfterUse();
return str;
}

View File

@ -2220,8 +2220,8 @@ nsHtml5TreeBuilder::extractCharsetFromContent(nsHtml5String attributeValue,
if (end == -1) {
end = buffer.length;
}
charset =
nsHtml5Portability::newStringFromBuffer(buffer, start, end - start, tb);
charset = nsHtml5Portability::newStringFromBuffer(
buffer, start, end - start, tb, false);
}
return charset;
}

View File

@ -413,35 +413,41 @@ nsHtml5TreeOperation::CreateHTMLElement(
int32_t len = aAttributes->getLength();
for (int32_t i = 0; i < len; i++) {
// prefix doesn't need regetting. it is always null or a static atom
// local name is never null
nsCOMPtr<nsIAtom> localName =
Reget(aAttributes->getLocalNameNoBoundsCheck(i));
nsCOMPtr<nsIAtom> prefix = aAttributes->getPrefixNoBoundsCheck(i);
int32_t nsuri = aAttributes->getURINoBoundsCheck(i);
nsString value; // Not Auto, because using it to hold nsStringBuffer*
aAttributes->getValueNoBoundsCheck(i).ToString(value);
if (nsGkAtoms::a == aName && nsGkAtoms::name == localName) {
// This is an HTML5-incompliant Geckoism.
// Remove when fixing bug 582361
NS_ConvertUTF16toUTF8 cname(value);
NS_ConvertUTF8toUTF16 uv(nsUnescape(cname.BeginWriting()));
newContent->SetAttr(nsuri,
localName,
prefix,
uv,
false);
nsHtml5String val = aAttributes->getValueNoBoundsCheck(i);
nsIAtom* klass = val.MaybeAsAtom();
if (klass) {
newContent->SetSingleClassFromParser(klass);
} else {
newContent->SetAttr(nsuri,
localName,
prefix,
value,
false);
// prefix doesn't need regetting. it is always null or a static atom
// local name is never null
nsCOMPtr<nsIAtom> localName =
Reget(aAttributes->getLocalNameNoBoundsCheck(i));
nsCOMPtr<nsIAtom> prefix = aAttributes->getPrefixNoBoundsCheck(i);
int32_t nsuri = aAttributes->getURINoBoundsCheck(i);
// Custom element setup may be needed if there is an "is" attribute.
if (kNameSpaceID_None == nsuri && !prefix && nsGkAtoms::is == localName) {
nsContentUtils::SetupCustomElement(newContent, &value);
nsString value; // Not Auto, because using it to hold nsStringBuffer*
val.ToString(value);
if (nsGkAtoms::a == aName && nsGkAtoms::name == localName) {
// This is an HTML5-incompliant Geckoism.
// Remove when fixing bug 582361
NS_ConvertUTF16toUTF8 cname(value);
NS_ConvertUTF8toUTF16 uv(nsUnescape(cname.BeginWriting()));
newContent->SetAttr(nsuri,
localName,
prefix,
uv,
false);
} else {
newContent->SetAttr(nsuri,
localName,
prefix,
value,
false);
// Custom element setup may be needed if there is an "is" attribute.
if (kNameSpaceID_None == nsuri && !prefix && nsGkAtoms::is == localName) {
nsContentUtils::SetupCustomElement(newContent, &value);
}
}
}
}
@ -497,16 +503,22 @@ nsHtml5TreeOperation::CreateSVGElement(
int32_t len = aAttributes->getLength();
for (int32_t i = 0; i < len; i++) {
// prefix doesn't need regetting. it is always null or a static atom
// local name is never null
nsCOMPtr<nsIAtom> localName =
Reget(aAttributes->getLocalNameNoBoundsCheck(i));
nsCOMPtr<nsIAtom> prefix = aAttributes->getPrefixNoBoundsCheck(i);
int32_t nsuri = aAttributes->getURINoBoundsCheck(i);
nsHtml5String val = aAttributes->getValueNoBoundsCheck(i);
nsIAtom* klass = val.MaybeAsAtom();
if (klass) {
newContent->SetSingleClassFromParser(klass);
} else {
// prefix doesn't need regetting. it is always null or a static atom
// local name is never null
nsCOMPtr<nsIAtom> localName =
Reget(aAttributes->getLocalNameNoBoundsCheck(i));
nsCOMPtr<nsIAtom> prefix = aAttributes->getPrefixNoBoundsCheck(i);
int32_t nsuri = aAttributes->getURINoBoundsCheck(i);
nsString value; // Not Auto, because using it to hold nsStringBuffer*
aAttributes->getValueNoBoundsCheck(i).ToString(value);
newContent->SetAttr(nsuri, localName, prefix, value, false);
nsString value; // Not Auto, because using it to hold nsStringBuffer*
val.ToString(value);
newContent->SetAttr(nsuri, localName, prefix, value, false);
}
}
return newContent;
}
@ -545,16 +557,22 @@ nsHtml5TreeOperation::CreateMathMLElement(nsIAtom* aName,
int32_t len = aAttributes->getLength();
for (int32_t i = 0; i < len; i++) {
// prefix doesn't need regetting. it is always null or a static atom
// local name is never null
nsCOMPtr<nsIAtom> localName =
Reget(aAttributes->getLocalNameNoBoundsCheck(i));
nsCOMPtr<nsIAtom> prefix = aAttributes->getPrefixNoBoundsCheck(i);
int32_t nsuri = aAttributes->getURINoBoundsCheck(i);
nsHtml5String val = aAttributes->getValueNoBoundsCheck(i);
nsIAtom* klass = val.MaybeAsAtom();
if (klass) {
newContent->SetSingleClassFromParser(klass);
} else {
// prefix doesn't need regetting. it is always null or a static atom
// local name is never null
nsCOMPtr<nsIAtom> localName =
Reget(aAttributes->getLocalNameNoBoundsCheck(i));
nsCOMPtr<nsIAtom> prefix = aAttributes->getPrefixNoBoundsCheck(i);
int32_t nsuri = aAttributes->getURINoBoundsCheck(i);
nsString value; // Not Auto, because using it to hold nsStringBuffer*
aAttributes->getValueNoBoundsCheck(i).ToString(value);
newContent->SetAttr(nsuri, localName, prefix, value, false);
nsString value; // Not Auto, because using it to hold nsStringBuffer*
val.ToString(value);
newContent->SetAttr(nsuri, localName, prefix, value, false);
}
}
return newContent;
}