Bug 1550519 - Show a translucent parent highlight when a subgrid is highlighted....
[gecko.git] / dom / base / nsTextFragment.h
blob90162b50ef40362f82da5a92941c5be6924c342e
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/. */
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*
13 #ifndef nsTextFragment_h___
14 #define nsTextFragment_h___
16 #include "mozilla/Attributes.h"
17 #include "mozilla/MemoryReporting.h"
19 #include "nsString.h"
20 #include "nsStringBuffer.h"
21 #include "nsReadableUtils.h"
22 #include "nsISupportsImpl.h"
24 // XXX should this normalize the code to keep a \u0000 at the end?
26 // XXX nsTextFragmentPool?
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.
34 * This class does not have a virtual destructor therefore it is not
35 * meant to be subclassed.
37 class nsTextFragment final {
38 public:
39 static nsresult Init();
40 static void Shutdown();
42 /**
43 * Default constructor. Initialize the fragment to be empty.
45 nsTextFragment() : m1b(nullptr), mAllBits(0) {
46 MOZ_COUNT_CTOR(nsTextFragment);
47 NS_ASSERTION(sizeof(FragmentBits) == 4, "Bad field packing!");
50 ~nsTextFragment();
52 /**
53 * Change the contents of this fragment to be a copy of the
54 * the argument fragment, or to "" if unable to allocate enough memory.
56 nsTextFragment& operator=(const nsTextFragment& aOther);
58 /**
59 * Return true if this fragment is represented by char16_t data
61 bool Is2b() const { return mState.mIs2b; }
63 /**
64 * Return true if this fragment contains Bidi text
65 * For performance reasons this flag is only set if explicitely requested (by
66 * setting the aUpdateBidi argument on SetTo or Append to true).
68 bool IsBidi() const { return mState.mIsBidi; }
70 /**
71 * Get a pointer to constant char16_t data.
73 const char16_t* Get2b() const {
74 MOZ_ASSERT(Is2b(), "not 2b text");
75 return static_cast<char16_t*>(m2b->Data());
78 /**
79 * Get a pointer to constant char data.
81 const char* Get1b() const {
82 NS_ASSERTION(!Is2b(), "not 1b text");
83 return (const char*)m1b;
86 /**
87 * Get the length of the fragment. The length is the number of logical
88 * characters, not the number of bytes to store the characters.
90 uint32_t GetLength() const { return mState.mLength; }
92 bool CanGrowBy(size_t n) const {
93 return n < (1 << 29) && mState.mLength + n < (1 << 29);
96 /**
97 * Change the contents of this fragment to be a copy of the given
98 * buffer. If aUpdateBidi is true, contents of the fragment will be scanned,
99 * and mState.mIsBidi will be turned on if it includes any Bidi characters.
100 * If aForce2b is true, aBuffer will be stored as char16_t as is. Then,
101 * you can access the value faster but may waste memory if all characters
102 * are less than U+0100.
104 bool SetTo(const char16_t* aBuffer, int32_t aLength, bool aUpdateBidi,
105 bool aForce2b);
107 bool SetTo(const nsString& aString, bool aUpdateBidi, bool aForce2b) {
108 ReleaseText();
109 if (aForce2b && !aUpdateBidi) {
110 nsStringBuffer* buffer = nsStringBuffer::FromString(aString);
111 if (buffer) {
112 NS_ADDREF(m2b = buffer);
113 mState.mInHeap = true;
114 mState.mIs2b = true;
115 mState.mLength = aString.Length();
116 return true;
120 return SetTo(aString.get(), aString.Length(), aUpdateBidi, aForce2b);
124 * Append aData to the end of this fragment. If aUpdateBidi is true, contents
125 * of the fragment will be scanned, and mState.mIsBidi will be turned on if
126 * it includes any Bidi characters.
127 * If aForce2b is true, the string will be stored as char16_t as is. Then,
128 * you can access the value faster but may waste memory if all characters
129 * are less than U+0100.
131 bool Append(const char16_t* aBuffer, uint32_t aLength, bool aUpdateBidi,
132 bool aForce2b);
135 * Append the contents of this string fragment to aString
137 void AppendTo(nsAString& aString) const {
138 if (!AppendTo(aString, mozilla::fallible)) {
139 aString.AllocFailed(aString.Length() + GetLength());
144 * Append the contents of this string fragment to aString
145 * @return false if an out of memory condition is detected, true otherwise
147 MOZ_MUST_USE
148 bool AppendTo(nsAString& aString,
149 const mozilla::fallible_t& aFallible) const {
150 if (mState.mIs2b) {
151 if (aString.IsEmpty()) {
152 m2b->ToString(mState.mLength, aString);
153 return true;
155 bool ok = aString.Append(Get2b(), mState.mLength, aFallible);
156 if (!ok) {
157 return false;
160 return true;
161 } else {
162 return AppendASCIItoUTF16(Substring(m1b, mState.mLength), aString,
163 aFallible);
168 * Append a substring of the contents of this string fragment to aString.
169 * @param aOffset where to start the substring in this text fragment
170 * @param aLength the length of the substring
172 void AppendTo(nsAString& aString, int32_t aOffset, int32_t aLength) const {
173 if (!AppendTo(aString, aOffset, aLength, mozilla::fallible)) {
174 aString.AllocFailed(aString.Length() + aLength);
179 * Append a substring of the contents of this string fragment to aString.
180 * @param aString the string in which to append
181 * @param aOffset where to start the substring in this text fragment
182 * @param aLength the length of the substring
183 * @return false if an out of memory condition is detected, true otherwise
185 MOZ_MUST_USE
186 bool AppendTo(nsAString& aString, int32_t aOffset, int32_t aLength,
187 const mozilla::fallible_t& aFallible) const {
188 if (mState.mIs2b) {
189 bool ok = aString.Append(Get2b() + aOffset, aLength, aFallible);
190 if (!ok) {
191 return false;
194 return true;
195 } else {
196 return AppendASCIItoUTF16(Substring(m1b + aOffset, aLength), aString,
197 aFallible);
202 * Make a copy of the fragments contents starting at offset for
203 * count characters. The offset and count will be adjusted to
204 * lie within the fragments data. The fragments data is converted if
205 * necessary.
207 void CopyTo(char16_t* aDest, int32_t aOffset, int32_t aCount);
210 * Return the character in the text-fragment at the given
211 * index. This always returns a char16_t.
213 char16_t CharAt(int32_t aIndex) const {
214 MOZ_ASSERT(uint32_t(aIndex) < mState.mLength, "bad index");
215 return mState.mIs2b ? Get2b()[aIndex]
216 : static_cast<unsigned char>(m1b[aIndex]);
219 void SetBidi(bool aBidi) { mState.mIsBidi = aBidi; }
221 struct FragmentBits {
222 // uint32_t to ensure that the values are unsigned, because we
223 // want 0/1, not 0/-1!
224 // Making these bool causes Windows to not actually pack them,
225 // which causes crashes because we assume this structure is no more than
226 // 32 bits!
227 uint32_t mInHeap : 1;
228 uint32_t mIs2b : 1;
229 uint32_t mIsBidi : 1;
230 // Note that when you change the bits of mLength, you also need to change
231 // NS_MAX_TEXT_FRAGMENT_LENGTH.
232 uint32_t mLength : 29;
235 #define NS_MAX_TEXT_FRAGMENT_LENGTH (static_cast<uint32_t>(0x1FFFFFFF))
237 size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
240 * Check whether the text in this fragment is the same as the text in the
241 * other fragment.
243 MOZ_MUST_USE bool TextEquals(const nsTextFragment& aOther) const;
245 private:
246 void ReleaseText();
249 * Scan the contents of the fragment and turn on mState.mIsBidi if it
250 * includes any Bidi characters.
252 void UpdateBidiFlag(const char16_t* aBuffer, uint32_t aLength);
254 union {
255 nsStringBuffer* m2b;
256 const char* m1b; // This is const since it can point to shared data
259 union {
260 uint32_t mAllBits;
261 FragmentBits mState;
265 #endif /* nsTextFragment_h___ */