Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/gfx/thebes/gfxSkipChars.h
Line
Count
Source (jump to first uncovered line)
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/. */
5
6
#ifndef GFX_SKIP_CHARS_H
7
#define GFX_SKIP_CHARS_H
8
9
#include "nsTArray.h"
10
11
/*
12
 * gfxSkipChars is a data structure representing a list of characters that
13
 * have been skipped. The initial string is called the "original string"
14
 * and after skipping some characters, the result is called the "skipped string".
15
 * gfxSkipChars provides efficient ways to translate between offsets in the
16
 * original string and the skipped string. It is used by textrun code to keep
17
 * track of offsets before and after text transformations such as whitespace
18
 * compression and control code deletion.
19
 */
20
21
/**
22
 * The gfxSkipChars is represented as a sorted array of skipped ranges.
23
 *
24
 * A freshly-created gfxSkipChars means "all chars kept".
25
 */
26
class gfxSkipChars
27
{
28
    friend struct SkippedRangeStartComparator;
29
    friend struct SkippedRangeOffsetComparator;
30
31
private:
32
    class SkippedRange
33
    {
34
    public:
35
        SkippedRange(uint32_t aOffset, uint32_t aLength, uint32_t aDelta)
36
            : mOffset(aOffset), mLength(aLength), mDelta(aDelta)
37
        { }
38
39
        uint32_t Start() const
40
        {
41
            return mOffset;
42
        }
43
44
        uint32_t End() const
45
        {
46
            return mOffset + mLength;
47
        }
48
49
        uint32_t Length() const
50
        {
51
            return mLength;
52
        }
53
54
        uint32_t SkippedOffset() const
55
        {
56
            return mOffset - mDelta;
57
        }
58
59
        uint32_t Delta() const
60
        {
61
            return mDelta;
62
        }
63
64
        uint32_t NextDelta() const
65
        {
66
            return mDelta + mLength;
67
        }
68
69
        void Extend(uint32_t aChars)
70
        {
71
            mLength += aChars;
72
        }
73
74
    private:
75
        uint32_t mOffset; // original-string offset at which we want to skip
76
        uint32_t mLength; // number of skipped chars at this offset
77
        uint32_t mDelta;  // sum of lengths of preceding skipped-ranges
78
    };
79
80
public:
81
    gfxSkipChars()
82
        : mCharCount(0)
83
0
    { }
84
85
    void SkipChars(uint32_t aChars)
86
    {
87
        NS_ASSERTION(mCharCount + aChars > mCharCount,
88
                     "Character count overflow");
89
        uint32_t rangeCount = mRanges.Length();
90
        uint32_t delta = 0;
91
        if (rangeCount > 0) {
92
            SkippedRange& lastRange = mRanges[rangeCount - 1];
93
            if (lastRange.End() == mCharCount) {
94
                lastRange.Extend(aChars);
95
                mCharCount += aChars;
96
                return;
97
            }
98
            delta = lastRange.NextDelta();
99
        }
100
        mRanges.AppendElement(SkippedRange(mCharCount, aChars, delta));
101
        mCharCount += aChars;
102
    }
103
104
    void KeepChars(uint32_t aChars)
105
    {
106
        NS_ASSERTION(mCharCount + aChars > mCharCount,
107
                     "Character count overflow");
108
        mCharCount += aChars;
109
    }
110
111
    void SkipChar()
112
    {
113
        SkipChars(1);
114
    }
115
116
    void KeepChar()
117
    {
118
        KeepChars(1);
119
    }
120
121
    void TakeFrom(gfxSkipChars* aSkipChars)
122
    {
123
        mRanges.SwapElements(aSkipChars->mRanges);
124
        mCharCount = aSkipChars->mCharCount;
125
        aSkipChars->mCharCount = 0;
126
    }
127
128
    int32_t GetOriginalCharCount() const
129
    {
130
        return mCharCount;
131
    }
132
133
    const SkippedRange& LastRange() const
134
    {
135
        // this is only valid if mRanges is non-empty; no assertion here
136
        // because nsTArray will already assert if we abuse it
137
        return mRanges[mRanges.Length() - 1];
138
    }
139
140
    friend class gfxSkipCharsIterator;
141
142
private:
143
    nsTArray<SkippedRange> mRanges;
144
    uint32_t               mCharCount;
145
};
146
147
/**
148
 * A gfxSkipCharsIterator represents a position in the original string. It lets you
149
 * map efficiently to and from positions in the string after skipped characters
150
 * have been removed. You can also specify an offset that is added to all
151
 * incoming original string offsets and subtracted from all outgoing original
152
 * string offsets --- useful when the gfxSkipChars corresponds to something
153
 * offset from the original DOM coordinates, which it often does for gfxTextRuns.
154
 *
155
 * The current positions (in both the original and skipped strings) are
156
 * always constrained to be >= 0 and <= the string length. When the position
157
 * is equal to the string length, it is at the end of the string. The current
158
 * positions do not include any aOriginalStringToSkipCharsOffset.
159
 *
160
 * When the position in the original string corresponds to a skipped character,
161
 * the skipped-characters offset is the offset of the next unskipped character,
162
 * or the skipped-characters string length if there is no next unskipped character.
163
 */
164
class gfxSkipCharsIterator
165
{
166
public:
167
    /**
168
     * @param aOriginalStringToSkipCharsOffset add this to all incoming and
169
     * outgoing original string offsets
170
     */
171
    gfxSkipCharsIterator(const gfxSkipChars& aSkipChars,
172
                         int32_t aOriginalStringToSkipCharsOffset,
173
                         int32_t aOriginalStringOffset)
174
        : mSkipChars(&aSkipChars),
175
          mOriginalStringOffset(0),
176
          mSkippedStringOffset(0),
177
          mCurrentRangeIndex(-1),
178
          mOriginalStringToSkipCharsOffset(aOriginalStringToSkipCharsOffset)
179
    {
180
        SetOriginalOffset(aOriginalStringOffset);
181
    }
182
183
    explicit gfxSkipCharsIterator(const gfxSkipChars& aSkipChars,
184
                                  int32_t aOriginalStringToSkipCharsOffset = 0)
185
        : mSkipChars(&aSkipChars),
186
          mOriginalStringOffset(0),
187
          mSkippedStringOffset(0),
188
          mOriginalStringToSkipCharsOffset(aOriginalStringToSkipCharsOffset)
189
    {
190
        mCurrentRangeIndex =
191
            mSkipChars->mRanges.IsEmpty() ||
192
            mSkipChars->mRanges[0].Start() > 0 ? -1 : 0;
193
    }
194
195
    gfxSkipCharsIterator(const gfxSkipCharsIterator& aIterator)
196
        : mSkipChars(aIterator.mSkipChars),
197
          mOriginalStringOffset(aIterator.mOriginalStringOffset),
198
          mSkippedStringOffset(aIterator.mSkippedStringOffset),
199
          mCurrentRangeIndex(aIterator.mCurrentRangeIndex),
200
          mOriginalStringToSkipCharsOffset(aIterator.mOriginalStringToSkipCharsOffset)
201
    { }
202
203
    /**
204
     * The empty constructor creates an object that is useless until it is assigned.
205
     */
206
    gfxSkipCharsIterator()
207
        : mSkipChars(nullptr),
208
          mOriginalStringOffset(0),
209
          mSkippedStringOffset(0),
210
          mCurrentRangeIndex(0),
211
          mOriginalStringToSkipCharsOffset(0)
212
    { }
213
214
    /**
215
     * Return true if this iterator is properly initialized and usable.
216
     */
217
    bool IsInitialized()
218
    {
219
        return mSkipChars != nullptr;
220
    }
221
222
    /**
223
     * Set the iterator to aOriginalStringOffset in the original string.
224
     * This can efficiently move forward or backward from the current position.
225
     * aOriginalStringOffset is clamped to [0,originalStringLength].
226
     */
227
    void SetOriginalOffset(int32_t aOriginalStringOffset);
228
229
    /**
230
     * Set the iterator to aSkippedStringOffset in the skipped string.
231
     * This can efficiently move forward or backward from the current position.
232
     * aSkippedStringOffset is clamped to [0,skippedStringLength].
233
     */
234
    void SetSkippedOffset(uint32_t aSkippedStringOffset);
235
236
    uint32_t ConvertOriginalToSkipped(int32_t aOriginalStringOffset)
237
    {
238
        SetOriginalOffset(aOriginalStringOffset);
239
        return GetSkippedOffset();
240
    }
241
242
    int32_t ConvertSkippedToOriginal(uint32_t aSkippedStringOffset)
243
    {
244
        SetSkippedOffset(aSkippedStringOffset);
245
        return GetOriginalOffset();
246
    }
247
248
    /**
249
     * Test if the character at the current position in the original string
250
     * is skipped or not. If aRunLength is non-null, then *aRunLength is set
251
     * to a number of characters all of which are either skipped or not, starting
252
     * at this character. When the current position is at the end of the original
253
     * string, we return true and *aRunLength is set to zero.
254
     */
255
    bool IsOriginalCharSkipped(int32_t* aRunLength = nullptr) const;
256
257
    void AdvanceOriginal(int32_t aDelta)
258
    {
259
        SetOriginalOffset(GetOriginalOffset() + aDelta);
260
    }
261
262
    void AdvanceSkipped(int32_t aDelta)
263
    {
264
        SetSkippedOffset(GetSkippedOffset() + aDelta);
265
    }
266
267
    /**
268
     * @return the offset within the original string
269
     */
270
    int32_t GetOriginalOffset() const
271
    {
272
        return mOriginalStringOffset - mOriginalStringToSkipCharsOffset;
273
    }
274
275
    /**
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.
282
     */
283
    uint32_t GetSkippedOffset() const
284
    {
285
        return mSkippedStringOffset;
286
    }
287
288
    int32_t GetOriginalEnd() const
289
    {
290
        return mSkipChars->GetOriginalCharCount() -
291
            mOriginalStringToSkipCharsOffset;
292
    }
293
294
private:
295
    const gfxSkipChars* mSkipChars;
296
297
    // Current position
298
    int32_t mOriginalStringOffset;
299
    uint32_t mSkippedStringOffset;
300
301
    // Index of the last skippedRange that precedes or contains the current
302
    // position in the original string.
303
    // If index == -1 then we are before the first skipped char.
304
    int32_t mCurrentRangeIndex;
305
306
    // This offset is added to map from "skipped+unskipped characters in
307
    // the original DOM string" character space to "skipped+unskipped
308
    // characters in the textrun's gfxSkipChars" character space
309
    int32_t mOriginalStringToSkipCharsOffset;
310
};
311
312
#endif /*GFX_SKIP_CHARS_H*/