gfxSkipChars.h 9.5 KB

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