1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/content/base/src/nsTextFragment.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,239 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +/* 1.9 + * A class which represents a fragment of text (eg inside a text 1.10 + * node); if only codepoints below 256 are used, the text is stored as 1.11 + * a char*; otherwise the text is stored as a char16_t* 1.12 + */ 1.13 + 1.14 +#ifndef nsTextFragment_h___ 1.15 +#define nsTextFragment_h___ 1.16 + 1.17 +#include "mozilla/Attributes.h" 1.18 +#include "mozilla/MemoryReporting.h" 1.19 + 1.20 +#include "nsString.h" 1.21 +#include "nsReadableUtils.h" 1.22 +#include "nsISupportsImpl.h" 1.23 + 1.24 +class nsString; 1.25 +class nsCString; 1.26 + 1.27 +// XXX should this normalize the code to keep a \u0000 at the end? 1.28 + 1.29 +// XXX nsTextFragmentPool? 1.30 + 1.31 +/** 1.32 + * A fragment of text. If mIs2b is 1 then the m2b pointer is valid 1.33 + * otherwise the m1b pointer is valid. If m1b is used then each byte 1.34 + * of data represents a single ucs2 character with the high byte being 1.35 + * zero. 1.36 + * 1.37 + * This class does not have a virtual destructor therefore it is not 1.38 + * meant to be subclassed. 1.39 + */ 1.40 +class nsTextFragment MOZ_FINAL { 1.41 +public: 1.42 + static nsresult Init(); 1.43 + static void Shutdown(); 1.44 + 1.45 + /** 1.46 + * Default constructor. Initialize the fragment to be empty. 1.47 + */ 1.48 + nsTextFragment() 1.49 + : m1b(nullptr), mAllBits(0) 1.50 + { 1.51 + MOZ_COUNT_CTOR(nsTextFragment); 1.52 + NS_ASSERTION(sizeof(FragmentBits) == 4, "Bad field packing!"); 1.53 + } 1.54 + 1.55 + ~nsTextFragment(); 1.56 + 1.57 + /** 1.58 + * Change the contents of this fragment to be a copy of the 1.59 + * the argument fragment, or to "" if unable to allocate enough memory. 1.60 + */ 1.61 + nsTextFragment& operator=(const nsTextFragment& aOther); 1.62 + 1.63 + /** 1.64 + * Return true if this fragment is represented by char16_t data 1.65 + */ 1.66 + bool Is2b() const 1.67 + { 1.68 + return mState.mIs2b; 1.69 + } 1.70 + 1.71 + /** 1.72 + * Return true if this fragment contains Bidi text 1.73 + * For performance reasons this flag is only set if explicitely requested (by 1.74 + * setting the aUpdateBidi argument on SetTo or Append to true). 1.75 + */ 1.76 + bool IsBidi() const 1.77 + { 1.78 + return mState.mIsBidi; 1.79 + } 1.80 + 1.81 + /** 1.82 + * Get a pointer to constant char16_t data. 1.83 + */ 1.84 + const char16_t *Get2b() const 1.85 + { 1.86 + NS_ASSERTION(Is2b(), "not 2b text"); 1.87 + return m2b; 1.88 + } 1.89 + 1.90 + /** 1.91 + * Get a pointer to constant char data. 1.92 + */ 1.93 + const char *Get1b() const 1.94 + { 1.95 + NS_ASSERTION(!Is2b(), "not 1b text"); 1.96 + return (const char *)m1b; 1.97 + } 1.98 + 1.99 + /** 1.100 + * Get the length of the fragment. The length is the number of logical 1.101 + * characters, not the number of bytes to store the characters. 1.102 + */ 1.103 + uint32_t GetLength() const 1.104 + { 1.105 + return mState.mLength; 1.106 + } 1.107 + 1.108 + bool CanGrowBy(size_t n) const 1.109 + { 1.110 + return n < (1 << 29) && mState.mLength + n < (1 << 29); 1.111 + } 1.112 + 1.113 + /** 1.114 + * Change the contents of this fragment to be a copy of the given 1.115 + * buffer. If aUpdateBidi is true, contents of the fragment will be scanned, 1.116 + * and mState.mIsBidi will be turned on if it includes any Bidi characters. 1.117 + */ 1.118 + bool SetTo(const char16_t* aBuffer, int32_t aLength, bool aUpdateBidi); 1.119 + 1.120 + /** 1.121 + * Append aData to the end of this fragment. If aUpdateBidi is true, contents 1.122 + * of the fragment will be scanned, and mState.mIsBidi will be turned on if 1.123 + * it includes any Bidi characters. 1.124 + */ 1.125 + bool Append(const char16_t* aBuffer, uint32_t aLength, bool aUpdateBidi); 1.126 + 1.127 + /** 1.128 + * Append the contents of this string fragment to aString 1.129 + */ 1.130 + void AppendTo(nsAString& aString) const { 1.131 + if (!AppendTo(aString, mozilla::fallible_t())) { 1.132 + NS_ABORT_OOM(GetLength()); 1.133 + } 1.134 + } 1.135 + 1.136 + /** 1.137 + * Append the contents of this string fragment to aString 1.138 + * @return false if an out of memory condition is detected, true otherwise 1.139 + */ 1.140 + bool AppendTo(nsAString& aString, 1.141 + const mozilla::fallible_t&) const NS_WARN_UNUSED_RESULT { 1.142 + if (mState.mIs2b) { 1.143 + bool ok = aString.Append(m2b, mState.mLength, mozilla::fallible_t()); 1.144 + if (!ok) { 1.145 + return false; 1.146 + } 1.147 + 1.148 + return true; 1.149 + } else { 1.150 + return AppendASCIItoUTF16(Substring(m1b, mState.mLength), aString, 1.151 + mozilla::fallible_t()); 1.152 + } 1.153 + } 1.154 + 1.155 + /** 1.156 + * Append a substring of the contents of this string fragment to aString. 1.157 + * @param aOffset where to start the substring in this text fragment 1.158 + * @param aLength the length of the substring 1.159 + */ 1.160 + void AppendTo(nsAString& aString, int32_t aOffset, int32_t aLength) const { 1.161 + if (!AppendTo(aString, aOffset, aLength, mozilla::fallible_t())) { 1.162 + NS_ABORT_OOM(aLength); 1.163 + } 1.164 + } 1.165 + 1.166 + /** 1.167 + * Append a substring of the contents of this string fragment to aString. 1.168 + * @param aString the string in which to append 1.169 + * @param aOffset where to start the substring in this text fragment 1.170 + * @param aLength the length of the substring 1.171 + * @return false if an out of memory condition is detected, true otherwise 1.172 + */ 1.173 + bool AppendTo(nsAString& aString, int32_t aOffset, int32_t aLength, 1.174 + const mozilla::fallible_t&) const NS_WARN_UNUSED_RESULT 1.175 + { 1.176 + if (mState.mIs2b) { 1.177 + bool ok = aString.Append(m2b + aOffset, aLength, mozilla::fallible_t()); 1.178 + if (!ok) { 1.179 + return false; 1.180 + } 1.181 + 1.182 + return true; 1.183 + } else { 1.184 + return AppendASCIItoUTF16(Substring(m1b + aOffset, aLength), aString, 1.185 + mozilla::fallible_t()); 1.186 + } 1.187 + } 1.188 + 1.189 + /** 1.190 + * Make a copy of the fragments contents starting at offset for 1.191 + * count characters. The offset and count will be adjusted to 1.192 + * lie within the fragments data. The fragments data is converted if 1.193 + * necessary. 1.194 + */ 1.195 + void CopyTo(char16_t *aDest, int32_t aOffset, int32_t aCount); 1.196 + 1.197 + /** 1.198 + * Return the character in the text-fragment at the given 1.199 + * index. This always returns a char16_t. 1.200 + */ 1.201 + char16_t CharAt(int32_t aIndex) const 1.202 + { 1.203 + NS_ASSERTION(uint32_t(aIndex) < mState.mLength, "bad index"); 1.204 + return mState.mIs2b ? m2b[aIndex] : static_cast<unsigned char>(m1b[aIndex]); 1.205 + } 1.206 + 1.207 + struct FragmentBits { 1.208 + // uint32_t to ensure that the values are unsigned, because we 1.209 + // want 0/1, not 0/-1! 1.210 + // Making these bool causes Windows to not actually pack them, 1.211 + // which causes crashes because we assume this structure is no more than 1.212 + // 32 bits! 1.213 + uint32_t mInHeap : 1; 1.214 + uint32_t mIs2b : 1; 1.215 + uint32_t mIsBidi : 1; 1.216 + uint32_t mLength : 29; 1.217 + }; 1.218 + 1.219 + size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; 1.220 + 1.221 +private: 1.222 + void ReleaseText(); 1.223 + 1.224 + /** 1.225 + * Scan the contents of the fragment and turn on mState.mIsBidi if it 1.226 + * includes any Bidi characters. 1.227 + */ 1.228 + void UpdateBidiFlag(const char16_t* aBuffer, uint32_t aLength); 1.229 + 1.230 + union { 1.231 + char16_t *m2b; 1.232 + const char *m1b; // This is const since it can point to shared data 1.233 + }; 1.234 + 1.235 + union { 1.236 + uint32_t mAllBits; 1.237 + FragmentBits mState; 1.238 + }; 1.239 +}; 1.240 + 1.241 +#endif /* nsTextFragment_h___ */ 1.242 +