diff --git a/gfx/thebes/gfxSkipChars.cpp b/gfx/thebes/gfxSkipChars.cpp index d1dbcb1d8b3a..a24eb12d80a4 100644 --- a/gfx/thebes/gfxSkipChars.cpp +++ b/gfx/thebes/gfxSkipChars.cpp @@ -5,227 +5,136 @@ #include "gfxSkipChars.h" -#include -#include - -#define SHORTCUT_FREQUENCY 256 - -// Even numbered list entries are "keep" entries -static bool -IsKeepEntry(uint32_t aEntry) -{ - return !(aEntry & 1); -} - void -gfxSkipChars::BuildShortcuts() +gfxSkipCharsIterator::SetOriginalOffset(int32_t aOffset) { - if (!mList || mCharCount < SHORTCUT_FREQUENCY) - return; - - mShortcuts = new Shortcut[mCharCount/SHORTCUT_FREQUENCY]; - if (!mShortcuts) - return; - - uint32_t i; - uint32_t nextShortcutIndex = 0; - uint32_t originalCharOffset = 0; - uint32_t skippedCharOffset = 0; - for (i = 0; i < mListLength; ++i) { - uint8_t len = mList[i]; - - // We use >= here to ensure that when mCharCount is a multiple of - // SHORTCUT_FREQUENCY, we fill in the final shortcut with a reference - // to the last element of mList. This means that in general when a list - // element ends on an offset that's a multiple of SHORTCUT_FREQUENCY, - // that list element is the shortcut for that offset, which is - // slightly suboptimal (the *next* element is the one we really want), - // but it's all correct and simpler this way. - while (originalCharOffset + len >= (nextShortcutIndex + 1)*SHORTCUT_FREQUENCY) { - mShortcuts[nextShortcutIndex] = - Shortcut(i, originalCharOffset, skippedCharOffset); - ++nextShortcutIndex; - } - - originalCharOffset += len; - if (IsKeepEntry(i)) { - skippedCharOffset += len; - } - } -} - -void -gfxSkipCharsIterator::SetOffsets(uint32_t aOffset, bool aInOriginalString) -{ - NS_ASSERTION(aOffset <= mSkipChars->mCharCount, + aOffset += mOriginalStringToSkipCharsOffset; + NS_ASSERTION(uint32_t(aOffset) <= mSkipChars->mCharCount, "Invalid offset"); - if (mSkipChars->mListLength == 0) { - mOriginalStringOffset = mSkippedStringOffset = aOffset; + mOriginalStringOffset = aOffset; + + uint32_t rangeCount = mSkipChars->mRanges.Length(); + if (rangeCount == 0) { + mSkippedStringOffset = aOffset; return; } - + + // at start of string? if (aOffset == 0) { - // Start from the beginning of the string. mSkippedStringOffset = 0; - mOriginalStringOffset = 0; - mListPrefixLength = 0; - mListPrefixKeepCharCount = 0; - mListPrefixCharCount = 0; - if (aInOriginalString) { - // Nothing more to do! + mCurrentRangeIndex = + rangeCount && mSkipChars->mRanges[0].Start() == 0 ? 0 : -1; + return; + } + + // find the range that includes or precedes aOffset + uint32_t lo = 0, hi = rangeCount; + const gfxSkipChars::SkippedRange* ranges = mSkipChars->mRanges.Elements(); + while (lo < hi) { + uint32_t mid = (lo + hi) / 2; + if (uint32_t(aOffset) < ranges[mid].Start()) { + hi = mid; + } else { + lo = mid + 1; + } + } + + if (lo == rangeCount) { + mCurrentRangeIndex = rangeCount - 1; + } else if (uint32_t(aOffset) < ranges[lo].Start()) { + mCurrentRangeIndex = lo - 1; + if (mCurrentRangeIndex == -1) { + mSkippedStringOffset = aOffset; return; } + } else { + mCurrentRangeIndex = lo; } - - if (aInOriginalString && mSkipChars->mShortcuts && - abs(int32_t(aOffset) - int32_t(mListPrefixCharCount)) > SHORTCUT_FREQUENCY) { - // Take a shortcut. This makes SetOffsets(..., true) O(1) by bounding - // the iterations in the loop below to at most SHORTCUT_FREQUENCY iterations - uint32_t shortcutIndex = aOffset/SHORTCUT_FREQUENCY; - if (shortcutIndex == 0) { - mListPrefixLength = 0; - mListPrefixKeepCharCount = 0; - mListPrefixCharCount = 0; + + const gfxSkipChars::SkippedRange& r = ranges[mCurrentRangeIndex]; + if (uint32_t(aOffset) < r.End()) { + mSkippedStringOffset = r.SkippedOffset(); + return; + } + + mSkippedStringOffset = aOffset - r.NextDelta(); +} + +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; + } + + uint32_t lo = 0, hi = rangeCount; + const gfxSkipChars::SkippedRange* ranges = mSkipChars->mRanges.Elements(); + while (lo < hi) { + uint32_t mid = (lo + hi) / 2; + if (aOffset < ranges[mid].SkippedOffset()) { + hi = mid; } else { - const gfxSkipChars::Shortcut& shortcut = mSkipChars->mShortcuts[shortcutIndex - 1]; - mListPrefixLength = shortcut.mListPrefixLength; - mListPrefixKeepCharCount = shortcut.mListPrefixKeepCharCount; - mListPrefixCharCount = shortcut.mListPrefixCharCount; + lo = mid + 1; } } - - int32_t currentRunLength = mSkipChars->mList[mListPrefixLength]; - for (;;) { - // See if aOffset is in the string segment described by - // mSkipChars->mList[mListPrefixLength] - uint32_t segmentOffset = aInOriginalString ? mListPrefixCharCount : mListPrefixKeepCharCount; - if ((aInOriginalString || IsKeepEntry(mListPrefixLength)) && - aOffset >= segmentOffset && aOffset < segmentOffset + currentRunLength) { - int32_t offsetInSegment = aOffset - segmentOffset; - mOriginalStringOffset = mListPrefixCharCount + offsetInSegment; - mSkippedStringOffset = mListPrefixKeepCharCount; - if (IsKeepEntry(mListPrefixLength)) { - mSkippedStringOffset += offsetInSegment; - } + + if (lo == rangeCount) { + mCurrentRangeIndex = rangeCount - 1; + } else if (aOffset < ranges[lo].SkippedOffset()) { + mCurrentRangeIndex = lo - 1; + if (mCurrentRangeIndex == -1) { + mOriginalStringOffset = aOffset; return; } - - if (aOffset < segmentOffset) { - // We need to move backwards - if (mListPrefixLength <= 0) { - // nowhere to go backwards - mOriginalStringOffset = mSkippedStringOffset = 0; - return; - } - // Go backwards one segment and restore invariants - --mListPrefixLength; - currentRunLength = mSkipChars->mList[mListPrefixLength]; - mListPrefixCharCount -= currentRunLength; - if (IsKeepEntry(mListPrefixLength)) { - mListPrefixKeepCharCount -= currentRunLength; - } - } else { - // We need to move forwards - if (mListPrefixLength >= mSkipChars->mListLength - 1) { - // nowhere to go forwards - mOriginalStringOffset = mListPrefixCharCount + currentRunLength; - mSkippedStringOffset = mListPrefixKeepCharCount; - if (IsKeepEntry(mListPrefixLength)) { - mSkippedStringOffset += currentRunLength; - } - return; - } - // Go forwards one segment and restore invariants - mListPrefixCharCount += currentRunLength; - if (IsKeepEntry(mListPrefixLength)) { - mListPrefixKeepCharCount += currentRunLength; - } - ++mListPrefixLength; - currentRunLength = mSkipChars->mList[mListPrefixLength]; - } + } else { + mCurrentRangeIndex = lo; } + + const gfxSkipChars::SkippedRange& r = ranges[mCurrentRangeIndex]; + mOriginalStringOffset = r.End() + aOffset - r.SkippedOffset(); } bool gfxSkipCharsIterator::IsOriginalCharSkipped(int32_t* aRunLength) const { - if (mSkipChars->mListLength == 0) { + if (mCurrentRangeIndex == -1) { + // we're before the first skipped range (if any) if (aRunLength) { - *aRunLength = mSkipChars->mCharCount - mOriginalStringOffset; + uint32_t end = mSkipChars->mRanges.IsEmpty() ? + mSkipChars->mCharCount : mSkipChars->mRanges[0].Start(); + *aRunLength = end - mOriginalStringOffset; } return mSkipChars->mCharCount == uint32_t(mOriginalStringOffset); } - - uint32_t listPrefixLength = mListPrefixLength; - // figure out which segment we're in - uint32_t currentRunLength = mSkipChars->mList[listPrefixLength]; - // Zero-length list entries are possible. Advance until mListPrefixLength - // is pointing to a run with real characters (or we're at the end of the - // string). - while (currentRunLength == 0 && listPrefixLength < mSkipChars->mListLength - 1) { - ++listPrefixLength; - // This does not break the iterator's invariant because no skipped - // or kept characters are being added - currentRunLength = mSkipChars->mList[listPrefixLength]; - } - NS_ASSERTION(uint32_t(mOriginalStringOffset) >= mListPrefixCharCount, - "Invariant violation"); - uint32_t offsetIntoCurrentRun = - uint32_t(mOriginalStringOffset) - mListPrefixCharCount; - if (listPrefixLength >= mSkipChars->mListLength - 1 && - offsetIntoCurrentRun >= currentRunLength) { - NS_ASSERTION(listPrefixLength == mSkipChars->mListLength - 1 && - offsetIntoCurrentRun == currentRunLength, - "Overran end of string"); - // We're at the end of the string + + const gfxSkipChars::SkippedRange& range = + mSkipChars->mRanges[mCurrentRangeIndex]; + + if (uint32_t(mOriginalStringOffset) < range.End()) { if (aRunLength) { - *aRunLength = 0; + *aRunLength = range.End() - mOriginalStringOffset; } return true; } - - bool isSkipped = !IsKeepEntry(listPrefixLength); - if (aRunLength) { - // Long runs of all-skipped or all-kept characters will be encoded as - // sequences of 255, 0, 255, 0 etc. Compute the maximum run length by skipping - // over zero entries. - uint32_t runLength = currentRunLength - offsetIntoCurrentRun; - for (uint32_t i = listPrefixLength + 2; i < mSkipChars->mListLength; i += 2) { - if (mSkipChars->mList[i - 1] != 0) - break; - runLength += mSkipChars->mList[i]; - } - *aRunLength = runLength; - } - return isSkipped; -} -void -gfxSkipCharsBuilder::FlushRun() -{ - NS_ASSERTION((mBuffer.Length() & 1) == mRunSkipped, - "out of sync?"); - // Fill in buffer entries starting at mBufferLength, as many as necessary - uint32_t charCount = mRunCharCount; - for (;;) { - uint32_t chars = std::min(255, charCount); - if (!mBuffer.AppendElement(chars)) { - mInErrorState = true; - return; - } - charCount -= chars; - if (charCount == 0) - break; - if (!mBuffer.AppendElement(0)) { - mInErrorState = true; - return; - } + if (aRunLength) { + uint32_t end = + uint32_t(mCurrentRangeIndex) + 1 < mSkipChars->mRanges.Length() ? + mSkipChars->mRanges[mCurrentRangeIndex + 1].Start() : + mSkipChars->mCharCount; + *aRunLength = end - mOriginalStringOffset; } - - NS_ASSERTION(mCharCount + mRunCharCount >= mCharCount, - "String length overflow"); - mCharCount += mRunCharCount; - mRunCharCount = 0; - mRunSkipped = !mRunSkipped; + + return mSkipChars->mCharCount == uint32_t(mOriginalStringOffset); } diff --git a/gfx/thebes/gfxSkipChars.h b/gfx/thebes/gfxSkipChars.h index bd094e1b6ccb..f276a68d8c95 100644 --- a/gfx/thebes/gfxSkipChars.h +++ b/gfx/thebes/gfxSkipChars.h @@ -6,7 +6,6 @@ #ifndef GFX_SKIP_CHARS_H #define GFX_SKIP_CHARS_H -#include "nsAutoPtr.h" #include "nsTArray.h" /* @@ -20,146 +19,126 @@ */ /** - * gfxSkipCharsBuilder is a helper class that accumulates a list of (skip, keep) - * commands and can eventually be used to construct a real gfxSkipChars. - * gfxSkipCharsBuilder objects are quite large so don't keep these around. - * On the positive side, the Skip/KeepChar(s) methods are very efficient, - * especially when you have runs of all-kept or all-skipped characters. - * - * mBuffer is an array of bytes; even numbered bytes represent characters kept, - * odd numbered bytes represent characters skipped. After those characters - * are accounted for, we have mRunCharCount characters which are kept or - * skipped depending on the value of mRunSkipped. - * - * mCharCount is the sum of counts of all skipped and kept characters, i.e., - * the length of the original string. - */ -class gfxSkipCharsBuilder { -public: - gfxSkipCharsBuilder() : - mCharCount(0), mRunCharCount(0), mRunSkipped(false), mInErrorState(false) - {} - - void SkipChars(uint32_t aChars) { - DoChars(aChars, true); - } - void KeepChars(uint32_t aChars) { - DoChars(aChars, false); - } - void SkipChar() { - SkipChars(1); - } - void KeepChar() { - KeepChars(1); - } - void DoChars(uint32_t aChars, bool aSkipped) { - if (aSkipped != mRunSkipped && aChars > 0) { - FlushRun(); - } - NS_ASSERTION(mRunCharCount + aChars > mRunCharCount, - "Character count overflow"); - mRunCharCount += aChars; - } - - bool IsOK() { return !mInErrorState; } - - uint32_t GetCharCount() { return mCharCount + mRunCharCount; } - bool GetAllCharsKept() { return mBuffer.Length() == 0; } - - friend class gfxSkipChars; - -private: - typedef AutoFallibleTArray Buffer; - - /** - * Moves mRunCharCount/mRunSkipped to the buffer (updating mCharCount), - * sets mRunCharCount to zero and toggles mRunSkipped. - */ - void FlushRun(); - - Buffer mBuffer; - uint32_t mCharCount; - uint32_t mRunCharCount; - bool mRunSkipped; // == mBuffer.Length()&1 - bool mInErrorState; -}; - -/** - * The gfxSkipChars list is represented as a list of bytes of the form - * [chars to keep, chars to skip, chars to keep, chars to skip, ...] - * In the special case where all chars are to be kept, the list is length - * zero. - * + * The gfxSkipChars is represented as a sorted array of skipped ranges. + * * A freshly-created gfxSkipChars means "all chars kept". */ -class gfxSkipChars { +class gfxSkipChars +{ +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() : mListLength(0), mCharCount(0) {} - - void TakeFrom(gfxSkipChars* aSkipChars) { - mList = aSkipChars->mList.forget(); - mListLength = aSkipChars->mListLength; + 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; - aSkipChars->mListLength = 0; - BuildShortcuts(); } - - void TakeFrom(gfxSkipCharsBuilder* aSkipCharsBuilder) { - if (!aSkipCharsBuilder->mBuffer.Length()) { - NS_ASSERTION(!aSkipCharsBuilder->mRunSkipped, "out of sync"); - // all characters kept - mCharCount = aSkipCharsBuilder->mRunCharCount; - mList = nullptr; - mListLength = 0; - } else { - aSkipCharsBuilder->FlushRun(); - mCharCount = aSkipCharsBuilder->mCharCount; - mList = new uint8_t[aSkipCharsBuilder->mBuffer.Length()]; - if (!mList) { - mListLength = 0; - } else { - mListLength = aSkipCharsBuilder->mBuffer.Length(); - memcpy(mList, aSkipCharsBuilder->mBuffer.Elements(), mListLength); - } - } - aSkipCharsBuilder->mBuffer.Clear(); - aSkipCharsBuilder->mCharCount = 0; - aSkipCharsBuilder->mRunCharCount = 0; - aSkipCharsBuilder->mRunSkipped = false; - BuildShortcuts(); + + int32_t GetOriginalCharCount() const + { + return mCharCount; } - - void SetAllKeep(uint32_t aLength) { - mCharCount = aLength; - mList = nullptr; - mListLength = 0; + + 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]; } - - int32_t GetOriginalCharCount() const { return mCharCount; } friend class gfxSkipCharsIterator; private: - struct Shortcut { - uint32_t mListPrefixLength; - uint32_t mListPrefixCharCount; - uint32_t mListPrefixKeepCharCount; - - Shortcut() {} - Shortcut(uint32_t aListPrefixLength, uint32_t aListPrefixCharCount, - uint32_t aListPrefixKeepCharCount) : - mListPrefixLength(aListPrefixLength), - mListPrefixCharCount(aListPrefixCharCount), - mListPrefixKeepCharCount(aListPrefixKeepCharCount) {} - }; - - void BuildShortcuts(); - - nsAutoArrayPtr mList; - nsAutoArrayPtr mShortcuts; - uint32_t mListLength; - uint32_t mCharCount; + nsTArray mRanges; + uint32_t mCharCount; }; /** @@ -169,17 +148,18 @@ private: * 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 { +class gfxSkipCharsIterator +{ public: /** * @param aOriginalStringToSkipCharsOffset add this to all incoming and @@ -189,66 +169,72 @@ public: int32_t aOriginalStringToSkipCharsOffset, int32_t aOriginalStringOffset) : mSkipChars(&aSkipChars), - mOriginalStringToSkipCharsOffset(aOriginalStringToSkipCharsOffset), - mListPrefixLength(0), mListPrefixCharCount(0), mListPrefixKeepCharCount(0) { + mOriginalStringOffset(0), + mSkippedStringOffset(0), + mCurrentRangeIndex(-1), + mOriginalStringToSkipCharsOffset(aOriginalStringToSkipCharsOffset) + { SetOriginalOffset(aOriginalStringOffset); } gfxSkipCharsIterator(const gfxSkipChars& aSkipChars, int32_t aOriginalStringToSkipCharsOffset = 0) : mSkipChars(&aSkipChars), - mOriginalStringOffset(0), mSkippedStringOffset(0), - mOriginalStringToSkipCharsOffset(aOriginalStringToSkipCharsOffset), - mListPrefixLength(0), mListPrefixCharCount(0), mListPrefixKeepCharCount(0) { - } + mOriginalStringOffset(0), + mSkippedStringOffset(0), + mCurrentRangeIndex(-1), + mOriginalStringToSkipCharsOffset(aOriginalStringToSkipCharsOffset) + { } gfxSkipCharsIterator(const gfxSkipCharsIterator& aIterator) : mSkipChars(aIterator.mSkipChars), mOriginalStringOffset(aIterator.mOriginalStringOffset), mSkippedStringOffset(aIterator.mSkippedStringOffset), - mOriginalStringToSkipCharsOffset(aIterator.mOriginalStringToSkipCharsOffset), - mListPrefixLength(aIterator.mListPrefixLength), - mListPrefixCharCount(aIterator.mListPrefixCharCount), - mListPrefixKeepCharCount(aIterator.mListPrefixKeepCharCount) - {} - + mCurrentRangeIndex(aIterator.mCurrentRangeIndex), + mOriginalStringToSkipCharsOffset(aIterator.mOriginalStringToSkipCharsOffset) + { } + /** * The empty constructor creates an object that is useless until it is assigned. */ - gfxSkipCharsIterator() : mSkipChars(nullptr) {} + gfxSkipCharsIterator() + : mSkipChars(nullptr) + { } /** * Return true if this iterator is properly initialized and usable. - */ - bool IsInitialized() { return mSkipChars != nullptr; } + */ + 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) { - SetOffsets(aOriginalStringOffset + mOriginalStringToSkipCharsOffset, true); - } - + 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) { - SetOffsets(aSkippedStringOffset, false); - } - - uint32_t ConvertOriginalToSkipped(int32_t aOriginalStringOffset) { + void SetSkippedOffset(uint32_t aSkippedStringOffset); + + uint32_t ConvertOriginalToSkipped(int32_t aOriginalStringOffset) + { SetOriginalOffset(aOriginalStringOffset); return GetSkippedOffset(); } - uint32_t ConvertSkippedToOriginal(int32_t aSkippedStringOffset) { + + uint32_t ConvertSkippedToOriginal(int32_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 @@ -257,20 +243,25 @@ public: * string, we return true and *aRunLength is set to zero. */ bool IsOriginalCharSkipped(int32_t* aRunLength = nullptr) const; - - void AdvanceOriginal(int32_t aDelta) { - SetOffsets(mOriginalStringOffset + aDelta, true); + + void AdvanceOriginal(int32_t aDelta) + { + SetOriginalOffset(GetOriginalOffset() + aDelta); } - void AdvanceSkipped(int32_t aDelta) { - SetOffsets(mSkippedStringOffset + aDelta, false); + + void AdvanceSkipped(int32_t aDelta) + { + SetSkippedOffset(GetSkippedOffset() + aDelta); } - + /** * @return the offset within the original string */ - int32_t GetOriginalOffset() const { + 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 @@ -279,38 +270,33 @@ public: * 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; } + uint32_t GetSkippedOffset() const + { + return mSkippedStringOffset; + } - int32_t GetOriginalEnd() const { + int32_t GetOriginalEnd() const + { return mSkipChars->GetOriginalCharCount() - mOriginalStringToSkipCharsOffset; } private: - void SetOffsets(uint32_t aOffset, bool aInOriginalString); - 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; - - /* - * This is used to speed up cursor-style traversal. The invariant is that - * the first mListPrefixLength bytes of mSkipChars.mList sum to - * mListPrefixCharCount, and the even-indexed bytes in that prefix sum to - * mListPrefixKeepCharCount. - * Also, 0 <= mListPrefixLength < mSkipChars.mListLength, or else - * mSkipChars.mListLength is zero. - * Also, mListPrefixCharCount <= mOriginalStringOffset (and therefore - * mListPrefixKeepCharCount < mSkippedStringOffset). - */ - uint32_t mListPrefixLength; - uint32_t mListPrefixCharCount; - uint32_t mListPrefixKeepCharCount; }; #endif /*GFX_SKIP_CHARS_H*/ diff --git a/layout/generic/nsTextFrame.cpp b/layout/generic/nsTextFrame.cpp index 92d05b6f93de..ce015b44ac13 100644 --- a/layout/generic/nsTextFrame.cpp +++ b/layout/generic/nsTextFrame.cpp @@ -1888,7 +1888,7 @@ static const nsTextFrameUtils::CompressionMode CSSWhitespaceToCompressionMode[] gfxTextRun* BuildTextRunsScanner::BuildTextRunForFrames(void* aTextBuffer) { - gfxSkipCharsBuilder builder; + gfxSkipChars skipChars; const void* textPtr = aTextBuffer; bool anySmallcapsStyle = false; @@ -1987,7 +1987,7 @@ BuildTextRunsScanner::BuildTextRunForFrames(void* aTextBuffer) TextRunMappedFlow* newFlow = &userData->mMappedFlows[i]; newFlow->mStartFrame = mappedFlow->mStartFrame; - newFlow->mDOMOffsetToBeforeTransformOffset = builder.GetCharCount() - + newFlow->mDOMOffsetToBeforeTransformOffset = skipChars.GetOriginalCharCount() - mappedFlow->mStartFrame->GetContentOffset(); newFlow->mContentLength = contentLength; @@ -2003,7 +2003,7 @@ BuildTextRunsScanner::BuildTextRunForFrames(void* aTextBuffer) char16_t* bufStart = static_cast(aTextBuffer); char16_t* bufEnd = nsTextFrameUtils::TransformText( frag->Get2b() + contentStart, contentLength, bufStart, - compression, &mNextRunContextInfo, &builder, &analysisFlags); + compression, &mNextRunContextInfo, &skipChars, &analysisFlags); aTextBuffer = bufEnd; currentTransformedTextOffset = bufEnd - static_cast(textPtr); } else { @@ -2018,7 +2018,7 @@ BuildTextRunsScanner::BuildTextRunForFrames(void* aTextBuffer) } uint8_t* end = nsTextFrameUtils::TransformText( reinterpret_cast(frag->Get1b()) + contentStart, contentLength, - bufStart, compression, &mNextRunContextInfo, &builder, &analysisFlags); + bufStart, compression, &mNextRunContextInfo, &skipChars, &analysisFlags); aTextBuffer = ExpandBuffer(static_cast(aTextBuffer), tempBuf.Elements(), end - tempBuf.Elements()); currentTransformedTextOffset = @@ -2027,7 +2027,7 @@ BuildTextRunsScanner::BuildTextRunForFrames(void* aTextBuffer) uint8_t* bufStart = static_cast(aTextBuffer); uint8_t* end = nsTextFrameUtils::TransformText( reinterpret_cast(frag->Get1b()) + contentStart, contentLength, - bufStart, compression, &mNextRunContextInfo, &builder, &analysisFlags); + bufStart, compression, &mNextRunContextInfo, &skipChars, &analysisFlags); aTextBuffer = end; currentTransformedTextOffset = end - static_cast(textPtr); } @@ -2035,12 +2035,6 @@ BuildTextRunsScanner::BuildTextRunForFrames(void* aTextBuffer) textFlags |= analysisFlags; } - // Check for out-of-memory in gfxSkipCharsBuilder - if (!builder.IsOK()) { - DestroyUserData(userDataToDestroy); - return nullptr; - } - void* finalUserData; if (userData == &dummyData) { textFlags |= nsTextFrameUtils::TEXT_IS_SIMPLE_FLOW; @@ -2093,8 +2087,6 @@ BuildTextRunsScanner::BuildTextRunForFrames(void* aTextBuffer) textFlags |= gfxTextRunFactory::TEXT_NEED_BOUNDING_BOX; } - gfxSkipChars skipChars; - skipChars.TakeFrom(&builder); // Convert linebreak coordinates to transformed string offsets NS_ASSERTION(nextBreakIndex == mLineBreakBeforeFrames.Length(), "Didn't find all the frames to break-before..."); @@ -2235,7 +2227,7 @@ BuildTextRunsScanner::SetupLineBreakerContext(gfxTextRun *aTextRun) return false; } - gfxSkipCharsBuilder builder; + gfxSkipChars skipChars; nsAutoTArray textBreakPoints; TextRunUserData dummyData; @@ -2280,7 +2272,7 @@ BuildTextRunsScanner::SetupLineBreakerContext(gfxTextRun *aTextRun) TextRunMappedFlow* newFlow = &userData->mMappedFlows[i]; newFlow->mStartFrame = mappedFlow->mStartFrame; - newFlow->mDOMOffsetToBeforeTransformOffset = builder.GetCharCount() - + newFlow->mDOMOffsetToBeforeTransformOffset = skipChars.GetOriginalCharCount() - mappedFlow->mStartFrame->GetContentOffset(); newFlow->mContentLength = contentLength; @@ -2296,7 +2288,7 @@ BuildTextRunsScanner::SetupLineBreakerContext(gfxTextRun *aTextRun) char16_t* bufStart = static_cast(textPtr); char16_t* bufEnd = nsTextFrameUtils::TransformText( frag->Get2b() + contentStart, contentLength, bufStart, - compression, &mNextRunContextInfo, &builder, &analysisFlags); + compression, &mNextRunContextInfo, &skipChars, &analysisFlags); textPtr = bufEnd; } else { if (mDoubleByteText) { @@ -2310,14 +2302,14 @@ BuildTextRunsScanner::SetupLineBreakerContext(gfxTextRun *aTextRun) } uint8_t* end = nsTextFrameUtils::TransformText( reinterpret_cast(frag->Get1b()) + contentStart, contentLength, - bufStart, compression, &mNextRunContextInfo, &builder, &analysisFlags); + bufStart, compression, &mNextRunContextInfo, &skipChars, &analysisFlags); textPtr = ExpandBuffer(static_cast(textPtr), tempBuf.Elements(), end - tempBuf.Elements()); } else { uint8_t* bufStart = static_cast(textPtr); uint8_t* end = nsTextFrameUtils::TransformText( reinterpret_cast(frag->Get1b()) + contentStart, contentLength, - bufStart, compression, &mNextRunContextInfo, &builder, &analysisFlags); + bufStart, compression, &mNextRunContextInfo, &skipChars, &analysisFlags); textPtr = end; } } @@ -8331,7 +8323,7 @@ nsresult nsTextFrame::GetRenderedText(nsAString* aAppendToString, uint32_t aSkippedMaxLength) { // The handling of aSkippedStartOffset and aSkippedMaxLength could be more efficient... - gfxSkipCharsBuilder skipCharsBuilder; + gfxSkipChars skipChars; nsTextFrame* textFrame; const nsTextFragment* textFrag = mContent->GetText(); uint32_t keptCharsLength = 0; @@ -8360,7 +8352,7 @@ nsresult nsTextFrame::GetRenderedText(nsAString* aAppendToString, TrimmedOffsets trimmedContentOffsets = textFrame->GetTrimmedOffsets(textFrag, false); int32_t startOfLineSkipChars = trimmedContentOffsets.mStart - textFrame->mContentOffset; if (startOfLineSkipChars > 0) { - skipCharsBuilder.SkipChars(startOfLineSkipChars); + skipChars.SkipChars(startOfLineSkipChars); iter.SetOriginalOffset(trimmedContentOffsets.mStart); } @@ -8370,10 +8362,10 @@ nsresult nsTextFrame::GetRenderedText(nsAString* aAppendToString, keptCharsLength < aSkippedMaxLength) { // For each original char from content text if (iter.IsOriginalCharSkipped() || ++validCharsLength <= aSkippedStartOffset) { - skipCharsBuilder.SkipChar(); + skipChars.SkipChar(); } else { ++keptCharsLength; - skipCharsBuilder.KeepChar(); + skipChars.KeepChar(); if (aAppendToString) { aAppendToString->Append( TransformChar(textStyle, textFrame->mTextRun, iter.GetSkippedOffset(), @@ -8388,10 +8380,10 @@ nsresult nsTextFrame::GetRenderedText(nsAString* aAppendToString, } if (aSkipChars) { - aSkipChars->TakeFrom(&skipCharsBuilder); // Copy skipChars into aSkipChars + aSkipChars->TakeFrom(&skipChars); // Copy skipChars into aSkipChars if (aSkipIter) { // Caller must provide both pointers in order to retrieve a gfxSkipCharsIterator, - // because the gfxSkipCharsIterator holds a weak pointer to the gfxSkipCars. + // because the gfxSkipCharsIterator holds a weak pointer to the gfxSkipChars. *aSkipIter = gfxSkipCharsIterator(*aSkipChars, GetContentLength()); } } diff --git a/layout/generic/nsTextFrameUtils.cpp b/layout/generic/nsTextFrameUtils.cpp index 272280fdfea9..e00c6bf6fdd7 100644 --- a/layout/generic/nsTextFrameUtils.cpp +++ b/layout/generic/nsTextFrameUtils.cpp @@ -38,7 +38,7 @@ nsTextFrameUtils::TransformText(const char16_t* aText, uint32_t aLength, char16_t* aOutput, CompressionMode aCompression, uint8_t* aIncomingFlags, - gfxSkipCharsBuilder* aSkipChars, + gfxSkipChars* aSkipChars, uint32_t* aAnalysisFlags) { uint32_t flags = 0; @@ -140,7 +140,7 @@ nsTextFrameUtils::TransformText(const uint8_t* aText, uint32_t aLength, uint8_t* aOutput, CompressionMode aCompression, uint8_t* aIncomingFlags, - gfxSkipCharsBuilder* aSkipChars, + gfxSkipChars* aSkipChars, uint32_t* aAnalysisFlags) { uint32_t flags = 0; diff --git a/layout/generic/nsTextFrameUtils.h b/layout/generic/nsTextFrameUtils.h index eb2e9413b160..800c84fe268f 100644 --- a/layout/generic/nsTextFrameUtils.h +++ b/layout/generic/nsTextFrameUtils.h @@ -100,14 +100,14 @@ public: char16_t* aOutput, CompressionMode aCompression, uint8_t * aIncomingFlags, - gfxSkipCharsBuilder* aSkipChars, + gfxSkipChars* aSkipChars, uint32_t* aAnalysisFlags); static uint8_t* TransformText(const uint8_t* aText, uint32_t aLength, uint8_t* aOutput, CompressionMode aCompression, uint8_t * aIncomingFlags, - gfxSkipCharsBuilder* aSkipChars, + gfxSkipChars* aSkipChars, uint32_t* aAnalysisFlags); static void