bug 955957 - pt 1 - reimplement gfxSkipChars and gfxSkipCharsIterator to perform better with huge text runs. r=roc

This commit is contained in:
Jonathan Kew 2014-01-10 07:48:01 +00:00
parent 5d40c6e32d
commit 48bf0ba949
5 changed files with 289 additions and 402 deletions

View File

@ -5,227 +5,136 @@
#include "gfxSkipChars.h"
#include <stdlib.h>
#include <algorithm>
#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<uint32_t>(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);
}

View File

@ -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<uint8_t,256> 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<uint8_t> mList;
nsAutoArrayPtr<Shortcut> mShortcuts;
uint32_t mListLength;
uint32_t mCharCount;
nsTArray<SkippedRange> 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*/

View File

@ -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<char16_t*>(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<const char16_t*>(textPtr);
} else {
@ -2018,7 +2018,7 @@ BuildTextRunsScanner::BuildTextRunForFrames(void* aTextBuffer)
}
uint8_t* end = nsTextFrameUtils::TransformText(
reinterpret_cast<const uint8_t*>(frag->Get1b()) + contentStart, contentLength,
bufStart, compression, &mNextRunContextInfo, &builder, &analysisFlags);
bufStart, compression, &mNextRunContextInfo, &skipChars, &analysisFlags);
aTextBuffer = ExpandBuffer(static_cast<char16_t*>(aTextBuffer),
tempBuf.Elements(), end - tempBuf.Elements());
currentTransformedTextOffset =
@ -2027,7 +2027,7 @@ BuildTextRunsScanner::BuildTextRunForFrames(void* aTextBuffer)
uint8_t* bufStart = static_cast<uint8_t*>(aTextBuffer);
uint8_t* end = nsTextFrameUtils::TransformText(
reinterpret_cast<const uint8_t*>(frag->Get1b()) + contentStart, contentLength,
bufStart, compression, &mNextRunContextInfo, &builder, &analysisFlags);
bufStart, compression, &mNextRunContextInfo, &skipChars, &analysisFlags);
aTextBuffer = end;
currentTransformedTextOffset = end - static_cast<const uint8_t*>(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<int32_t,50> 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<char16_t*>(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<const uint8_t*>(frag->Get1b()) + contentStart, contentLength,
bufStart, compression, &mNextRunContextInfo, &builder, &analysisFlags);
bufStart, compression, &mNextRunContextInfo, &skipChars, &analysisFlags);
textPtr = ExpandBuffer(static_cast<char16_t*>(textPtr),
tempBuf.Elements(), end - tempBuf.Elements());
} else {
uint8_t* bufStart = static_cast<uint8_t*>(textPtr);
uint8_t* end = nsTextFrameUtils::TransformText(
reinterpret_cast<const uint8_t*>(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());
}
}

View File

@ -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;

View File

@ -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