1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/thebes/gfxSkipChars.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,302 @@ 1.4 +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- 1.5 + * This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#ifndef GFX_SKIP_CHARS_H 1.10 +#define GFX_SKIP_CHARS_H 1.11 + 1.12 +#include "nsTArray.h" 1.13 + 1.14 +/* 1.15 + * gfxSkipChars is a data structure representing a list of characters that 1.16 + * have been skipped. The initial string is called the "original string" 1.17 + * and after skipping some characters, the result is called the "skipped string". 1.18 + * gfxSkipChars provides efficient ways to translate between offsets in the 1.19 + * original string and the skipped string. It is used by textrun code to keep 1.20 + * track of offsets before and after text transformations such as whitespace 1.21 + * compression and control code deletion. 1.22 + */ 1.23 + 1.24 +/** 1.25 + * The gfxSkipChars is represented as a sorted array of skipped ranges. 1.26 + * 1.27 + * A freshly-created gfxSkipChars means "all chars kept". 1.28 + */ 1.29 +class gfxSkipChars 1.30 +{ 1.31 +private: 1.32 + class SkippedRange 1.33 + { 1.34 + public: 1.35 + SkippedRange(uint32_t aOffset, uint32_t aLength, uint32_t aDelta) 1.36 + : mOffset(aOffset), mLength(aLength), mDelta(aDelta) 1.37 + { } 1.38 + 1.39 + uint32_t Start() const 1.40 + { 1.41 + return mOffset; 1.42 + } 1.43 + 1.44 + uint32_t End() const 1.45 + { 1.46 + return mOffset + mLength; 1.47 + } 1.48 + 1.49 + uint32_t Length() const 1.50 + { 1.51 + return mLength; 1.52 + } 1.53 + 1.54 + uint32_t SkippedOffset() const 1.55 + { 1.56 + return mOffset - mDelta; 1.57 + } 1.58 + 1.59 + uint32_t Delta() const 1.60 + { 1.61 + return mDelta; 1.62 + } 1.63 + 1.64 + uint32_t NextDelta() const 1.65 + { 1.66 + return mDelta + mLength; 1.67 + } 1.68 + 1.69 + void Extend(uint32_t aChars) 1.70 + { 1.71 + mLength += aChars; 1.72 + } 1.73 + 1.74 + private: 1.75 + uint32_t mOffset; // original-string offset at which we want to skip 1.76 + uint32_t mLength; // number of skipped chars at this offset 1.77 + uint32_t mDelta; // sum of lengths of preceding skipped-ranges 1.78 + }; 1.79 + 1.80 +public: 1.81 + gfxSkipChars() 1.82 + : mCharCount(0) 1.83 + { } 1.84 + 1.85 + void SkipChars(uint32_t aChars) 1.86 + { 1.87 + NS_ASSERTION(mCharCount + aChars > mCharCount, 1.88 + "Character count overflow"); 1.89 + uint32_t rangeCount = mRanges.Length(); 1.90 + uint32_t delta = 0; 1.91 + if (rangeCount > 0) { 1.92 + SkippedRange& lastRange = mRanges[rangeCount - 1]; 1.93 + if (lastRange.End() == mCharCount) { 1.94 + lastRange.Extend(aChars); 1.95 + mCharCount += aChars; 1.96 + return; 1.97 + } 1.98 + delta = lastRange.NextDelta(); 1.99 + } 1.100 + mRanges.AppendElement(SkippedRange(mCharCount, aChars, delta)); 1.101 + mCharCount += aChars; 1.102 + } 1.103 + 1.104 + void KeepChars(uint32_t aChars) 1.105 + { 1.106 + NS_ASSERTION(mCharCount + aChars > mCharCount, 1.107 + "Character count overflow"); 1.108 + mCharCount += aChars; 1.109 + } 1.110 + 1.111 + void SkipChar() 1.112 + { 1.113 + SkipChars(1); 1.114 + } 1.115 + 1.116 + void KeepChar() 1.117 + { 1.118 + KeepChars(1); 1.119 + } 1.120 + 1.121 + void TakeFrom(gfxSkipChars* aSkipChars) 1.122 + { 1.123 + mRanges.SwapElements(aSkipChars->mRanges); 1.124 + mCharCount = aSkipChars->mCharCount; 1.125 + aSkipChars->mCharCount = 0; 1.126 + } 1.127 + 1.128 + int32_t GetOriginalCharCount() const 1.129 + { 1.130 + return mCharCount; 1.131 + } 1.132 + 1.133 + const SkippedRange& LastRange() const 1.134 + { 1.135 + // this is only valid if mRanges is non-empty; no assertion here 1.136 + // because nsTArray will already assert if we abuse it 1.137 + return mRanges[mRanges.Length() - 1]; 1.138 + } 1.139 + 1.140 + friend class gfxSkipCharsIterator; 1.141 + 1.142 +private: 1.143 + nsTArray<SkippedRange> mRanges; 1.144 + uint32_t mCharCount; 1.145 +}; 1.146 + 1.147 +/** 1.148 + * A gfxSkipCharsIterator represents a position in the original string. It lets you 1.149 + * map efficiently to and from positions in the string after skipped characters 1.150 + * have been removed. You can also specify an offset that is added to all 1.151 + * incoming original string offsets and subtracted from all outgoing original 1.152 + * string offsets --- useful when the gfxSkipChars corresponds to something 1.153 + * offset from the original DOM coordinates, which it often does for gfxTextRuns. 1.154 + * 1.155 + * The current positions (in both the original and skipped strings) are 1.156 + * always constrained to be >= 0 and <= the string length. When the position 1.157 + * is equal to the string length, it is at the end of the string. The current 1.158 + * positions do not include any aOriginalStringToSkipCharsOffset. 1.159 + * 1.160 + * When the position in the original string corresponds to a skipped character, 1.161 + * the skipped-characters offset is the offset of the next unskipped character, 1.162 + * or the skipped-characters string length if there is no next unskipped character. 1.163 + */ 1.164 +class gfxSkipCharsIterator 1.165 +{ 1.166 +public: 1.167 + /** 1.168 + * @param aOriginalStringToSkipCharsOffset add this to all incoming and 1.169 + * outgoing original string offsets 1.170 + */ 1.171 + gfxSkipCharsIterator(const gfxSkipChars& aSkipChars, 1.172 + int32_t aOriginalStringToSkipCharsOffset, 1.173 + int32_t aOriginalStringOffset) 1.174 + : mSkipChars(&aSkipChars), 1.175 + mOriginalStringOffset(0), 1.176 + mSkippedStringOffset(0), 1.177 + mCurrentRangeIndex(-1), 1.178 + mOriginalStringToSkipCharsOffset(aOriginalStringToSkipCharsOffset) 1.179 + { 1.180 + SetOriginalOffset(aOriginalStringOffset); 1.181 + } 1.182 + 1.183 + gfxSkipCharsIterator(const gfxSkipChars& aSkipChars, 1.184 + int32_t aOriginalStringToSkipCharsOffset = 0) 1.185 + : mSkipChars(&aSkipChars), 1.186 + mOriginalStringOffset(0), 1.187 + mSkippedStringOffset(0), 1.188 + mCurrentRangeIndex(-1), 1.189 + mOriginalStringToSkipCharsOffset(aOriginalStringToSkipCharsOffset) 1.190 + { } 1.191 + 1.192 + gfxSkipCharsIterator(const gfxSkipCharsIterator& aIterator) 1.193 + : mSkipChars(aIterator.mSkipChars), 1.194 + mOriginalStringOffset(aIterator.mOriginalStringOffset), 1.195 + mSkippedStringOffset(aIterator.mSkippedStringOffset), 1.196 + mCurrentRangeIndex(aIterator.mCurrentRangeIndex), 1.197 + mOriginalStringToSkipCharsOffset(aIterator.mOriginalStringToSkipCharsOffset) 1.198 + { } 1.199 + 1.200 + /** 1.201 + * The empty constructor creates an object that is useless until it is assigned. 1.202 + */ 1.203 + gfxSkipCharsIterator() 1.204 + : mSkipChars(nullptr) 1.205 + { } 1.206 + 1.207 + /** 1.208 + * Return true if this iterator is properly initialized and usable. 1.209 + */ 1.210 + bool IsInitialized() 1.211 + { 1.212 + return mSkipChars != nullptr; 1.213 + } 1.214 + 1.215 + /** 1.216 + * Set the iterator to aOriginalStringOffset in the original string. 1.217 + * This can efficiently move forward or backward from the current position. 1.218 + * aOriginalStringOffset is clamped to [0,originalStringLength]. 1.219 + */ 1.220 + void SetOriginalOffset(int32_t aOriginalStringOffset); 1.221 + 1.222 + /** 1.223 + * Set the iterator to aSkippedStringOffset in the skipped string. 1.224 + * This can efficiently move forward or backward from the current position. 1.225 + * aSkippedStringOffset is clamped to [0,skippedStringLength]. 1.226 + */ 1.227 + void SetSkippedOffset(uint32_t aSkippedStringOffset); 1.228 + 1.229 + uint32_t ConvertOriginalToSkipped(int32_t aOriginalStringOffset) 1.230 + { 1.231 + SetOriginalOffset(aOriginalStringOffset); 1.232 + return GetSkippedOffset(); 1.233 + } 1.234 + 1.235 + uint32_t ConvertSkippedToOriginal(int32_t aSkippedStringOffset) 1.236 + { 1.237 + SetSkippedOffset(aSkippedStringOffset); 1.238 + return GetOriginalOffset(); 1.239 + } 1.240 + 1.241 + /** 1.242 + * Test if the character at the current position in the original string 1.243 + * is skipped or not. If aRunLength is non-null, then *aRunLength is set 1.244 + * to a number of characters all of which are either skipped or not, starting 1.245 + * at this character. When the current position is at the end of the original 1.246 + * string, we return true and *aRunLength is set to zero. 1.247 + */ 1.248 + bool IsOriginalCharSkipped(int32_t* aRunLength = nullptr) const; 1.249 + 1.250 + void AdvanceOriginal(int32_t aDelta) 1.251 + { 1.252 + SetOriginalOffset(GetOriginalOffset() + aDelta); 1.253 + } 1.254 + 1.255 + void AdvanceSkipped(int32_t aDelta) 1.256 + { 1.257 + SetSkippedOffset(GetSkippedOffset() + aDelta); 1.258 + } 1.259 + 1.260 + /** 1.261 + * @return the offset within the original string 1.262 + */ 1.263 + int32_t GetOriginalOffset() const 1.264 + { 1.265 + return mOriginalStringOffset - mOriginalStringToSkipCharsOffset; 1.266 + } 1.267 + 1.268 + /** 1.269 + * @return the offset within the skipped string corresponding to the 1.270 + * current position in the original string. If the current position 1.271 + * in the original string is a character that is skipped, then we return 1.272 + * the position corresponding to the first non-skipped character in the 1.273 + * original string after the current position, or the length of the skipped 1.274 + * string if there is no such character. 1.275 + */ 1.276 + uint32_t GetSkippedOffset() const 1.277 + { 1.278 + return mSkippedStringOffset; 1.279 + } 1.280 + 1.281 + int32_t GetOriginalEnd() const 1.282 + { 1.283 + return mSkipChars->GetOriginalCharCount() - 1.284 + mOriginalStringToSkipCharsOffset; 1.285 + } 1.286 + 1.287 +private: 1.288 + const gfxSkipChars* mSkipChars; 1.289 + 1.290 + // Current position 1.291 + int32_t mOriginalStringOffset; 1.292 + uint32_t mSkippedStringOffset; 1.293 + 1.294 + // Index of the last skippedRange that precedes or contains the current 1.295 + // position in the original string. 1.296 + // If index == -1 then we are before the first skipped char. 1.297 + int32_t mCurrentRangeIndex; 1.298 + 1.299 + // This offset is added to map from "skipped+unskipped characters in 1.300 + // the original DOM string" character space to "skipped+unskipped 1.301 + // characters in the textrun's gfxSkipChars" character space 1.302 + int32_t mOriginalStringToSkipCharsOffset; 1.303 +}; 1.304 + 1.305 +#endif /*GFX_SKIP_CHARS_H*/