nsHtml5String.cpp (5611B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 #include "nsHtml5String.h" 6 #include "nsCharTraits.h" 7 #include "nsHtml5TreeBuilder.h" 8 #include "mozilla/StringBuffer.h" 9 10 using mozilla::StringBuffer; 11 12 void nsHtml5String::ToString(nsAString& aString) { 13 switch (GetKind()) { 14 case eStringBuffer: 15 return aString.Assign(AsStringBuffer(), Length()); 16 case eAtom: 17 return AsAtom()->ToString(aString); 18 case eEmpty: 19 aString.Truncate(); 20 return; 21 default: 22 aString.Truncate(); 23 aString.SetIsVoid(true); 24 return; 25 } 26 } 27 28 void nsHtml5String::CopyToBuffer(char16_t* aBuffer) const { 29 memcpy(aBuffer, AsPtr(), Length() * sizeof(char16_t)); 30 } 31 32 bool nsHtml5String::LowerCaseEqualsASCII(const char* aLowerCaseLiteral) const { 33 return !nsCharTraits<char16_t>::compareLowerCaseToASCIINullTerminated( 34 AsPtr(), Length(), aLowerCaseLiteral); 35 } 36 37 bool nsHtml5String::EqualsASCII(const char* aLiteral) const { 38 return !nsCharTraits<char16_t>::compareASCIINullTerminated(AsPtr(), Length(), 39 aLiteral); 40 } 41 42 bool nsHtml5String::LowerCaseStartsWithASCII( 43 const char* aLowerCaseLiteral) const { 44 const char* litPtr = aLowerCaseLiteral; 45 const char16_t* strPtr = AsPtr(); 46 const char16_t* end = strPtr + Length(); 47 char16_t litChar; 48 while ((litChar = *litPtr)) { 49 MOZ_ASSERT(!(litChar >= 'A' && litChar <= 'Z'), 50 "Literal isn't in lower case."); 51 if (strPtr == end) { 52 return false; 53 } 54 char16_t strChar = *strPtr; 55 if (strChar >= 'A' && strChar <= 'Z') { 56 strChar += 0x20; 57 } 58 if (litChar != strChar) { 59 return false; 60 } 61 ++litPtr; 62 ++strPtr; 63 } 64 return true; 65 } 66 67 bool nsHtml5String::Equals(nsHtml5String aOther) const { 68 MOZ_ASSERT(operator bool()); 69 MOZ_ASSERT(aOther); 70 if (Length() != aOther.Length()) { 71 return false; 72 } 73 return !memcmp(AsPtr(), aOther.AsPtr(), Length() * sizeof(char16_t)); 74 } 75 76 nsHtml5String nsHtml5String::Clone() { 77 switch (GetKind()) { 78 case eStringBuffer: 79 AsStringBuffer()->AddRef(); 80 break; 81 case eAtom: 82 AsAtom()->AddRef(); 83 break; 84 default: 85 break; 86 } 87 return nsHtml5String(mBits); 88 } 89 90 void nsHtml5String::Release() { 91 switch (GetKind()) { 92 case eStringBuffer: 93 AsStringBuffer()->Release(); 94 break; 95 case eAtom: 96 AsAtom()->Release(); 97 break; 98 default: 99 break; 100 } 101 mBits = eNull; 102 } 103 104 // static 105 nsHtml5String nsHtml5String::FromBuffer(char16_t* aBuffer, int32_t aLength, 106 nsHtml5TreeBuilder* aTreeBuilder) { 107 if (!aLength) { 108 return nsHtml5String(eEmpty); 109 } 110 // Work with StringBuffer directly to make sure that storage is actually 111 // StringBuffer and to make sure the allocation strategy matches 112 // nsAttrValue::GetStringBuffer, so that it doesn't need to reallocate and 113 // copy. 114 RefPtr<StringBuffer> buffer = StringBuffer::Create(aBuffer, aLength); 115 if (MOZ_UNLIKELY(!buffer)) { 116 if (!aTreeBuilder) { 117 MOZ_CRASH("Out of memory."); 118 } 119 aTreeBuilder->MarkAsBroken(NS_ERROR_OUT_OF_MEMORY); 120 buffer = StringBuffer::Alloc(2 * sizeof(char16_t)); 121 if (!buffer) { 122 MOZ_CRASH( 123 "Out of memory so badly that couldn't even allocate placeholder."); 124 } 125 char16_t* data = reinterpret_cast<char16_t*>(buffer->Data()); 126 data[0] = 0xFFFD; 127 data[1] = 0; 128 } 129 return nsHtml5String(reinterpret_cast<uintptr_t>(buffer.forget().take()) | 130 eStringBuffer); 131 } 132 133 // static 134 nsHtml5String nsHtml5String::FromLiteral(const char* aLiteral) { 135 size_t length = std::strlen(aLiteral); 136 if (!length) { 137 return nsHtml5String(eEmpty); 138 } 139 // Work with StringBuffer directly to make sure that storage is actually 140 // StringBuffer and to make sure the allocation strategy matches 141 // nsAttrValue::GetStringBuffer, so that it doesn't need to reallocate and 142 // copy. 143 RefPtr<StringBuffer> buffer( 144 StringBuffer::Alloc((length + 1) * sizeof(char16_t))); 145 if (!buffer) { 146 MOZ_CRASH("Out of memory."); 147 } 148 char16_t* data = reinterpret_cast<char16_t*>(buffer->Data()); 149 ConvertAsciitoUtf16(mozilla::Span(aLiteral, length), 150 mozilla::Span(data, length)); 151 data[length] = 0; 152 return nsHtml5String(reinterpret_cast<uintptr_t>(buffer.forget().take()) | 153 eStringBuffer); 154 } 155 156 // static 157 nsHtml5String nsHtml5String::FromString(const nsAString& aString) { 158 auto length = aString.Length(); 159 if (!length) { 160 return nsHtml5String(eEmpty); 161 } 162 if (StringBuffer* buffer = aString.GetStringBuffer()) { 163 if (length == buffer->StorageSize() / sizeof(char16_t) - 1) { 164 buffer->AddRef(); 165 return nsHtml5String(reinterpret_cast<uintptr_t>(buffer) | eStringBuffer); 166 } 167 } 168 RefPtr<StringBuffer> buffer = 169 StringBuffer::Alloc((length + 1) * sizeof(char16_t)); 170 if (!buffer) { 171 MOZ_CRASH("Out of memory."); 172 } 173 char16_t* data = reinterpret_cast<char16_t*>(buffer->Data()); 174 memcpy(data, aString.BeginReading(), length * sizeof(char16_t)); 175 data[length] = 0; 176 return nsHtml5String(reinterpret_cast<uintptr_t>(buffer.forget().take()) | 177 eStringBuffer); 178 } 179 180 // static 181 nsHtml5String nsHtml5String::FromAtom(already_AddRefed<nsAtom> aAtom) { 182 return nsHtml5String(reinterpret_cast<uintptr_t>(aAtom.take()) | eAtom); 183 } 184 185 // static 186 nsHtml5String nsHtml5String::EmptyString() { return nsHtml5String(eEmpty); }