зеркало из https://github.com/mozilla/pjs.git
Bug 430332. Defer nsTransformingTextRun::RebuildTextRun until the linebreaker has completely set up the break and capitalization data on the transformed text run. r=smontagu
This commit is contained in:
Родитель
72a5cdcb42
Коммит
f570471138
|
@ -61,7 +61,9 @@ public:
|
||||||
* character. This is used for the context detection necessary for
|
* character. This is used for the context detection necessary for
|
||||||
* bidi.numeral implementation.
|
* bidi.numeral implementation.
|
||||||
*/
|
*/
|
||||||
TEXT_INCOMING_ARABICCHAR = 0x40000000
|
TEXT_INCOMING_ARABICCHAR = 0x40000000,
|
||||||
|
|
||||||
|
TEXT_UNUSED_FLAGS = 0x80000000
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1394,6 +1394,10 @@ gfxTextRun::~gfxTextRun()
|
||||||
{
|
{
|
||||||
#ifdef DEBUG_TEXT_RUN_STORAGE_METRICS
|
#ifdef DEBUG_TEXT_RUN_STORAGE_METRICS
|
||||||
AccountStorageForTextRun(this, -1);
|
AccountStorageForTextRun(this, -1);
|
||||||
|
#endif
|
||||||
|
#ifdef DEBUG
|
||||||
|
// Make it easy to detect a dead text run
|
||||||
|
mFlags = 0xFFFFFFFF;
|
||||||
#endif
|
#endif
|
||||||
NS_RELEASE(mFontGroup);
|
NS_RELEASE(mFontGroup);
|
||||||
MOZ_COUNT_DTOR(gfxTextRun);
|
MOZ_COUNT_DTOR(gfxTextRun);
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html>
|
||||||
|
<body style="font-family:monospace; width:6ch;">
|
||||||
|
<b>ab</b> cd
|
||||||
|
<b>ab</b> cd
|
||||||
|
<b>ab</b> cd
|
||||||
|
<b>ab</b> cd
|
||||||
|
<b>ab</b> cd
|
||||||
|
<b>ab</b> cd
|
||||||
|
<b>ab</b> cd
|
||||||
|
<b>ab</b> cd<span id="s">ef</span>
|
||||||
|
<script>
|
||||||
|
document.body.clientWidth;
|
||||||
|
document.getElementById("s").style.fontSize = "200%";
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -615,6 +615,12 @@ public:
|
||||||
mCurrentRunContextInfo(nsTextFrameUtils::INCOMING_NONE) {
|
mCurrentRunContextInfo(nsTextFrameUtils::INCOMING_NONE) {
|
||||||
ResetRunInfo();
|
ResetRunInfo();
|
||||||
}
|
}
|
||||||
|
~BuildTextRunsScanner() {
|
||||||
|
NS_ASSERTION(mBreakSinks.IsEmpty(), "Should have been cleared");
|
||||||
|
NS_ASSERTION(mTextRunsToDelete.IsEmpty(), "Should have been cleared");
|
||||||
|
NS_ASSERTION(mLineBreakBeforeFrames.IsEmpty(), "Should have been cleared");
|
||||||
|
NS_ASSERTION(mMappedFlows.IsEmpty(), "Should have been cleared");
|
||||||
|
}
|
||||||
|
|
||||||
void SetAtStartOfLine() {
|
void SetAtStartOfLine() {
|
||||||
mStartOfLine = PR_TRUE;
|
mStartOfLine = PR_TRUE;
|
||||||
|
@ -641,6 +647,7 @@ public:
|
||||||
void ScanFrame(nsIFrame* aFrame);
|
void ScanFrame(nsIFrame* aFrame);
|
||||||
PRBool IsTextRunValidForMappedFlows(gfxTextRun* aTextRun);
|
PRBool IsTextRunValidForMappedFlows(gfxTextRun* aTextRun);
|
||||||
void FlushFrames(PRBool aFlushLineBreaks, PRBool aSuppressTrailingBreak);
|
void FlushFrames(PRBool aFlushLineBreaks, PRBool aSuppressTrailingBreak);
|
||||||
|
void FlushLineBreaks(gfxTextRun* aTrailingTextRun);
|
||||||
void ResetRunInfo() {
|
void ResetRunInfo() {
|
||||||
mLastFrame = nsnull;
|
mLastFrame = nsnull;
|
||||||
mMappedFlows.Clear();
|
mMappedFlows.Clear();
|
||||||
|
@ -648,10 +655,6 @@ public:
|
||||||
mMaxTextLength = 0;
|
mMaxTextLength = 0;
|
||||||
mDoubleByteText = PR_FALSE;
|
mDoubleByteText = PR_FALSE;
|
||||||
}
|
}
|
||||||
void ResetLineBreaker() {
|
|
||||||
PRBool trailingBreak;
|
|
||||||
mLineBreaker.Reset(&trailingBreak);
|
|
||||||
}
|
|
||||||
void AccumulateRunInfo(nsTextFrame* aFrame);
|
void AccumulateRunInfo(nsTextFrame* aFrame);
|
||||||
/**
|
/**
|
||||||
* @return null to indicate either textrun construction failed or
|
* @return null to indicate either textrun construction failed or
|
||||||
|
@ -727,6 +730,18 @@ public:
|
||||||
aCapitalize, mContext);
|
aCapitalize, mContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Finish() {
|
||||||
|
NS_ASSERTION(!(mTextRun->GetFlags() &
|
||||||
|
(gfxTextRunWordCache::TEXT_UNUSED_FLAGS |
|
||||||
|
nsTextFrameUtils::TEXT_UNUSED_FLAG)),
|
||||||
|
"Flag set that should never be set! (memory safety error?)");
|
||||||
|
if (mTextRun->GetFlags() & nsTextFrameUtils::TEXT_IS_TRANSFORMED) {
|
||||||
|
nsTransformedTextRun* transformedTextRun =
|
||||||
|
static_cast<nsTransformedTextRun*>(mTextRun);
|
||||||
|
transformedTextRun->FinishSettingProperties(mContext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
gfxTextRun* mTextRun;
|
gfxTextRun* mTextRun;
|
||||||
gfxContext* mContext;
|
gfxContext* mContext;
|
||||||
PRUint32 mOffsetIntoTextRun;
|
PRUint32 mOffsetIntoTextRun;
|
||||||
|
@ -738,6 +753,7 @@ private:
|
||||||
nsAutoTArray<MappedFlow,10> mMappedFlows;
|
nsAutoTArray<MappedFlow,10> mMappedFlows;
|
||||||
nsAutoTArray<nsTextFrame*,50> mLineBreakBeforeFrames;
|
nsAutoTArray<nsTextFrame*,50> mLineBreakBeforeFrames;
|
||||||
nsAutoTArray<nsAutoPtr<BreakSink>,10> mBreakSinks;
|
nsAutoTArray<nsAutoPtr<BreakSink>,10> mBreakSinks;
|
||||||
|
nsAutoTArray<gfxTextRun*,5> mTextRunsToDelete;
|
||||||
nsLineBreaker mLineBreaker;
|
nsLineBreaker mLineBreaker;
|
||||||
gfxTextRun* mCurrentFramesAllSameTextRun;
|
gfxTextRun* mCurrentFramesAllSameTextRun;
|
||||||
gfxContext* mContext;
|
gfxContext* mContext;
|
||||||
|
@ -1075,12 +1091,15 @@ BuildTextRuns(gfxContext* aContext, nsTextFrame* aForFrame,
|
||||||
if (seenStartLine) {
|
if (seenStartLine) {
|
||||||
++linesAfterStartLine;
|
++linesAfterStartLine;
|
||||||
if (linesAfterStartLine >= NUM_LINES_TO_BUILD_TEXT_RUNS && scanner.CanStopOnThisLine()) {
|
if (linesAfterStartLine >= NUM_LINES_TO_BUILD_TEXT_RUNS && scanner.CanStopOnThisLine()) {
|
||||||
// Don't flush; we may be in the middle of a textrun that we can't
|
// Don't flush frames; we may be in the middle of a textrun
|
||||||
// end here. That's OK, we just won't build it.
|
// that we can't end here. That's OK, we just won't build it.
|
||||||
// Note that we must already have finished the textrun for aForFrame,
|
// Note that we must already have finished the textrun for aForFrame,
|
||||||
// because we've seen the end of a textrun in a line after the line
|
// because we've seen the end of a textrun in a line after the line
|
||||||
// containing aForFrame.
|
// containing aForFrame.
|
||||||
scanner.ResetLineBreaker();
|
scanner.FlushLineBreaks(nsnull);
|
||||||
|
// This flushes out mMappedFlows and mLineBreakBeforeFrames, which
|
||||||
|
// silences assertions in the scanner destructor.
|
||||||
|
scanner.ResetRunInfo();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1132,56 +1151,72 @@ void BuildTextRunsScanner::FlushFrames(PRBool aFlushLineBreaks, PRBool aSuppress
|
||||||
if (mMappedFlows.Length() == 0)
|
if (mMappedFlows.Length() == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
gfxTextRun* textRun;
|
gfxTextRun* textRun = nsnull;
|
||||||
if (!mSkipIncompleteTextRuns && mCurrentFramesAllSameTextRun &&
|
if (!mMappedFlows.IsEmpty()) {
|
||||||
((mCurrentFramesAllSameTextRun->GetFlags() & nsTextFrameUtils::TEXT_INCOMING_WHITESPACE) != 0) ==
|
if (!mSkipIncompleteTextRuns && mCurrentFramesAllSameTextRun &&
|
||||||
((mCurrentRunContextInfo & nsTextFrameUtils::INCOMING_WHITESPACE) != 0) &&
|
((mCurrentFramesAllSameTextRun->GetFlags() & nsTextFrameUtils::TEXT_INCOMING_WHITESPACE) != 0) ==
|
||||||
((mCurrentFramesAllSameTextRun->GetFlags() & gfxTextRunWordCache::TEXT_INCOMING_ARABICCHAR) != 0) ==
|
((mCurrentRunContextInfo & nsTextFrameUtils::INCOMING_WHITESPACE) != 0) &&
|
||||||
((mCurrentRunContextInfo & nsTextFrameUtils::INCOMING_ARABICCHAR) != 0) &&
|
((mCurrentFramesAllSameTextRun->GetFlags() & gfxTextRunWordCache::TEXT_INCOMING_ARABICCHAR) != 0) ==
|
||||||
IsTextRunValidForMappedFlows(mCurrentFramesAllSameTextRun)) {
|
((mCurrentRunContextInfo & nsTextFrameUtils::INCOMING_ARABICCHAR) != 0) &&
|
||||||
// Optimization: We do not need to (re)build the textrun.
|
IsTextRunValidForMappedFlows(mCurrentFramesAllSameTextRun)) {
|
||||||
textRun = mCurrentFramesAllSameTextRun;
|
// Optimization: We do not need to (re)build the textrun.
|
||||||
|
textRun = mCurrentFramesAllSameTextRun;
|
||||||
|
|
||||||
// Feed this run's text into the linebreaker to provide context. This also
|
// Feed this run's text into the linebreaker to provide context. This also
|
||||||
// updates mNextRunContextInfo appropriately.
|
// updates mNextRunContextInfo appropriately.
|
||||||
SetupBreakSinksForTextRun(textRun, PR_TRUE, PR_FALSE);
|
SetupBreakSinksForTextRun(textRun, PR_TRUE, PR_FALSE);
|
||||||
mNextRunContextInfo = nsTextFrameUtils::INCOMING_NONE;
|
mNextRunContextInfo = nsTextFrameUtils::INCOMING_NONE;
|
||||||
if (textRun->GetFlags() & nsTextFrameUtils::TEXT_TRAILING_WHITESPACE) {
|
if (textRun->GetFlags() & nsTextFrameUtils::TEXT_TRAILING_WHITESPACE) {
|
||||||
mNextRunContextInfo |= nsTextFrameUtils::INCOMING_WHITESPACE;
|
mNextRunContextInfo |= nsTextFrameUtils::INCOMING_WHITESPACE;
|
||||||
|
}
|
||||||
|
if (textRun->GetFlags() & gfxTextRunWordCache::TEXT_TRAILING_ARABICCHAR) {
|
||||||
|
mNextRunContextInfo |= nsTextFrameUtils::INCOMING_ARABICCHAR;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
nsAutoTArray<PRUint8,BIG_TEXT_NODE_SIZE> buffer;
|
||||||
|
if (!buffer.AppendElements(mMaxTextLength*(mDoubleByteText ? 2 : 1)))
|
||||||
|
return;
|
||||||
|
textRun = BuildTextRunForFrames(buffer.Elements());
|
||||||
}
|
}
|
||||||
if (textRun->GetFlags() & gfxTextRunWordCache::TEXT_TRAILING_ARABICCHAR) {
|
|
||||||
mNextRunContextInfo |= nsTextFrameUtils::INCOMING_ARABICCHAR;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
nsAutoTArray<PRUint8,BIG_TEXT_NODE_SIZE> buffer;
|
|
||||||
if (!buffer.AppendElements(mMaxTextLength*(mDoubleByteText ? 2 : 1)))
|
|
||||||
return;
|
|
||||||
textRun = BuildTextRunForFrames(buffer.Elements());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aFlushLineBreaks) {
|
if (aFlushLineBreaks) {
|
||||||
PRBool trailingLineBreak;
|
FlushLineBreaks(aSuppressTrailingBreak ? nsnull : textRun);
|
||||||
nsresult rv = mLineBreaker.Reset(&trailingLineBreak);
|
|
||||||
// textRun may be null for various reasons, including because we constructed
|
|
||||||
// a partial textrun just to get the linebreaker and other state set up
|
|
||||||
// to build the next textrun.
|
|
||||||
if (NS_SUCCEEDED(rv) && trailingLineBreak && textRun && !aSuppressTrailingBreak) {
|
|
||||||
textRun->SetFlagBits(nsTextFrameUtils::TEXT_HAS_TRAILING_BREAK);
|
|
||||||
}
|
|
||||||
PRUint32 i;
|
|
||||||
for (i = 0; i < mBreakSinks.Length(); ++i) {
|
|
||||||
if (!mBreakSinks[i]->mExistingTextRun || mBreakSinks[i]->mChangedBreaks) {
|
|
||||||
// TODO cause frames associated with the textrun to be reflowed, if they
|
|
||||||
// aren't being reflowed already!
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mBreakSinks.Clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mCanStopOnThisLine = PR_TRUE;
|
mCanStopOnThisLine = PR_TRUE;
|
||||||
ResetRunInfo();
|
ResetRunInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BuildTextRunsScanner::FlushLineBreaks(gfxTextRun* aTrailingTextRun)
|
||||||
|
{
|
||||||
|
PRBool trailingLineBreak;
|
||||||
|
nsresult rv = mLineBreaker.Reset(&trailingLineBreak);
|
||||||
|
// textRun may be null for various reasons, including because we constructed
|
||||||
|
// a partial textrun just to get the linebreaker and other state set up
|
||||||
|
// to build the next textrun.
|
||||||
|
if (NS_SUCCEEDED(rv) && trailingLineBreak && aTrailingTextRun) {
|
||||||
|
aTrailingTextRun->SetFlagBits(nsTextFrameUtils::TEXT_HAS_TRAILING_BREAK);
|
||||||
|
}
|
||||||
|
|
||||||
|
PRUint32 i;
|
||||||
|
for (i = 0; i < mBreakSinks.Length(); ++i) {
|
||||||
|
if (!mBreakSinks[i]->mExistingTextRun || mBreakSinks[i]->mChangedBreaks) {
|
||||||
|
// TODO cause frames associated with the textrun to be reflowed, if they
|
||||||
|
// aren't being reflowed already!
|
||||||
|
}
|
||||||
|
mBreakSinks[i]->Finish();
|
||||||
|
}
|
||||||
|
mBreakSinks.Clear();
|
||||||
|
|
||||||
|
for (i = 0; i < mTextRunsToDelete.Length(); ++i) {
|
||||||
|
gfxTextRun* deleteTextRun = mTextRunsToDelete[i];
|
||||||
|
gTextRuns->RemoveFromCache(deleteTextRun);
|
||||||
|
delete deleteTextRun;
|
||||||
|
}
|
||||||
|
mTextRunsToDelete.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
void BuildTextRunsScanner::AccumulateRunInfo(nsTextFrame* aFrame)
|
void BuildTextRunsScanner::AccumulateRunInfo(nsTextFrame* aFrame)
|
||||||
{
|
{
|
||||||
NS_ASSERTION(mMaxTextLength <= mMaxTextLength + aFrame->GetContentLength(), "integer overflow");
|
NS_ASSERTION(mMaxTextLength <= mMaxTextLength + aFrame->GetContentLength(), "integer overflow");
|
||||||
|
@ -1493,15 +1528,18 @@ BuildTextRunsScanner::BuildTextRunForFrames(void* aTextBuffer)
|
||||||
TextRunMappedFlow dummyMappedFlow;
|
TextRunMappedFlow dummyMappedFlow;
|
||||||
|
|
||||||
TextRunUserData* userData;
|
TextRunUserData* userData;
|
||||||
|
TextRunUserData* userDataToDestroy;
|
||||||
// If the situation is particularly simple (and common) we don't need to
|
// If the situation is particularly simple (and common) we don't need to
|
||||||
// allocate userData.
|
// allocate userData.
|
||||||
if (mMappedFlows.Length() == 1 && !mMappedFlows[0].mEndFrame &&
|
if (mMappedFlows.Length() == 1 && !mMappedFlows[0].mEndFrame &&
|
||||||
mMappedFlows[0].mStartFrame->GetContentOffset() == 0) {
|
mMappedFlows[0].mStartFrame->GetContentOffset() == 0) {
|
||||||
userData = &dummyData;
|
userData = &dummyData;
|
||||||
|
userDataToDestroy = nsnull;
|
||||||
dummyData.mMappedFlows = &dummyMappedFlow;
|
dummyData.mMappedFlows = &dummyMappedFlow;
|
||||||
} else {
|
} else {
|
||||||
userData = static_cast<TextRunUserData*>
|
userData = static_cast<TextRunUserData*>
|
||||||
(nsMemory::Alloc(sizeof(TextRunUserData) + mMappedFlows.Length()*sizeof(TextRunMappedFlow)));
|
(nsMemory::Alloc(sizeof(TextRunUserData) + mMappedFlows.Length()*sizeof(TextRunMappedFlow)));
|
||||||
|
userDataToDestroy = userData;
|
||||||
userData->mMappedFlows = reinterpret_cast<TextRunMappedFlow*>(userData + 1);
|
userData->mMappedFlows = reinterpret_cast<TextRunMappedFlow*>(userData + 1);
|
||||||
}
|
}
|
||||||
userData->mMappedFlowCount = mMappedFlows.Length();
|
userData->mMappedFlowCount = mMappedFlows.Length();
|
||||||
|
@ -1578,7 +1616,7 @@ BuildTextRunsScanner::BuildTextRunForFrames(void* aTextBuffer)
|
||||||
// then expand.
|
// then expand.
|
||||||
nsAutoTArray<PRUint8,BIG_TEXT_NODE_SIZE> tempBuf;
|
nsAutoTArray<PRUint8,BIG_TEXT_NODE_SIZE> tempBuf;
|
||||||
if (!tempBuf.AppendElements(contentLength)) {
|
if (!tempBuf.AppendElements(contentLength)) {
|
||||||
DestroyUserData(userData);
|
DestroyUserData(userDataToDestroy);
|
||||||
return nsnull;
|
return nsnull;
|
||||||
}
|
}
|
||||||
PRUint8* bufStart = tempBuf.Elements();
|
PRUint8* bufStart = tempBuf.Elements();
|
||||||
|
@ -1606,7 +1644,7 @@ BuildTextRunsScanner::BuildTextRunForFrames(void* aTextBuffer)
|
||||||
|
|
||||||
// Check for out-of-memory in gfxSkipCharsBuilder
|
// Check for out-of-memory in gfxSkipCharsBuilder
|
||||||
if (!builder.IsOK()) {
|
if (!builder.IsOK()) {
|
||||||
DestroyUserData(userData);
|
DestroyUserData(userDataToDestroy);
|
||||||
return nsnull;
|
return nsnull;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1641,7 +1679,7 @@ BuildTextRunsScanner::BuildTextRunForFrames(void* aTextBuffer)
|
||||||
nsTextFrame* firstFrame = mMappedFlows[0].mStartFrame;
|
nsTextFrame* firstFrame = mMappedFlows[0].mStartFrame;
|
||||||
gfxFontGroup* fontGroup = GetFontGroupForFrame(firstFrame);
|
gfxFontGroup* fontGroup = GetFontGroupForFrame(firstFrame);
|
||||||
if (!fontGroup) {
|
if (!fontGroup) {
|
||||||
DestroyUserData(userData);
|
DestroyUserData(userDataToDestroy);
|
||||||
return nsnull;
|
return nsnull;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1751,7 +1789,7 @@ BuildTextRunsScanner::BuildTextRunForFrames(void* aTextBuffer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!textRun) {
|
if (!textRun) {
|
||||||
DestroyUserData(userData);
|
DestroyUserData(userDataToDestroy);
|
||||||
return nsnull;
|
return nsnull;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1764,11 +1802,16 @@ BuildTextRunsScanner::BuildTextRunForFrames(void* aTextBuffer)
|
||||||
if (mSkipIncompleteTextRuns) {
|
if (mSkipIncompleteTextRuns) {
|
||||||
mSkipIncompleteTextRuns = !TextContainsLineBreakerWhiteSpace(textPtr,
|
mSkipIncompleteTextRuns = !TextContainsLineBreakerWhiteSpace(textPtr,
|
||||||
transformedLength, mDoubleByteText);
|
transformedLength, mDoubleByteText);
|
||||||
|
// Arrange for this textrun to be deleted the next time the linebreaker
|
||||||
// Nuke the textrun
|
// is flushed out
|
||||||
gTextRuns->RemoveFromCache(textRun);
|
mTextRunsToDelete.AppendElement(textRun);
|
||||||
delete textRun;
|
// Since we're doing to destroy the user data now, avoid a dangling
|
||||||
DestroyUserData(userData);
|
// pointer. Strictly speaking we don't need to do this since it should
|
||||||
|
// not be used (since this textrun will not be used and will be
|
||||||
|
// itself deleted soon), but it's always better to not have dangling
|
||||||
|
// pointers around.
|
||||||
|
textRun->SetUserData(nsnull);
|
||||||
|
DestroyUserData(userDataToDestroy);
|
||||||
return nsnull;
|
return nsnull;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -66,6 +66,7 @@ public:
|
||||||
// the original text has at least one soft hyphen character
|
// the original text has at least one soft hyphen character
|
||||||
TEXT_HAS_SHY = 0x020000,
|
TEXT_HAS_SHY = 0x020000,
|
||||||
TEXT_WAS_TRANSFORMED = 0x040000,
|
TEXT_WAS_TRANSFORMED = 0x040000,
|
||||||
|
TEXT_UNUSED_FLAG = 0x080000,
|
||||||
|
|
||||||
// The following flags are set by nsTextFrame
|
// The following flags are set by nsTextFrame
|
||||||
|
|
||||||
|
|
|
@ -72,7 +72,7 @@ nsTransformedTextRun::SetCapitalization(PRUint32 aStart, PRUint32 aLength,
|
||||||
memset(mCapitalize.Elements(), 0, GetLength()*sizeof(PRPackedBool));
|
memset(mCapitalize.Elements(), 0, GetLength()*sizeof(PRPackedBool));
|
||||||
}
|
}
|
||||||
memcpy(mCapitalize.Elements() + aStart, aCapitalization, aLength*sizeof(PRPackedBool));
|
memcpy(mCapitalize.Elements() + aStart, aCapitalization, aLength*sizeof(PRPackedBool));
|
||||||
mFactory->RebuildTextRun(this, aRefContext);
|
mNeedsRebuild = PR_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
PRBool
|
PRBool
|
||||||
|
@ -82,76 +82,20 @@ nsTransformedTextRun::SetPotentialLineBreaks(PRUint32 aStart, PRUint32 aLength,
|
||||||
{
|
{
|
||||||
PRBool changed = gfxTextRun::SetPotentialLineBreaks(aStart, aLength,
|
PRBool changed = gfxTextRun::SetPotentialLineBreaks(aStart, aLength,
|
||||||
aBreakBefore, aRefContext);
|
aBreakBefore, aRefContext);
|
||||||
mFactory->RebuildTextRun(this, aRefContext);
|
if (changed) {
|
||||||
|
mNeedsRebuild = PR_TRUE;
|
||||||
|
}
|
||||||
return changed;
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
PRBool
|
|
||||||
nsTransformedTextRun::SetLineBreaks(PRUint32 aStart, PRUint32 aLength,
|
|
||||||
PRBool aLineBreakBefore, PRBool aLineBreakAfter,
|
|
||||||
gfxFloat* aAdvanceWidthDelta,
|
|
||||||
gfxContext* aRefContext)
|
|
||||||
{
|
|
||||||
nsTArray<PRUint32> newBreaks;
|
|
||||||
PRUint32 i;
|
|
||||||
PRBool changed = PR_FALSE;
|
|
||||||
for (i = 0; i < mLineBreaks.Length(); ++i) {
|
|
||||||
PRUint32 pos = mLineBreaks[i];
|
|
||||||
if (pos >= aStart)
|
|
||||||
break;
|
|
||||||
newBreaks.AppendElement(pos);
|
|
||||||
}
|
|
||||||
if (aLineBreakBefore != (i < mLineBreaks.Length() &&
|
|
||||||
mLineBreaks[i] == aStart)) {
|
|
||||||
changed = PR_TRUE;
|
|
||||||
}
|
|
||||||
if (aLineBreakBefore) {
|
|
||||||
nsTextFrameUtils::AppendLineBreakOffset(&newBreaks, aStart);
|
|
||||||
}
|
|
||||||
if (aLineBreakAfter != (i + 1 < mLineBreaks.Length() &&
|
|
||||||
mLineBreaks[i + 1] == aStart + aLength)) {
|
|
||||||
changed = PR_TRUE;
|
|
||||||
}
|
|
||||||
if (aLineBreakAfter) {
|
|
||||||
nsTextFrameUtils::AppendLineBreakOffset(&newBreaks, aStart + aLength);
|
|
||||||
}
|
|
||||||
for (; i < mLineBreaks.Length(); ++i) {
|
|
||||||
if (mLineBreaks[i] > aStart + aLength)
|
|
||||||
break;
|
|
||||||
changed = PR_TRUE;
|
|
||||||
}
|
|
||||||
if (!changed) {
|
|
||||||
if (aAdvanceWidthDelta) {
|
|
||||||
*aAdvanceWidthDelta = 0;
|
|
||||||
}
|
|
||||||
return PR_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
newBreaks.AppendElements(mLineBreaks.Elements() + i, mLineBreaks.Length() - i);
|
|
||||||
mLineBreaks.SwapElements(newBreaks);
|
|
||||||
|
|
||||||
gfxFloat currentAdvance = GetAdvanceWidth(aStart, aLength, nsnull);
|
|
||||||
mFactory->RebuildTextRun(this, aRefContext);
|
|
||||||
if (aAdvanceWidthDelta) {
|
|
||||||
*aAdvanceWidthDelta = GetAdvanceWidth(aStart, aLength, nsnull) - currentAdvance;
|
|
||||||
}
|
|
||||||
return PR_TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
gfxTextRun*
|
gfxTextRun*
|
||||||
nsTransformingTextRunFactory::MakeTextRun(const PRUnichar* aString, PRUint32 aLength,
|
nsTransformingTextRunFactory::MakeTextRun(const PRUnichar* aString, PRUint32 aLength,
|
||||||
const gfxTextRunFactory::Parameters* aParams,
|
const gfxTextRunFactory::Parameters* aParams,
|
||||||
gfxFontGroup* aFontGroup, PRUint32 aFlags,
|
gfxFontGroup* aFontGroup, PRUint32 aFlags,
|
||||||
nsStyleContext** aStyles, PRBool aOwnsFactory)
|
nsStyleContext** aStyles, PRBool aOwnsFactory)
|
||||||
{
|
{
|
||||||
nsTransformedTextRun* textRun =
|
return nsTransformedTextRun::Create(aParams, this, aFontGroup,
|
||||||
nsTransformedTextRun::Create(aParams, this, aFontGroup,
|
aString, aLength, aFlags, aStyles, aOwnsFactory);
|
||||||
aString, aLength, aFlags, aStyles, aOwnsFactory);
|
|
||||||
if (!textRun)
|
|
||||||
return nsnull;
|
|
||||||
|
|
||||||
RebuildTextRun(textRun, aParams->mContext);
|
|
||||||
return textRun;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gfxTextRun*
|
gfxTextRun*
|
||||||
|
@ -271,7 +215,7 @@ GetParametersForInner(nsTransformedTextRun* aTextRun, PRUint32* aFlags,
|
||||||
{
|
{
|
||||||
gfxTextRunFactory::Parameters params =
|
gfxTextRunFactory::Parameters params =
|
||||||
{ aRefContext, nsnull, nsnull,
|
{ aRefContext, nsnull, nsnull,
|
||||||
nsnull, nsnull, aTextRun->GetAppUnitsPerDevUnit()
|
nsnull, 0, aTextRun->GetAppUnitsPerDevUnit()
|
||||||
};
|
};
|
||||||
*aFlags = aTextRun->GetFlags() & ~gfxFontGroup::TEXT_IS_PERSISTENT;
|
*aFlags = aTextRun->GetFlags() & ~gfxFontGroup::TEXT_IS_PERSISTENT;
|
||||||
return params;
|
return params;
|
||||||
|
@ -313,17 +257,9 @@ nsFontVariantTextRunFactory::RebuildTextRun(nsTransformedTextRun* aTextRun,
|
||||||
PRBool runIsLowercase = PR_FALSE;
|
PRBool runIsLowercase = PR_FALSE;
|
||||||
nsAutoTArray<nsStyleContext*,50> styleArray;
|
nsAutoTArray<nsStyleContext*,50> styleArray;
|
||||||
nsAutoTArray<PRPackedBool,50> canBreakBeforeArray;
|
nsAutoTArray<PRPackedBool,50> canBreakBeforeArray;
|
||||||
nsAutoTArray<PRUint32,10> lineBreakBeforeArray;
|
|
||||||
|
|
||||||
PRUint32 nextLineBreak = 0;
|
|
||||||
PRUint32 i;
|
PRUint32 i;
|
||||||
for (i = 0; i <= length; ++i) {
|
for (i = 0; i <= length; ++i) {
|
||||||
if (nextLineBreak < aTextRun->mLineBreaks.Length() &&
|
|
||||||
aTextRun->mLineBreaks[nextLineBreak] == i) {
|
|
||||||
lineBreakBeforeArray.AppendElement(i - runStart);
|
|
||||||
++nextLineBreak;
|
|
||||||
}
|
|
||||||
|
|
||||||
PRBool isLowercase = PR_FALSE;
|
PRBool isLowercase = PR_FALSE;
|
||||||
if (i < length) {
|
if (i < length) {
|
||||||
// Characters that aren't the start of a cluster are ignored here. They
|
// Characters that aren't the start of a cluster are ignored here. They
|
||||||
|
@ -346,9 +282,7 @@ nsFontVariantTextRunFactory::RebuildTextRun(nsTransformedTextRun* aTextRun,
|
||||||
nsAutoPtr<gfxTextRun> transformedChild;
|
nsAutoPtr<gfxTextRun> transformedChild;
|
||||||
gfxTextRunCache::AutoTextRun cachedChild;
|
gfxTextRunCache::AutoTextRun cachedChild;
|
||||||
gfxTextRun* child;
|
gfxTextRun* child;
|
||||||
// Setup actual line break data for child (which may affect shaping)
|
|
||||||
innerParams.mInitialBreaks = lineBreakBeforeArray.Elements();
|
|
||||||
innerParams.mInitialBreakCount = lineBreakBeforeArray.Length();
|
|
||||||
if (runIsLowercase) {
|
if (runIsLowercase) {
|
||||||
transformedChild = uppercaseFactory.MakeTextRun(str + runStart, i - runStart,
|
transformedChild = uppercaseFactory.MakeTextRun(str + runStart, i - runStart,
|
||||||
&innerParams, smallFont, flags, styleArray.Elements(), PR_FALSE);
|
&innerParams, smallFont, flags, styleArray.Elements(), PR_FALSE);
|
||||||
|
@ -372,10 +306,6 @@ nsFontVariantTextRunFactory::RebuildTextRun(nsTransformedTextRun* aTextRun,
|
||||||
runStart = i;
|
runStart = i;
|
||||||
styleArray.Clear();
|
styleArray.Clear();
|
||||||
canBreakBeforeArray.Clear();
|
canBreakBeforeArray.Clear();
|
||||||
lineBreakBeforeArray.Clear();
|
|
||||||
if (nextLineBreak > 0 && aTextRun->mLineBreaks[nextLineBreak - 1] == i) {
|
|
||||||
lineBreakBeforeArray.AppendElement(0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i < length) {
|
if (i < length) {
|
||||||
|
@ -384,8 +314,6 @@ nsFontVariantTextRunFactory::RebuildTextRun(nsTransformedTextRun* aTextRun,
|
||||||
canBreakBeforeArray.AppendElement(aTextRun->CanBreakLineBefore(i));
|
canBreakBeforeArray.AppendElement(aTextRun->CanBreakLineBefore(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
NS_ASSERTION(nextLineBreak == aTextRun->mLineBreaks.Length(),
|
|
||||||
"lost track of line breaks somehow");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -404,8 +332,6 @@ nsCaseTransformTextRunFactory::RebuildTextRun(nsTransformedTextRun* aTextRun,
|
||||||
nsAutoTArray<PRPackedBool,50> charsToMergeArray;
|
nsAutoTArray<PRPackedBool,50> charsToMergeArray;
|
||||||
nsAutoTArray<nsStyleContext*,50> styleArray;
|
nsAutoTArray<nsStyleContext*,50> styleArray;
|
||||||
nsAutoTArray<PRPackedBool,50> canBreakBeforeArray;
|
nsAutoTArray<PRPackedBool,50> canBreakBeforeArray;
|
||||||
nsAutoTArray<PRUint32,10> lineBreakBeforeArray;
|
|
||||||
PRUint32 nextLineBreak = 0;
|
|
||||||
PRUint32 extraCharsCount = 0;
|
PRUint32 extraCharsCount = 0;
|
||||||
|
|
||||||
PRUint32 i;
|
PRUint32 i;
|
||||||
|
@ -415,11 +341,6 @@ nsCaseTransformTextRunFactory::RebuildTextRun(nsTransformedTextRun* aTextRun,
|
||||||
charsToMergeArray.AppendElement(PR_FALSE);
|
charsToMergeArray.AppendElement(PR_FALSE);
|
||||||
styleArray.AppendElement(styles[i]);
|
styleArray.AppendElement(styles[i]);
|
||||||
canBreakBeforeArray.AppendElement(aTextRun->CanBreakLineBefore(i));
|
canBreakBeforeArray.AppendElement(aTextRun->CanBreakLineBefore(i));
|
||||||
if (nextLineBreak < aTextRun->mLineBreaks.Length() &&
|
|
||||||
aTextRun->mLineBreaks[nextLineBreak] == i) {
|
|
||||||
lineBreakBeforeArray.AppendElement(i + extraCharsCount);
|
|
||||||
++nextLineBreak;
|
|
||||||
}
|
|
||||||
|
|
||||||
PRUint8 style = mAllUppercase ? NS_STYLE_TEXT_TRANSFORM_UPPERCASE
|
PRUint8 style = mAllUppercase ? NS_STYLE_TEXT_TRANSFORM_UPPERCASE
|
||||||
: styles[i]->GetStyleText()->mTextTransform;
|
: styles[i]->GetStyleText()->mTextTransform;
|
||||||
|
@ -461,13 +382,6 @@ nsCaseTransformTextRunFactory::RebuildTextRun(nsTransformedTextRun* aTextRun,
|
||||||
canBreakBeforeArray.AppendElement(PR_FALSE);
|
canBreakBeforeArray.AppendElement(PR_FALSE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (nextLineBreak < aTextRun->mLineBreaks.Length() &&
|
|
||||||
aTextRun->mLineBreaks[nextLineBreak] == length) {
|
|
||||||
lineBreakBeforeArray.AppendElement(length + extraCharsCount);
|
|
||||||
++nextLineBreak;
|
|
||||||
}
|
|
||||||
NS_ASSERTION(nextLineBreak == aTextRun->mLineBreaks.Length(),
|
|
||||||
"lost track of line breaks somehow");
|
|
||||||
|
|
||||||
PRUint32 flags;
|
PRUint32 flags;
|
||||||
gfxTextRunFactory::Parameters innerParams =
|
gfxTextRunFactory::Parameters innerParams =
|
||||||
|
@ -477,9 +391,7 @@ nsCaseTransformTextRunFactory::RebuildTextRun(nsTransformedTextRun* aTextRun,
|
||||||
nsAutoPtr<gfxTextRun> transformedChild;
|
nsAutoPtr<gfxTextRun> transformedChild;
|
||||||
gfxTextRunCache::AutoTextRun cachedChild;
|
gfxTextRunCache::AutoTextRun cachedChild;
|
||||||
gfxTextRun* child;
|
gfxTextRun* child;
|
||||||
// Setup actual line break data for child (which may affect shaping)
|
|
||||||
innerParams.mInitialBreaks = lineBreakBeforeArray.Elements();
|
|
||||||
innerParams.mInitialBreakCount = lineBreakBeforeArray.Length();
|
|
||||||
if (mInnerTransformingTextRunFactory) {
|
if (mInnerTransformingTextRunFactory) {
|
||||||
transformedChild = mInnerTransformingTextRunFactory->MakeTextRun(
|
transformedChild = mInnerTransformingTextRunFactory->MakeTextRun(
|
||||||
convertedString.BeginReading(), convertedString.Length(),
|
convertedString.BeginReading(), convertedString.Length(),
|
||||||
|
|
|
@ -113,22 +113,30 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void SetCapitalization(PRUint32 aStart, PRUint32 aLength,
|
void SetCapitalization(PRUint32 aStart, PRUint32 aLength,
|
||||||
PRPackedBool* aCapitalization,
|
PRPackedBool* aCapitalization,
|
||||||
gfxContext* aRefContext);
|
gfxContext* aRefContext);
|
||||||
virtual PRBool SetPotentialLineBreaks(PRUint32 aStart, PRUint32 aLength,
|
virtual PRBool SetPotentialLineBreaks(PRUint32 aStart, PRUint32 aLength,
|
||||||
PRPackedBool* aBreakBefore,
|
PRPackedBool* aBreakBefore,
|
||||||
gfxContext* aRefContext);
|
gfxContext* aRefContext);
|
||||||
virtual PRBool SetLineBreaks(PRUint32 aStart, PRUint32 aLength,
|
/**
|
||||||
PRBool aLineBreakBefore, PRBool aLineBreakAfter,
|
* Called after SetCapitalization and SetPotentialLineBreaks
|
||||||
gfxFloat* aAdvanceWidthDelta,
|
* are done and before we request any data from the textrun. Also always
|
||||||
gfxContext* aRefContext);
|
* called after a Create.
|
||||||
|
*/
|
||||||
|
void FinishSettingProperties(gfxContext* aRefContext)
|
||||||
|
{
|
||||||
|
if (mNeedsRebuild) {
|
||||||
|
mNeedsRebuild = PR_FALSE;
|
||||||
|
mFactory->RebuildTextRun(this, aRefContext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
nsTransformingTextRunFactory *mFactory;
|
nsTransformingTextRunFactory *mFactory;
|
||||||
nsTArray<PRUint32> mLineBreaks;
|
|
||||||
nsTArray<nsRefPtr<nsStyleContext> > mStyles;
|
nsTArray<nsRefPtr<nsStyleContext> > mStyles;
|
||||||
nsTArray<PRPackedBool> mCapitalize;
|
nsTArray<PRPackedBool> mCapitalize;
|
||||||
PRPackedBool mOwnsFactory;
|
PRPackedBool mOwnsFactory;
|
||||||
|
PRPackedBool mNeedsRebuild;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
nsTransformedTextRun(const gfxTextRunFactory::Parameters* aParams,
|
nsTransformedTextRun(const gfxTextRunFactory::Parameters* aParams,
|
||||||
|
@ -138,15 +146,12 @@ private:
|
||||||
const PRUint32 aFlags, nsStyleContext** aStyles,
|
const PRUint32 aFlags, nsStyleContext** aStyles,
|
||||||
PRBool aOwnsFactory)
|
PRBool aOwnsFactory)
|
||||||
: gfxTextRun(aParams, aString, aLength, aFontGroup, aFlags, sizeof(nsTransformedTextRun)),
|
: gfxTextRun(aParams, aString, aLength, aFontGroup, aFlags, sizeof(nsTransformedTextRun)),
|
||||||
mFactory(aFactory), mOwnsFactory(aOwnsFactory)
|
mFactory(aFactory), mOwnsFactory(aOwnsFactory), mNeedsRebuild(PR_TRUE)
|
||||||
{
|
{
|
||||||
PRUint32 i;
|
PRUint32 i;
|
||||||
for (i = 0; i < aLength; ++i) {
|
for (i = 0; i < aLength; ++i) {
|
||||||
mStyles.AppendElement(aStyles[i]);
|
mStyles.AppendElement(aStyles[i]);
|
||||||
}
|
}
|
||||||
for (i = 0; i < aParams->mInitialBreakCount; ++i) {
|
|
||||||
mLineBreaks.AppendElement(aParams->mInitialBreaks[i]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче