diff options
Diffstat (limited to 'gfx/thebes/gfxSkipChars.h')
-rw-r--r-- | gfx/thebes/gfxSkipChars.h | 308 |
1 files changed, 308 insertions, 0 deletions
diff --git a/gfx/thebes/gfxSkipChars.h b/gfx/thebes/gfxSkipChars.h new file mode 100644 index 000000000..352a16090 --- /dev/null +++ b/gfx/thebes/gfxSkipChars.h @@ -0,0 +1,308 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef GFX_SKIP_CHARS_H +#define GFX_SKIP_CHARS_H + +#include "nsTArray.h" + +/* + * gfxSkipChars is a data structure representing a list of characters that + * have been skipped. The initial string is called the "original string" + * and after skipping some characters, the result is called the "skipped string". + * gfxSkipChars provides efficient ways to translate between offsets in the + * original string and the skipped string. It is used by textrun code to keep + * track of offsets before and after text transformations such as whitespace + * compression and control code deletion. + */ + +/** + * The gfxSkipChars is represented as a sorted array of skipped ranges. + * + * A freshly-created gfxSkipChars means "all chars kept". + */ +class gfxSkipChars +{ + friend struct SkippedRangeStartComparator; + friend struct SkippedRangeOffsetComparator; + +private: + class SkippedRange + { + public: + SkippedRange(uint32_t aOffset, uint32_t aLength, uint32_t aDelta) + : mOffset(aOffset), mLength(aLength), mDelta(aDelta) + { } + + uint32_t Start() const + { + return mOffset; + } + + uint32_t End() const + { + return mOffset + mLength; + } + + uint32_t Length() const + { + return mLength; + } + + uint32_t SkippedOffset() const + { + return mOffset - mDelta; + } + + uint32_t Delta() const + { + return mDelta; + } + + uint32_t NextDelta() const + { + return mDelta + mLength; + } + + void Extend(uint32_t aChars) + { + mLength += aChars; + } + + private: + uint32_t mOffset; // original-string offset at which we want to skip + uint32_t mLength; // number of skipped chars at this offset + uint32_t mDelta; // sum of lengths of preceding skipped-ranges + }; + +public: + gfxSkipChars() + : mCharCount(0) + { } + + void SkipChars(uint32_t aChars) + { + NS_ASSERTION(mCharCount + aChars > mCharCount, + "Character count overflow"); + uint32_t rangeCount = mRanges.Length(); + uint32_t delta = 0; + if (rangeCount > 0) { + SkippedRange& lastRange = mRanges[rangeCount - 1]; + if (lastRange.End() == mCharCount) { + lastRange.Extend(aChars); + mCharCount += aChars; + return; + } + delta = lastRange.NextDelta(); + } + mRanges.AppendElement(SkippedRange(mCharCount, aChars, delta)); + mCharCount += aChars; + } + + void KeepChars(uint32_t aChars) + { + NS_ASSERTION(mCharCount + aChars > mCharCount, + "Character count overflow"); + mCharCount += aChars; + } + + void SkipChar() + { + SkipChars(1); + } + + void KeepChar() + { + KeepChars(1); + } + + void TakeFrom(gfxSkipChars* aSkipChars) + { + mRanges.SwapElements(aSkipChars->mRanges); + mCharCount = aSkipChars->mCharCount; + aSkipChars->mCharCount = 0; + } + + int32_t GetOriginalCharCount() const + { + return mCharCount; + } + + const SkippedRange& LastRange() const + { + // this is only valid if mRanges is non-empty; no assertion here + // because nsTArray will already assert if we abuse it + return mRanges[mRanges.Length() - 1]; + } + + friend class gfxSkipCharsIterator; + +private: + nsTArray<SkippedRange> mRanges; + uint32_t mCharCount; +}; + +/** + * A gfxSkipCharsIterator represents a position in the original string. It lets you + * map efficiently to and from positions in the string after skipped characters + * have been removed. You can also specify an offset that is added to all + * incoming original string offsets and subtracted from all outgoing original + * string offsets --- useful when the gfxSkipChars corresponds to something + * offset from the original DOM coordinates, which it often does for gfxTextRuns. + * + * The current positions (in both the original and skipped strings) are + * always constrained to be >= 0 and <= the string length. When the position + * is equal to the string length, it is at the end of the string. The current + * positions do not include any aOriginalStringToSkipCharsOffset. + * + * When the position in the original string corresponds to a skipped character, + * the skipped-characters offset is the offset of the next unskipped character, + * or the skipped-characters string length if there is no next unskipped character. + */ +class gfxSkipCharsIterator +{ +public: + /** + * @param aOriginalStringToSkipCharsOffset add this to all incoming and + * outgoing original string offsets + */ + gfxSkipCharsIterator(const gfxSkipChars& aSkipChars, + int32_t aOriginalStringToSkipCharsOffset, + int32_t aOriginalStringOffset) + : mSkipChars(&aSkipChars), + mOriginalStringOffset(0), + mSkippedStringOffset(0), + mCurrentRangeIndex(-1), + mOriginalStringToSkipCharsOffset(aOriginalStringToSkipCharsOffset) + { + SetOriginalOffset(aOriginalStringOffset); + } + + explicit gfxSkipCharsIterator(const gfxSkipChars& aSkipChars, + int32_t aOriginalStringToSkipCharsOffset = 0) + : mSkipChars(&aSkipChars), + mOriginalStringOffset(0), + mSkippedStringOffset(0), + mOriginalStringToSkipCharsOffset(aOriginalStringToSkipCharsOffset) + { + mCurrentRangeIndex = + mSkipChars->mRanges.IsEmpty() || + mSkipChars->mRanges[0].Start() > 0 ? -1 : 0; + } + + gfxSkipCharsIterator(const gfxSkipCharsIterator& aIterator) + : mSkipChars(aIterator.mSkipChars), + mOriginalStringOffset(aIterator.mOriginalStringOffset), + mSkippedStringOffset(aIterator.mSkippedStringOffset), + mCurrentRangeIndex(aIterator.mCurrentRangeIndex), + mOriginalStringToSkipCharsOffset(aIterator.mOriginalStringToSkipCharsOffset) + { } + + /** + * The empty constructor creates an object that is useless until it is assigned. + */ + gfxSkipCharsIterator() + : mSkipChars(nullptr) + { } + + /** + * Return true if this iterator is properly initialized and usable. + */ + bool IsInitialized() + { + return mSkipChars != nullptr; + } + + /** + * Set the iterator to aOriginalStringOffset in the original string. + * This can efficiently move forward or backward from the current position. + * aOriginalStringOffset is clamped to [0,originalStringLength]. + */ + void SetOriginalOffset(int32_t aOriginalStringOffset); + + /** + * Set the iterator to aSkippedStringOffset in the skipped string. + * This can efficiently move forward or backward from the current position. + * aSkippedStringOffset is clamped to [0,skippedStringLength]. + */ + void SetSkippedOffset(uint32_t aSkippedStringOffset); + + uint32_t ConvertOriginalToSkipped(int32_t aOriginalStringOffset) + { + SetOriginalOffset(aOriginalStringOffset); + return GetSkippedOffset(); + } + + int32_t ConvertSkippedToOriginal(uint32_t aSkippedStringOffset) + { + SetSkippedOffset(aSkippedStringOffset); + return GetOriginalOffset(); + } + + /** + * Test if the character at the current position in the original string + * is skipped or not. If aRunLength is non-null, then *aRunLength is set + * to a number of characters all of which are either skipped or not, starting + * at this character. When the current position is at the end of the original + * string, we return true and *aRunLength is set to zero. + */ + bool IsOriginalCharSkipped(int32_t* aRunLength = nullptr) const; + + void AdvanceOriginal(int32_t aDelta) + { + SetOriginalOffset(GetOriginalOffset() + aDelta); + } + + void AdvanceSkipped(int32_t aDelta) + { + SetSkippedOffset(GetSkippedOffset() + aDelta); + } + + /** + * @return the offset within the original string + */ + int32_t GetOriginalOffset() const + { + return mOriginalStringOffset - mOriginalStringToSkipCharsOffset; + } + + /** + * @return the offset within the skipped string corresponding to the + * current position in the original string. If the current position + * in the original string is a character that is skipped, then we return + * the position corresponding to the first non-skipped character in the + * original string after the current position, or the length of the skipped + * string if there is no such character. + */ + uint32_t GetSkippedOffset() const + { + return mSkippedStringOffset; + } + + int32_t GetOriginalEnd() const + { + return mSkipChars->GetOriginalCharCount() - + mOriginalStringToSkipCharsOffset; + } + +private: + const gfxSkipChars* mSkipChars; + + // Current position + int32_t mOriginalStringOffset; + uint32_t mSkippedStringOffset; + + // Index of the last skippedRange that precedes or contains the current + // position in the original string. + // If index == -1 then we are before the first skipped char. + int32_t mCurrentRangeIndex; + + // This offset is added to map from "skipped+unskipped characters in + // the original DOM string" character space to "skipped+unskipped + // characters in the textrun's gfxSkipChars" character space + int32_t mOriginalStringToSkipCharsOffset; +}; + +#endif /*GFX_SKIP_CHARS_H*/ |