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