1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #ifndef GFX_SKIP_CHARS_H
7 #define GFX_SKIP_CHARS_H
14 * gfxSkipChars is a data structure representing a list of characters that
15 * have been skipped. The initial string is called the "original string"
16 * and after skipping some characters, the result is called the "skipped string".
17 * gfxSkipChars provides efficient ways to translate between offsets in the
18 * original string and the skipped string. It is used by textrun code to keep
19 * track of offsets before and after text transformations such as whitespace
20 * compression and control code deletion.
24 * gfxSkipCharsBuilder is a helper class that accumulates a list of (skip, keep)
25 * commands and can eventually be used to construct a real gfxSkipChars.
26 * gfxSkipCharsBuilder objects are quite large so don't keep these around.
27 * On the positive side, the Skip/KeepChar(s) methods are very efficient,
28 * especially when you have runs of all-kept or all-skipped characters.
30 * mBuffer is an array of bytes; even numbered bytes represent characters kept,
31 * odd numbered bytes represent characters skipped. After those characters
32 * are accounted for, we have mRunCharCount characters which are kept or
33 * skipped depending on the value of mRunSkipped.
35 * mCharCount is the sum of counts of all skipped and kept characters, i.e.,
36 * the length of the original string.
38 class THEBES_API gfxSkipCharsBuilder
{
40 gfxSkipCharsBuilder() :
41 mCharCount(0), mRunCharCount(0), mRunSkipped(false), mInErrorState(false)
44 void SkipChars(uint32_t aChars
) {
45 DoChars(aChars
, true);
47 void KeepChars(uint32_t aChars
) {
48 DoChars(aChars
, false);
56 void DoChars(uint32_t aChars
, bool aSkipped
) {
57 if (aSkipped
!= mRunSkipped
&& aChars
> 0) {
60 NS_ASSERTION(mRunCharCount
+ aChars
> mRunCharCount
,
61 "Character count overflow");
62 mRunCharCount
+= aChars
;
65 bool IsOK() { return !mInErrorState
; }
67 uint32_t GetCharCount() { return mCharCount
+ mRunCharCount
; }
68 bool GetAllCharsKept() { return mBuffer
.Length() == 0; }
70 friend class gfxSkipChars
;
73 typedef AutoFallibleTArray
<uint8_t,256> Buffer
;
76 * Moves mRunCharCount/mRunSkipped to the buffer (updating mCharCount),
77 * sets mRunCharCount to zero and toggles mRunSkipped.
83 uint32_t mRunCharCount
;
84 bool mRunSkipped
; // == mBuffer.Length()&1
89 * The gfxSkipChars list is represented as a list of bytes of the form
90 * [chars to keep, chars to skip, chars to keep, chars to skip, ...]
91 * In the special case where all chars are to be kept, the list is length
94 * A freshly-created gfxSkipChars means "all chars kept".
96 class THEBES_API gfxSkipChars
{
98 gfxSkipChars() : mListLength(0), mCharCount(0) {}
100 void TakeFrom(gfxSkipChars
* aSkipChars
) {
101 mList
= aSkipChars
->mList
.forget();
102 mListLength
= aSkipChars
->mListLength
;
103 mCharCount
= aSkipChars
->mCharCount
;
104 aSkipChars
->mCharCount
= 0;
105 aSkipChars
->mListLength
= 0;
109 void TakeFrom(gfxSkipCharsBuilder
* aSkipCharsBuilder
) {
110 if (!aSkipCharsBuilder
->mBuffer
.Length()) {
111 NS_ASSERTION(!aSkipCharsBuilder
->mRunSkipped
, "out of sync");
112 // all characters kept
113 mCharCount
= aSkipCharsBuilder
->mRunCharCount
;
117 aSkipCharsBuilder
->FlushRun();
118 mCharCount
= aSkipCharsBuilder
->mCharCount
;
119 mList
= new uint8_t[aSkipCharsBuilder
->mBuffer
.Length()];
123 mListLength
= aSkipCharsBuilder
->mBuffer
.Length();
124 memcpy(mList
, aSkipCharsBuilder
->mBuffer
.Elements(), mListLength
);
127 aSkipCharsBuilder
->mBuffer
.Clear();
128 aSkipCharsBuilder
->mCharCount
= 0;
129 aSkipCharsBuilder
->mRunCharCount
= 0;
130 aSkipCharsBuilder
->mRunSkipped
= false;
134 void SetAllKeep(uint32_t aLength
) {
135 mCharCount
= aLength
;
140 int32_t GetOriginalCharCount() const { return mCharCount
; }
142 friend class gfxSkipCharsIterator
;
146 uint32_t mListPrefixLength
;
147 uint32_t mListPrefixCharCount
;
148 uint32_t mListPrefixKeepCharCount
;
151 Shortcut(uint32_t aListPrefixLength
, uint32_t aListPrefixCharCount
,
152 uint32_t aListPrefixKeepCharCount
) :
153 mListPrefixLength(aListPrefixLength
),
154 mListPrefixCharCount(aListPrefixCharCount
),
155 mListPrefixKeepCharCount(aListPrefixKeepCharCount
) {}
158 void BuildShortcuts();
160 nsAutoArrayPtr
<uint8_t> mList
;
161 nsAutoArrayPtr
<Shortcut
> mShortcuts
;
162 uint32_t mListLength
;
167 * A gfxSkipCharsIterator represents a position in the original string. It lets you
168 * map efficiently to and from positions in the string after skipped characters
169 * have been removed. You can also specify an offset that is added to all
170 * incoming original string offsets and subtracted from all outgoing original
171 * string offsets --- useful when the gfxSkipChars corresponds to something
172 * offset from the original DOM coordinates, which it often does for gfxTextRuns.
174 * The current positions (in both the original and skipped strings) are
175 * always constrained to be >= 0 and <= the string length. When the position
176 * is equal to the string length, it is at the end of the string. The current
177 * positions do not include any aOriginalStringToSkipCharsOffset.
179 * When the position in the original string corresponds to a skipped character,
180 * the skipped-characters offset is the offset of the next unskipped character,
181 * or the skipped-characters string length if there is no next unskipped character.
183 class THEBES_API gfxSkipCharsIterator
{
186 * @param aOriginalStringToSkipCharsOffset add this to all incoming and
187 * outgoing original string offsets
189 gfxSkipCharsIterator(const gfxSkipChars
& aSkipChars
,
190 int32_t aOriginalStringToSkipCharsOffset
,
191 int32_t aOriginalStringOffset
)
192 : mSkipChars(&aSkipChars
),
193 mOriginalStringToSkipCharsOffset(aOriginalStringToSkipCharsOffset
),
194 mListPrefixLength(0), mListPrefixCharCount(0), mListPrefixKeepCharCount(0) {
195 SetOriginalOffset(aOriginalStringOffset
);
198 gfxSkipCharsIterator(const gfxSkipChars
& aSkipChars
,
199 int32_t aOriginalStringToSkipCharsOffset
= 0)
200 : mSkipChars(&aSkipChars
),
201 mOriginalStringOffset(0), mSkippedStringOffset(0),
202 mOriginalStringToSkipCharsOffset(aOriginalStringToSkipCharsOffset
),
203 mListPrefixLength(0), mListPrefixCharCount(0), mListPrefixKeepCharCount(0) {
206 gfxSkipCharsIterator(const gfxSkipCharsIterator
& aIterator
)
207 : mSkipChars(aIterator
.mSkipChars
),
208 mOriginalStringOffset(aIterator
.mOriginalStringOffset
),
209 mSkippedStringOffset(aIterator
.mSkippedStringOffset
),
210 mOriginalStringToSkipCharsOffset(aIterator
.mOriginalStringToSkipCharsOffset
),
211 mListPrefixLength(aIterator
.mListPrefixLength
),
212 mListPrefixCharCount(aIterator
.mListPrefixCharCount
),
213 mListPrefixKeepCharCount(aIterator
.mListPrefixKeepCharCount
)
217 * The empty constructor creates an object that is useless until it is assigned.
219 gfxSkipCharsIterator() : mSkipChars(nullptr) {}
222 * Return true if this iterator is properly initialized and usable.
224 bool IsInitialized() { return mSkipChars
!= nullptr; }
227 * Set the iterator to aOriginalStringOffset in the original string.
228 * This can efficiently move forward or backward from the current position.
229 * aOriginalStringOffset is clamped to [0,originalStringLength].
231 void SetOriginalOffset(int32_t aOriginalStringOffset
) {
232 SetOffsets(aOriginalStringOffset
+ mOriginalStringToSkipCharsOffset
, true);
236 * Set the iterator to aSkippedStringOffset in the skipped string.
237 * This can efficiently move forward or backward from the current position.
238 * aSkippedStringOffset is clamped to [0,skippedStringLength].
240 void SetSkippedOffset(uint32_t aSkippedStringOffset
) {
241 SetOffsets(aSkippedStringOffset
, false);
244 uint32_t ConvertOriginalToSkipped(int32_t aOriginalStringOffset
) {
245 SetOriginalOffset(aOriginalStringOffset
);
246 return GetSkippedOffset();
248 uint32_t ConvertSkippedToOriginal(int32_t aSkippedStringOffset
) {
249 SetSkippedOffset(aSkippedStringOffset
);
250 return GetOriginalOffset();
254 * Test if the character at the current position in the original string
255 * is skipped or not. If aRunLength is non-null, then *aRunLength is set
256 * to a number of characters all of which are either skipped or not, starting
257 * at this character. When the current position is at the end of the original
258 * string, we return true and *aRunLength is set to zero.
260 bool IsOriginalCharSkipped(int32_t* aRunLength
= nullptr) const;
262 void AdvanceOriginal(int32_t aDelta
) {
263 SetOffsets(mOriginalStringOffset
+ aDelta
, true);
265 void AdvanceSkipped(int32_t aDelta
) {
266 SetOffsets(mSkippedStringOffset
+ aDelta
, false);
270 * @return the offset within the original string
272 int32_t GetOriginalOffset() const {
273 return mOriginalStringOffset
- mOriginalStringToSkipCharsOffset
;
276 * @return the offset within the skipped string corresponding to the
277 * current position in the original string. If the current position
278 * in the original string is a character that is skipped, then we return
279 * the position corresponding to the first non-skipped character in the
280 * original string after the current position, or the length of the skipped
281 * string if there is no such character.
283 uint32_t GetSkippedOffset() const { return mSkippedStringOffset
; }
285 int32_t GetOriginalEnd() const {
286 return mSkipChars
->GetOriginalCharCount() -
287 mOriginalStringToSkipCharsOffset
;
291 void SetOffsets(uint32_t aOffset
, bool aInOriginalString
);
293 const gfxSkipChars
* mSkipChars
;
294 int32_t mOriginalStringOffset
;
295 uint32_t mSkippedStringOffset
;
297 // This offset is added to map from "skipped+unskipped characters in
298 // the original DOM string" character space to "skipped+unskipped
299 // characters in the textrun's gfxSkipChars" character space
300 int32_t mOriginalStringToSkipCharsOffset
;
303 * This is used to speed up cursor-style traversal. The invariant is that
304 * the first mListPrefixLength bytes of mSkipChars.mList sum to
305 * mListPrefixCharCount, and the even-indexed bytes in that prefix sum to
306 * mListPrefixKeepCharCount.
307 * Also, 0 <= mListPrefixLength < mSkipChars.mListLength, or else
308 * mSkipChars.mListLength is zero.
309 * Also, mListPrefixCharCount <= mOriginalStringOffset (and therefore
310 * mListPrefixKeepCharCount < mSkippedStringOffset).
312 uint32_t mListPrefixLength
;
313 uint32_t mListPrefixCharCount
;
314 uint32_t mListPrefixKeepCharCount
;
317 #endif /*GFX_SKIP_CHARS_H*/