Line data Source code
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 : #include "gfxSkipChars.h"
7 : #include "mozilla/BinarySearch.h"
8 :
9 : struct SkippedRangeStartComparator
10 : {
11 : const uint32_t mOffset;
12 0 : explicit SkippedRangeStartComparator(const uint32_t aOffset) : mOffset(aOffset) {}
13 0 : int operator()(const gfxSkipChars::SkippedRange& aRange) const {
14 0 : return (mOffset < aRange.Start()) ? -1 : 1;
15 : }
16 : };
17 :
18 : void
19 504 : gfxSkipCharsIterator::SetOriginalOffset(int32_t aOffset)
20 : {
21 504 : aOffset += mOriginalStringToSkipCharsOffset;
22 504 : if (MOZ_UNLIKELY(uint32_t(aOffset) > mSkipChars->mCharCount)) {
23 0 : gfxCriticalError() <<
24 0 : "invalid offset " << aOffset <<
25 0 : " for gfxSkipChars length " << mSkipChars->mCharCount;
26 0 : aOffset = mSkipChars->mCharCount;
27 : }
28 :
29 504 : mOriginalStringOffset = aOffset;
30 :
31 504 : const uint32_t rangeCount = mSkipChars->mRanges.Length();
32 504 : if (rangeCount == 0) {
33 504 : mSkippedStringOffset = aOffset;
34 1008 : return;
35 : }
36 :
37 : // at start of string?
38 0 : if (aOffset == 0) {
39 0 : mSkippedStringOffset = 0;
40 0 : mCurrentRangeIndex =
41 0 : rangeCount && mSkipChars->mRanges[0].Start() == 0 ? 0 : -1;
42 0 : return;
43 : }
44 :
45 : // find the range that includes or precedes aOffset
46 0 : const nsTArray<gfxSkipChars::SkippedRange>& ranges = mSkipChars->mRanges;
47 : size_t idx;
48 0 : mozilla::BinarySearchIf(ranges, 0, rangeCount,
49 0 : SkippedRangeStartComparator(aOffset),
50 0 : &idx);
51 :
52 0 : if (idx == rangeCount) {
53 0 : mCurrentRangeIndex = rangeCount - 1;
54 0 : } else if (uint32_t(aOffset) < ranges[idx].Start()) {
55 0 : mCurrentRangeIndex = idx - 1;
56 0 : if (mCurrentRangeIndex == -1) {
57 0 : mSkippedStringOffset = aOffset;
58 0 : return;
59 : }
60 : } else {
61 0 : mCurrentRangeIndex = idx;
62 : }
63 :
64 0 : const gfxSkipChars::SkippedRange& r = ranges[mCurrentRangeIndex];
65 0 : if (uint32_t(aOffset) < r.End()) {
66 0 : mSkippedStringOffset = r.SkippedOffset();
67 0 : return;
68 : }
69 :
70 0 : mSkippedStringOffset = aOffset - r.NextDelta();
71 : }
72 :
73 : struct SkippedRangeOffsetComparator
74 : {
75 : const uint32_t mOffset;
76 0 : explicit SkippedRangeOffsetComparator(const uint32_t aOffset) : mOffset(aOffset) {}
77 0 : int operator()(const gfxSkipChars::SkippedRange& aRange) const {
78 0 : return (mOffset < aRange.SkippedOffset()) ? -1 : 1;
79 : }
80 : };
81 :
82 : void
83 49 : gfxSkipCharsIterator::SetSkippedOffset(uint32_t aOffset)
84 : {
85 49 : NS_ASSERTION((mSkipChars->mRanges.IsEmpty() &&
86 : aOffset <= mSkipChars->mCharCount) ||
87 : (aOffset <= mSkipChars->LastRange().SkippedOffset() +
88 : mSkipChars->mCharCount -
89 : mSkipChars->LastRange().End()),
90 : "Invalid skipped offset");
91 49 : mSkippedStringOffset = aOffset;
92 :
93 49 : uint32_t rangeCount = mSkipChars->mRanges.Length();
94 49 : if (rangeCount == 0) {
95 49 : mOriginalStringOffset = aOffset;
96 98 : return;
97 : }
98 :
99 0 : const nsTArray<gfxSkipChars::SkippedRange>& ranges = mSkipChars->mRanges;
100 : size_t idx;
101 0 : mozilla::BinarySearchIf(ranges, 0, rangeCount,
102 0 : SkippedRangeOffsetComparator(aOffset),
103 0 : &idx);
104 :
105 0 : if (idx == rangeCount) {
106 0 : mCurrentRangeIndex = rangeCount - 1;
107 0 : } else if (aOffset < ranges[idx].SkippedOffset()) {
108 0 : mCurrentRangeIndex = idx - 1;
109 0 : if (mCurrentRangeIndex == -1) {
110 0 : mOriginalStringOffset = aOffset;
111 0 : return;
112 : }
113 : } else {
114 0 : mCurrentRangeIndex = idx;
115 : }
116 :
117 0 : const gfxSkipChars::SkippedRange& r = ranges[mCurrentRangeIndex];
118 0 : mOriginalStringOffset = r.End() + aOffset - r.SkippedOffset();
119 : }
120 :
121 : bool
122 225 : gfxSkipCharsIterator::IsOriginalCharSkipped(int32_t* aRunLength) const
123 : {
124 225 : if (mCurrentRangeIndex == -1) {
125 : // we're before the first skipped range (if any)
126 225 : if (aRunLength) {
127 0 : uint32_t end = mSkipChars->mRanges.IsEmpty() ?
128 0 : mSkipChars->mCharCount : mSkipChars->mRanges[0].Start();
129 0 : *aRunLength = end - mOriginalStringOffset;
130 : }
131 225 : return mSkipChars->mCharCount == uint32_t(mOriginalStringOffset);
132 : }
133 :
134 : const gfxSkipChars::SkippedRange& range =
135 0 : mSkipChars->mRanges[mCurrentRangeIndex];
136 :
137 0 : if (uint32_t(mOriginalStringOffset) < range.End()) {
138 0 : if (aRunLength) {
139 0 : *aRunLength = range.End() - mOriginalStringOffset;
140 : }
141 0 : return true;
142 : }
143 :
144 0 : if (aRunLength) {
145 : uint32_t end =
146 0 : uint32_t(mCurrentRangeIndex) + 1 < mSkipChars->mRanges.Length() ?
147 0 : mSkipChars->mRanges[mCurrentRangeIndex + 1].Start() :
148 0 : mSkipChars->mCharCount;
149 0 : *aRunLength = end - mOriginalStringOffset;
150 : }
151 :
152 0 : return mSkipChars->mCharCount == uint32_t(mOriginalStringOffset);
153 : }
|