content/base/src/nsTextFragment.h

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:41426a501f46
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 /*
6 * A class which represents a fragment of text (eg inside a text
7 * node); if only codepoints below 256 are used, the text is stored as
8 * a char*; otherwise the text is stored as a char16_t*
9 */
10
11 #ifndef nsTextFragment_h___
12 #define nsTextFragment_h___
13
14 #include "mozilla/Attributes.h"
15 #include "mozilla/MemoryReporting.h"
16
17 #include "nsString.h"
18 #include "nsReadableUtils.h"
19 #include "nsISupportsImpl.h"
20
21 class nsString;
22 class nsCString;
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 MOZ_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 {
48 MOZ_COUNT_CTOR(nsTextFragment);
49 NS_ASSERTION(sizeof(FragmentBits) == 4, "Bad field packing!");
50 }
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 {
65 return mState.mIs2b;
66 }
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 {
75 return mState.mIsBidi;
76 }
77
78 /**
79 * Get a pointer to constant char16_t data.
80 */
81 const char16_t *Get2b() const
82 {
83 NS_ASSERTION(Is2b(), "not 2b text");
84 return m2b;
85 }
86
87 /**
88 * Get a pointer to constant char data.
89 */
90 const char *Get1b() const
91 {
92 NS_ASSERTION(!Is2b(), "not 1b text");
93 return (const char *)m1b;
94 }
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 {
102 return mState.mLength;
103 }
104
105 bool CanGrowBy(size_t n) const
106 {
107 return n < (1 << 29) && mState.mLength + n < (1 << 29);
108 }
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 */
115 bool SetTo(const char16_t* aBuffer, int32_t aLength, bool aUpdateBidi);
116
117 /**
118 * Append aData to the end of this fragment. If aUpdateBidi is true, contents
119 * of the fragment will be scanned, and mState.mIsBidi will be turned on if
120 * it includes any Bidi characters.
121 */
122 bool Append(const char16_t* aBuffer, uint32_t aLength, bool aUpdateBidi);
123
124 /**
125 * Append the contents of this string fragment to aString
126 */
127 void AppendTo(nsAString& aString) const {
128 if (!AppendTo(aString, mozilla::fallible_t())) {
129 NS_ABORT_OOM(GetLength());
130 }
131 }
132
133 /**
134 * Append the contents of this string fragment to aString
135 * @return false if an out of memory condition is detected, true otherwise
136 */
137 bool AppendTo(nsAString& aString,
138 const mozilla::fallible_t&) const NS_WARN_UNUSED_RESULT {
139 if (mState.mIs2b) {
140 bool ok = aString.Append(m2b, mState.mLength, mozilla::fallible_t());
141 if (!ok) {
142 return false;
143 }
144
145 return true;
146 } else {
147 return AppendASCIItoUTF16(Substring(m1b, mState.mLength), aString,
148 mozilla::fallible_t());
149 }
150 }
151
152 /**
153 * Append a substring of the contents of this string fragment to aString.
154 * @param aOffset where to start the substring in this text fragment
155 * @param aLength the length of the substring
156 */
157 void AppendTo(nsAString& aString, int32_t aOffset, int32_t aLength) const {
158 if (!AppendTo(aString, aOffset, aLength, mozilla::fallible_t())) {
159 NS_ABORT_OOM(aLength);
160 }
161 }
162
163 /**
164 * Append a substring of the contents of this string fragment to aString.
165 * @param aString the string in which to append
166 * @param aOffset where to start the substring in this text fragment
167 * @param aLength the length of the substring
168 * @return false if an out of memory condition is detected, true otherwise
169 */
170 bool AppendTo(nsAString& aString, int32_t aOffset, int32_t aLength,
171 const mozilla::fallible_t&) const NS_WARN_UNUSED_RESULT
172 {
173 if (mState.mIs2b) {
174 bool ok = aString.Append(m2b + aOffset, aLength, mozilla::fallible_t());
175 if (!ok) {
176 return false;
177 }
178
179 return true;
180 } else {
181 return AppendASCIItoUTF16(Substring(m1b + aOffset, aLength), aString,
182 mozilla::fallible_t());
183 }
184 }
185
186 /**
187 * Make a copy of the fragments contents starting at offset for
188 * count characters. The offset and count will be adjusted to
189 * lie within the fragments data. The fragments data is converted if
190 * necessary.
191 */
192 void CopyTo(char16_t *aDest, int32_t aOffset, int32_t aCount);
193
194 /**
195 * Return the character in the text-fragment at the given
196 * index. This always returns a char16_t.
197 */
198 char16_t CharAt(int32_t aIndex) const
199 {
200 NS_ASSERTION(uint32_t(aIndex) < mState.mLength, "bad index");
201 return mState.mIs2b ? m2b[aIndex] : static_cast<unsigned char>(m1b[aIndex]);
202 }
203
204 struct FragmentBits {
205 // uint32_t to ensure that the values are unsigned, because we
206 // want 0/1, not 0/-1!
207 // Making these bool causes Windows to not actually pack them,
208 // which causes crashes because we assume this structure is no more than
209 // 32 bits!
210 uint32_t mInHeap : 1;
211 uint32_t mIs2b : 1;
212 uint32_t mIsBidi : 1;
213 uint32_t mLength : 29;
214 };
215
216 size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
217
218 private:
219 void ReleaseText();
220
221 /**
222 * Scan the contents of the fragment and turn on mState.mIsBidi if it
223 * includes any Bidi characters.
224 */
225 void UpdateBidiFlag(const char16_t* aBuffer, uint32_t aLength);
226
227 union {
228 char16_t *m2b;
229 const char *m1b; // This is const since it can point to shared data
230 };
231
232 union {
233 uint32_t mAllBits;
234 FragmentBits mState;
235 };
236 };
237
238 #endif /* nsTextFragment_h___ */
239

mercurial