Thu, 15 Jan 2015 21:03:48 +0100
Integrate friendly tips from Tor colleagues to make (or not) 4.5 alpha 3;
This includes removal of overloaded (but unused) methods, and addition of
a overlooked call to DataStruct::SetData(nsISupports, uint32_t, bool.)
michael@0 | 1 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 4 | |
michael@0 | 5 | /* |
michael@0 | 6 | * A class which represents a fragment of text (eg inside a text |
michael@0 | 7 | * node); if only codepoints below 256 are used, the text is stored as |
michael@0 | 8 | * a char*; otherwise the text is stored as a char16_t* |
michael@0 | 9 | */ |
michael@0 | 10 | |
michael@0 | 11 | #ifndef nsTextFragment_h___ |
michael@0 | 12 | #define nsTextFragment_h___ |
michael@0 | 13 | |
michael@0 | 14 | #include "mozilla/Attributes.h" |
michael@0 | 15 | #include "mozilla/MemoryReporting.h" |
michael@0 | 16 | |
michael@0 | 17 | #include "nsString.h" |
michael@0 | 18 | #include "nsReadableUtils.h" |
michael@0 | 19 | #include "nsISupportsImpl.h" |
michael@0 | 20 | |
michael@0 | 21 | class nsString; |
michael@0 | 22 | class nsCString; |
michael@0 | 23 | |
michael@0 | 24 | // XXX should this normalize the code to keep a \u0000 at the end? |
michael@0 | 25 | |
michael@0 | 26 | // XXX nsTextFragmentPool? |
michael@0 | 27 | |
michael@0 | 28 | /** |
michael@0 | 29 | * A fragment of text. If mIs2b is 1 then the m2b pointer is valid |
michael@0 | 30 | * otherwise the m1b pointer is valid. If m1b is used then each byte |
michael@0 | 31 | * of data represents a single ucs2 character with the high byte being |
michael@0 | 32 | * zero. |
michael@0 | 33 | * |
michael@0 | 34 | * This class does not have a virtual destructor therefore it is not |
michael@0 | 35 | * meant to be subclassed. |
michael@0 | 36 | */ |
michael@0 | 37 | class nsTextFragment MOZ_FINAL { |
michael@0 | 38 | public: |
michael@0 | 39 | static nsresult Init(); |
michael@0 | 40 | static void Shutdown(); |
michael@0 | 41 | |
michael@0 | 42 | /** |
michael@0 | 43 | * Default constructor. Initialize the fragment to be empty. |
michael@0 | 44 | */ |
michael@0 | 45 | nsTextFragment() |
michael@0 | 46 | : m1b(nullptr), mAllBits(0) |
michael@0 | 47 | { |
michael@0 | 48 | MOZ_COUNT_CTOR(nsTextFragment); |
michael@0 | 49 | NS_ASSERTION(sizeof(FragmentBits) == 4, "Bad field packing!"); |
michael@0 | 50 | } |
michael@0 | 51 | |
michael@0 | 52 | ~nsTextFragment(); |
michael@0 | 53 | |
michael@0 | 54 | /** |
michael@0 | 55 | * Change the contents of this fragment to be a copy of the |
michael@0 | 56 | * the argument fragment, or to "" if unable to allocate enough memory. |
michael@0 | 57 | */ |
michael@0 | 58 | nsTextFragment& operator=(const nsTextFragment& aOther); |
michael@0 | 59 | |
michael@0 | 60 | /** |
michael@0 | 61 | * Return true if this fragment is represented by char16_t data |
michael@0 | 62 | */ |
michael@0 | 63 | bool Is2b() const |
michael@0 | 64 | { |
michael@0 | 65 | return mState.mIs2b; |
michael@0 | 66 | } |
michael@0 | 67 | |
michael@0 | 68 | /** |
michael@0 | 69 | * Return true if this fragment contains Bidi text |
michael@0 | 70 | * For performance reasons this flag is only set if explicitely requested (by |
michael@0 | 71 | * setting the aUpdateBidi argument on SetTo or Append to true). |
michael@0 | 72 | */ |
michael@0 | 73 | bool IsBidi() const |
michael@0 | 74 | { |
michael@0 | 75 | return mState.mIsBidi; |
michael@0 | 76 | } |
michael@0 | 77 | |
michael@0 | 78 | /** |
michael@0 | 79 | * Get a pointer to constant char16_t data. |
michael@0 | 80 | */ |
michael@0 | 81 | const char16_t *Get2b() const |
michael@0 | 82 | { |
michael@0 | 83 | NS_ASSERTION(Is2b(), "not 2b text"); |
michael@0 | 84 | return m2b; |
michael@0 | 85 | } |
michael@0 | 86 | |
michael@0 | 87 | /** |
michael@0 | 88 | * Get a pointer to constant char data. |
michael@0 | 89 | */ |
michael@0 | 90 | const char *Get1b() const |
michael@0 | 91 | { |
michael@0 | 92 | NS_ASSERTION(!Is2b(), "not 1b text"); |
michael@0 | 93 | return (const char *)m1b; |
michael@0 | 94 | } |
michael@0 | 95 | |
michael@0 | 96 | /** |
michael@0 | 97 | * Get the length of the fragment. The length is the number of logical |
michael@0 | 98 | * characters, not the number of bytes to store the characters. |
michael@0 | 99 | */ |
michael@0 | 100 | uint32_t GetLength() const |
michael@0 | 101 | { |
michael@0 | 102 | return mState.mLength; |
michael@0 | 103 | } |
michael@0 | 104 | |
michael@0 | 105 | bool CanGrowBy(size_t n) const |
michael@0 | 106 | { |
michael@0 | 107 | return n < (1 << 29) && mState.mLength + n < (1 << 29); |
michael@0 | 108 | } |
michael@0 | 109 | |
michael@0 | 110 | /** |
michael@0 | 111 | * Change the contents of this fragment to be a copy of the given |
michael@0 | 112 | * buffer. If aUpdateBidi is true, contents of the fragment will be scanned, |
michael@0 | 113 | * and mState.mIsBidi will be turned on if it includes any Bidi characters. |
michael@0 | 114 | */ |
michael@0 | 115 | bool SetTo(const char16_t* aBuffer, int32_t aLength, bool aUpdateBidi); |
michael@0 | 116 | |
michael@0 | 117 | /** |
michael@0 | 118 | * Append aData to the end of this fragment. If aUpdateBidi is true, contents |
michael@0 | 119 | * of the fragment will be scanned, and mState.mIsBidi will be turned on if |
michael@0 | 120 | * it includes any Bidi characters. |
michael@0 | 121 | */ |
michael@0 | 122 | bool Append(const char16_t* aBuffer, uint32_t aLength, bool aUpdateBidi); |
michael@0 | 123 | |
michael@0 | 124 | /** |
michael@0 | 125 | * Append the contents of this string fragment to aString |
michael@0 | 126 | */ |
michael@0 | 127 | void AppendTo(nsAString& aString) const { |
michael@0 | 128 | if (!AppendTo(aString, mozilla::fallible_t())) { |
michael@0 | 129 | NS_ABORT_OOM(GetLength()); |
michael@0 | 130 | } |
michael@0 | 131 | } |
michael@0 | 132 | |
michael@0 | 133 | /** |
michael@0 | 134 | * Append the contents of this string fragment to aString |
michael@0 | 135 | * @return false if an out of memory condition is detected, true otherwise |
michael@0 | 136 | */ |
michael@0 | 137 | bool AppendTo(nsAString& aString, |
michael@0 | 138 | const mozilla::fallible_t&) const NS_WARN_UNUSED_RESULT { |
michael@0 | 139 | if (mState.mIs2b) { |
michael@0 | 140 | bool ok = aString.Append(m2b, mState.mLength, mozilla::fallible_t()); |
michael@0 | 141 | if (!ok) { |
michael@0 | 142 | return false; |
michael@0 | 143 | } |
michael@0 | 144 | |
michael@0 | 145 | return true; |
michael@0 | 146 | } else { |
michael@0 | 147 | return AppendASCIItoUTF16(Substring(m1b, mState.mLength), aString, |
michael@0 | 148 | mozilla::fallible_t()); |
michael@0 | 149 | } |
michael@0 | 150 | } |
michael@0 | 151 | |
michael@0 | 152 | /** |
michael@0 | 153 | * Append a substring of the contents of this string fragment to aString. |
michael@0 | 154 | * @param aOffset where to start the substring in this text fragment |
michael@0 | 155 | * @param aLength the length of the substring |
michael@0 | 156 | */ |
michael@0 | 157 | void AppendTo(nsAString& aString, int32_t aOffset, int32_t aLength) const { |
michael@0 | 158 | if (!AppendTo(aString, aOffset, aLength, mozilla::fallible_t())) { |
michael@0 | 159 | NS_ABORT_OOM(aLength); |
michael@0 | 160 | } |
michael@0 | 161 | } |
michael@0 | 162 | |
michael@0 | 163 | /** |
michael@0 | 164 | * Append a substring of the contents of this string fragment to aString. |
michael@0 | 165 | * @param aString the string in which to append |
michael@0 | 166 | * @param aOffset where to start the substring in this text fragment |
michael@0 | 167 | * @param aLength the length of the substring |
michael@0 | 168 | * @return false if an out of memory condition is detected, true otherwise |
michael@0 | 169 | */ |
michael@0 | 170 | bool AppendTo(nsAString& aString, int32_t aOffset, int32_t aLength, |
michael@0 | 171 | const mozilla::fallible_t&) const NS_WARN_UNUSED_RESULT |
michael@0 | 172 | { |
michael@0 | 173 | if (mState.mIs2b) { |
michael@0 | 174 | bool ok = aString.Append(m2b + aOffset, aLength, mozilla::fallible_t()); |
michael@0 | 175 | if (!ok) { |
michael@0 | 176 | return false; |
michael@0 | 177 | } |
michael@0 | 178 | |
michael@0 | 179 | return true; |
michael@0 | 180 | } else { |
michael@0 | 181 | return AppendASCIItoUTF16(Substring(m1b + aOffset, aLength), aString, |
michael@0 | 182 | mozilla::fallible_t()); |
michael@0 | 183 | } |
michael@0 | 184 | } |
michael@0 | 185 | |
michael@0 | 186 | /** |
michael@0 | 187 | * Make a copy of the fragments contents starting at offset for |
michael@0 | 188 | * count characters. The offset and count will be adjusted to |
michael@0 | 189 | * lie within the fragments data. The fragments data is converted if |
michael@0 | 190 | * necessary. |
michael@0 | 191 | */ |
michael@0 | 192 | void CopyTo(char16_t *aDest, int32_t aOffset, int32_t aCount); |
michael@0 | 193 | |
michael@0 | 194 | /** |
michael@0 | 195 | * Return the character in the text-fragment at the given |
michael@0 | 196 | * index. This always returns a char16_t. |
michael@0 | 197 | */ |
michael@0 | 198 | char16_t CharAt(int32_t aIndex) const |
michael@0 | 199 | { |
michael@0 | 200 | NS_ASSERTION(uint32_t(aIndex) < mState.mLength, "bad index"); |
michael@0 | 201 | return mState.mIs2b ? m2b[aIndex] : static_cast<unsigned char>(m1b[aIndex]); |
michael@0 | 202 | } |
michael@0 | 203 | |
michael@0 | 204 | struct FragmentBits { |
michael@0 | 205 | // uint32_t to ensure that the values are unsigned, because we |
michael@0 | 206 | // want 0/1, not 0/-1! |
michael@0 | 207 | // Making these bool causes Windows to not actually pack them, |
michael@0 | 208 | // which causes crashes because we assume this structure is no more than |
michael@0 | 209 | // 32 bits! |
michael@0 | 210 | uint32_t mInHeap : 1; |
michael@0 | 211 | uint32_t mIs2b : 1; |
michael@0 | 212 | uint32_t mIsBidi : 1; |
michael@0 | 213 | uint32_t mLength : 29; |
michael@0 | 214 | }; |
michael@0 | 215 | |
michael@0 | 216 | size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; |
michael@0 | 217 | |
michael@0 | 218 | private: |
michael@0 | 219 | void ReleaseText(); |
michael@0 | 220 | |
michael@0 | 221 | /** |
michael@0 | 222 | * Scan the contents of the fragment and turn on mState.mIsBidi if it |
michael@0 | 223 | * includes any Bidi characters. |
michael@0 | 224 | */ |
michael@0 | 225 | void UpdateBidiFlag(const char16_t* aBuffer, uint32_t aLength); |
michael@0 | 226 | |
michael@0 | 227 | union { |
michael@0 | 228 | char16_t *m2b; |
michael@0 | 229 | const char *m1b; // This is const since it can point to shared data |
michael@0 | 230 | }; |
michael@0 | 231 | |
michael@0 | 232 | union { |
michael@0 | 233 | uint32_t mAllBits; |
michael@0 | 234 | FragmentBits mState; |
michael@0 | 235 | }; |
michael@0 | 236 | }; |
michael@0 | 237 | |
michael@0 | 238 | #endif /* nsTextFragment_h___ */ |
michael@0 | 239 |