gecko-dev/parser/html/nsHtml5String.cpp

188 lines
5.7 KiB
C++

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsHtml5String.h"
#include "nsCharTraits.h"
#include "nsHtml5TreeBuilder.h"
#include "nsUTF8Utils.h"
void nsHtml5String::ToString(nsAString& aString) {
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) const {
memcpy(aBuffer, AsPtr(), Length() * sizeof(char16_t));
}
bool nsHtml5String::LowerCaseEqualsASCII(const char* aLowerCaseLiteral) const {
return !nsCharTraits<char16_t>::compareLowerCaseToASCIINullTerminated(
AsPtr(), Length(), aLowerCaseLiteral);
}
bool nsHtml5String::EqualsASCII(const char* aLiteral) const {
return !nsCharTraits<char16_t>::compareASCIINullTerminated(AsPtr(), Length(),
aLiteral);
}
bool nsHtml5String::LowerCaseStartsWithASCII(
const char* aLowerCaseLiteral) const {
const char* litPtr = aLowerCaseLiteral;
const char16_t* strPtr = AsPtr();
const char16_t* end = strPtr + Length();
char16_t litChar;
while ((litChar = *litPtr)) {
MOZ_ASSERT(!(litChar >= 'A' && litChar <= 'Z'),
"Literal isn't in lower case.");
if (strPtr == end) {
return false;
}
char16_t strChar = *strPtr;
if (strChar >= 'A' && strChar <= 'Z') {
strChar += 0x20;
}
if (litChar != strChar) {
return false;
}
++litPtr;
++strPtr;
}
return true;
}
bool nsHtml5String::Equals(nsHtml5String aOther) const {
MOZ_ASSERT(operator bool());
MOZ_ASSERT(aOther);
if (Length() != aOther.Length()) {
return false;
}
return !memcmp(AsPtr(), aOther.AsPtr(), Length() * sizeof(char16_t));
}
nsHtml5String nsHtml5String::Clone() {
switch (GetKind()) {
case eStringBuffer:
AsStringBuffer()->AddRef();
break;
case eAtom:
AsAtom()->AddRef();
break;
default:
break;
}
return nsHtml5String(mBits);
}
void nsHtml5String::Release() {
switch (GetKind()) {
case eStringBuffer:
AsStringBuffer()->Release();
break;
case eAtom:
AsAtom()->Release();
break;
default:
break;
}
mBits = eNull;
}
// static
nsHtml5String nsHtml5String::FromBuffer(char16_t* aBuffer, int32_t aLength,
nsHtml5TreeBuilder* aTreeBuilder) {
if (!aLength) {
return nsHtml5String(eEmpty);
}
// Work with nsStringBuffer directly to make sure that storage is actually
// nsStringBuffer and to make sure the allocation strategy matches
// nsAttrValue::GetStringBuffer, so that it doesn't need to reallocate and
// copy.
RefPtr<nsStringBuffer> buffer(
nsStringBuffer::Alloc((aLength + 1) * sizeof(char16_t)));
if (!buffer) {
if (!aTreeBuilder) {
MOZ_CRASH("Out of memory.");
}
aTreeBuilder->MarkAsBroken(NS_ERROR_OUT_OF_MEMORY);
buffer = nsStringBuffer::Alloc(2 * sizeof(char16_t));
if (!buffer) {
MOZ_CRASH(
"Out of memory so badly that couldn't even allocate placeholder.");
}
char16_t* data = reinterpret_cast<char16_t*>(buffer->Data());
data[0] = 0xFFFD;
data[1] = 0;
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(reinterpret_cast<uintptr_t>(buffer.forget().take()) |
eStringBuffer);
}
// static
nsHtml5String nsHtml5String::FromLiteral(const char* aLiteral) {
size_t length = std::strlen(aLiteral);
if (!length) {
return nsHtml5String(eEmpty);
}
// Work with nsStringBuffer directly to make sure that storage is actually
// nsStringBuffer and to make sure the allocation strategy matches
// nsAttrValue::GetStringBuffer, so that it doesn't need to reallocate and
// copy.
RefPtr<nsStringBuffer> buffer(
nsStringBuffer::Alloc((length + 1) * sizeof(char16_t)));
if (!buffer) {
MOZ_CRASH("Out of memory.");
}
char16_t* data = reinterpret_cast<char16_t*>(buffer->Data());
ConvertAsciitoUtf16(Span(aLiteral, length), Span(data, length));
data[length] = 0;
return nsHtml5String(reinterpret_cast<uintptr_t>(buffer.forget().take()) |
eStringBuffer);
}
// static
nsHtml5String nsHtml5String::FromString(const nsAString& aString) {
auto length = aString.Length();
if (!length) {
return nsHtml5String(eEmpty);
}
RefPtr<nsStringBuffer> buffer = nsStringBuffer::FromString(aString);
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) {
MOZ_CRASH("Out of memory.");
}
char16_t* data = reinterpret_cast<char16_t*>(buffer->Data());
memcpy(data, aString.BeginReading(), length * sizeof(char16_t));
data[length] = 0;
return nsHtml5String(reinterpret_cast<uintptr_t>(buffer.forget().take()) |
eStringBuffer);
}
// static
nsHtml5String nsHtml5String::FromAtom(already_AddRefed<nsAtom> aAtom) {
return nsHtml5String(reinterpret_cast<uintptr_t>(aAtom.take()) | eAtom);
}
// static
nsHtml5String nsHtml5String::EmptyString() { return nsHtml5String(eEmpty); }