diff options
Diffstat (limited to 'gfx/thebes/gfxSkipChars.cpp')
-rw-r--r-- | gfx/thebes/gfxSkipChars.cpp | 146 |
1 files changed, 146 insertions, 0 deletions
diff --git a/gfx/thebes/gfxSkipChars.cpp b/gfx/thebes/gfxSkipChars.cpp new file mode 100644 index 0000000000..cd230efe74 --- /dev/null +++ b/gfx/thebes/gfxSkipChars.cpp @@ -0,0 +1,146 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * 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/. */ + +#include "gfxSkipChars.h" +#include "mozilla/BinarySearch.h" +#include "mozilla/gfx/Logging.h" + +struct SkippedRangeStartComparator { + const uint32_t mOffset; + explicit SkippedRangeStartComparator(const uint32_t aOffset) + : mOffset(aOffset) {} + int operator()(const gfxSkipChars::SkippedRange& aRange) const { + return (mOffset < aRange.Start()) ? -1 : 1; + } +}; + +void gfxSkipCharsIterator::SetOriginalOffset(int32_t aOffset) { + aOffset += mOriginalStringToSkipCharsOffset; + if (MOZ_UNLIKELY(uint32_t(aOffset) > mSkipChars->mCharCount)) { + gfxCriticalError() << "invalid offset " << aOffset + << " for gfxSkipChars length " << mSkipChars->mCharCount; + aOffset = mSkipChars->mCharCount; + } + + mOriginalStringOffset = aOffset; + + const uint32_t rangeCount = mSkipChars->mRanges.Length(); + if (rangeCount == 0) { + mSkippedStringOffset = aOffset; + return; + } + + // at start of string? + if (aOffset == 0) { + mSkippedStringOffset = 0; + mCurrentRangeIndex = + rangeCount && mSkipChars->mRanges[0].Start() == 0 ? 0 : -1; + return; + } + + // find the range that includes or precedes aOffset + const nsTArray<gfxSkipChars::SkippedRange>& ranges = mSkipChars->mRanges; + size_t idx; + mozilla::BinarySearchIf(ranges, 0, rangeCount, + SkippedRangeStartComparator(aOffset), &idx); + + if (idx == rangeCount) { + mCurrentRangeIndex = rangeCount - 1; + } else if (uint32_t(aOffset) < ranges[idx].Start()) { + mCurrentRangeIndex = idx - 1; + if (mCurrentRangeIndex == -1) { + mSkippedStringOffset = aOffset; + return; + } + } else { + mCurrentRangeIndex = idx; + } + + const gfxSkipChars::SkippedRange& r = ranges[mCurrentRangeIndex]; + if (uint32_t(aOffset) < r.End()) { + mSkippedStringOffset = r.SkippedOffset(); + return; + } + + mSkippedStringOffset = aOffset - r.NextDelta(); +} + +struct SkippedRangeOffsetComparator { + const uint32_t mOffset; + explicit SkippedRangeOffsetComparator(const uint32_t aOffset) + : mOffset(aOffset) {} + int operator()(const gfxSkipChars::SkippedRange& aRange) const { + return (mOffset < aRange.SkippedOffset()) ? -1 : 1; + } +}; + +void gfxSkipCharsIterator::SetSkippedOffset(uint32_t aOffset) { + NS_ASSERTION( + (mSkipChars->mRanges.IsEmpty() && aOffset <= mSkipChars->mCharCount) || + (aOffset <= mSkipChars->LastRange().SkippedOffset() + + mSkipChars->mCharCount - + mSkipChars->LastRange().End()), + "Invalid skipped offset"); + mSkippedStringOffset = aOffset; + + uint32_t rangeCount = mSkipChars->mRanges.Length(); + if (rangeCount == 0) { + mOriginalStringOffset = aOffset; + return; + } + + const nsTArray<gfxSkipChars::SkippedRange>& ranges = mSkipChars->mRanges; + size_t idx; + mozilla::BinarySearchIf(ranges, 0, rangeCount, + SkippedRangeOffsetComparator(aOffset), &idx); + + if (idx == rangeCount) { + mCurrentRangeIndex = rangeCount - 1; + } else if (aOffset < ranges[idx].SkippedOffset()) { + mCurrentRangeIndex = idx - 1; + if (mCurrentRangeIndex == -1) { + mOriginalStringOffset = aOffset; + return; + } + } else { + mCurrentRangeIndex = idx; + } + + const gfxSkipChars::SkippedRange& r = ranges[mCurrentRangeIndex]; + mOriginalStringOffset = r.End() + aOffset - r.SkippedOffset(); +} + +bool gfxSkipCharsIterator::IsOriginalCharSkipped(int32_t* aRunLength) const { + if (mCurrentRangeIndex == -1) { + // we're before the first skipped range (if any) + if (aRunLength) { + uint32_t end = mSkipChars->mRanges.IsEmpty() + ? mSkipChars->mCharCount + : mSkipChars->mRanges[0].Start(); + *aRunLength = end - mOriginalStringOffset; + } + return mSkipChars->mCharCount == uint32_t(mOriginalStringOffset); + } + + const gfxSkipChars::SkippedRange& range = + mSkipChars->mRanges[mCurrentRangeIndex]; + + if (uint32_t(mOriginalStringOffset) < range.End()) { + if (aRunLength) { + *aRunLength = range.End() - mOriginalStringOffset; + } + return true; + } + + if (aRunLength) { + uint32_t end = + uint32_t(mCurrentRangeIndex) + 1 < mSkipChars->mRanges.Length() + ? mSkipChars->mRanges[mCurrentRangeIndex + 1].Start() + : mSkipChars->mCharCount; + *aRunLength = end - mOriginalStringOffset; + } + + return mSkipChars->mCharCount == uint32_t(mOriginalStringOffset); +} |