Not part of the build. Update new text frame for textrun API changes. Also implements a textrun cache for the new text frame

This commit is contained in:
roc+@cs.cmu.edu 2007-05-09 15:04:56 -07:00
Родитель 5cdf43a09e
Коммит cc1cbf7323
5 изменённых файлов: 319 добавлений и 289 удалений

Просмотреть файл

@ -82,6 +82,8 @@
#include "nsTextFrameUtils.h"
#include "nsTextRunTransformations.h"
#include "nsFrameManager.h"
#include "nsTextFrameTextRunCache.h"
#include "nsExpirationTracker.h"
#include "nsTextFragment.h"
#include "nsGkAtoms.h"
@ -556,6 +558,157 @@ protected:
void SetOffsets(PRInt32 start, PRInt32 end);
};
static void
DestroyUserData(void* aUserData)
{
TextRunUserData* userData = NS_STATIC_CAST(TextRunUserData*, aUserData);
if (userData) {
nsMemory::Free(userData);
}
}
static void
ClearAllTextRunReferences(nsTextFrame* aFrame, gfxTextRun* aTextRun)
{
aFrame->RemoveStateBits(TEXT_IS_RUN_OWNER);
while (aFrame) {
if (aFrame->GetTextRun() != aTextRun)
break;
aFrame->SetTextRun(nsnull);
aFrame = NS_STATIC_CAST(nsTextFrame*, aFrame->GetNextContinuation());
}
}
static void
UnhookTextRunFromFrames(gfxTextRun* aTextRun)
{
if (!aTextRun->GetUserData())
return;
// Kill all references to the textrun. It could be referenced by any of its
// owners, and all their in-flows.
if (aTextRun->GetFlags() & nsTextFrameUtils::TEXT_IS_SIMPLE_FLOW) {
nsIFrame* firstInFlow = NS_STATIC_CAST(nsIFrame*, aTextRun->GetUserData());
ClearAllTextRunReferences(NS_STATIC_CAST(nsTextFrame*, firstInFlow), aTextRun);
} else {
TextRunUserData* userData =
NS_STATIC_CAST(TextRunUserData*, aTextRun->GetUserData());
PRInt32 i;
for (i = 0; i < userData->mMappedFlowCount; ++i) {
ClearAllTextRunReferences(userData->mMappedFlows[i].mStartFrame, aTextRun);
}
DestroyUserData(userData);
}
aTextRun->SetUserData(nsnull);
}
class FrameTextRunCache;
static FrameTextRunCache *gTextRuns = nsnull;
/*
* Cache textruns and expire them after 3*10 seconds of no use.
* Our textruns are either:
* -- not tracked and not in the cache
* -- tracked but not in the cache and nsTextFrameUtils::TEXT_IS_UNCACHED is set
* -- tracked, in the cache, and nsTextFrameUtils::TEXT_IS_UNCACHED is not set
*/
class FrameTextRunCache : public nsExpirationTracker<gfxTextRun,3> {
public:
enum { TIMEOUT_SECONDS = 10 };
FrameTextRunCache()
: nsExpirationTracker<gfxTextRun,3>(TIMEOUT_SECONDS*1000) {}
~FrameTextRunCache() {
AgeAllGenerations();
}
void RemoveFromCache(gfxTextRun* aTextRun) {
RemoveObject(aTextRun);
if (!(aTextRun->GetFlags() & nsTextFrameUtils::TEXT_IS_UNCACHED)) {
mCache.RemoveTextRun(aTextRun);
}
}
// This gets called when the timeout has expired on a gfxTextRun
virtual void NotifyExpired(gfxTextRun* aTextRun) {
UnhookTextRunFromFrames(aTextRun);
RemoveFromCache(aTextRun);
delete aTextRun;
}
class InnerCache : public gfxTextRunCache {
public:
// If a textrun is removed from the cache, and has no associated frame(s),
// then we may as well destroy it now. We should stop tracking it
// in any case; even if it has an associated frame, there is no point
// in keeping it around after it's dropped from that frame.
virtual void NotifyRemovedFromCache(gfxTextRun* aTextRun) {
if (aTextRun->GetExpirationState()->IsTracked()) {
gTextRuns->RemoveObject(aTextRun);
}
if (aTextRun->GetUserData())
return;
delete aTextRun;
}
};
InnerCache mCache;
};
static gfxTextRun *
MakeTextRun(const PRUnichar *aText, PRUint32 aLength,
gfxFontGroup *aFontGroup, const gfxFontGroup::Parameters* aParams,
PRUint32 aFlags)
{
nsAutoPtr<gfxTextRun> textRun;
if (aLength == 0) {
textRun = aFontGroup->MakeEmptyTextRun(aParams, aFlags | nsTextFrameUtils::TEXT_IS_UNCACHED);
} else if (aLength == 1 && aText[0] == ' ') {
textRun = aFontGroup->MakeSpaceTextRun(aParams, aFlags | nsTextFrameUtils::TEXT_IS_UNCACHED);
} else {
textRun = gTextRuns->mCache.GetOrMakeTextRun(aText, aLength, aFontGroup, aParams, aFlags);
}
if (!textRun)
return nsnull;
nsresult rv = gTextRuns->AddObject(textRun);
if (NS_FAILED(rv))
return nsnull;
return textRun.forget();
}
static gfxTextRun *
MakeTextRun(const PRUint8 *aText, PRUint32 aLength,
gfxFontGroup *aFontGroup, const gfxFontGroup::Parameters* aParams,
PRUint32 aFlags)
{
nsAutoPtr<gfxTextRun> textRun;
if (aLength == 0) {
textRun = aFontGroup->MakeEmptyTextRun(aParams, aFlags | nsTextFrameUtils::TEXT_IS_UNCACHED);
} else if (aLength == 1 && aText[0] == ' ') {
textRun = aFontGroup->MakeSpaceTextRun(aParams, aFlags | nsTextFrameUtils::TEXT_IS_UNCACHED);
} else {
textRun = gTextRuns->mCache.GetOrMakeTextRun(aText, aLength, aFontGroup, aParams, aFlags);
}
if (!textRun)
return nsnull;
nsresult rv = gTextRuns->AddObject(textRun);
if (NS_FAILED(rv))
return nsnull;
return textRun.forget();
}
nsresult
nsTextFrameTextRunCache::Init() {
gTextRuns = new FrameTextRunCache();
return gTextRuns ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
}
void
nsTextFrameTextRunCache::Shutdown() {
delete gTextRuns;
gTextRuns = nsnull;
}
PRInt32 nsTextFrame::GetInFlowContentLength() {
#ifdef IBMBIDI
nsTextFrame* nextBidi = nsnull;
@ -692,8 +845,7 @@ public:
void BuildTextRunForFrames(void* aTextBuffer);
void AssignTextRun(gfxTextRun* aTextRun);
nsTextFrame* GetNextBreakBeforeFrame(PRUint32* aIndex);
void SetupBreakSinksForTextRun(gfxTextRun* aTextRun, const void* aText, PRUint32 aLength,
PRBool aIs2b, PRBool aIsExistingTextRun);
void SetupBreakSinksForTextRun(gfxTextRun* aTextRun, PRBool aIsExistingTextRun);
PRBool StylesMatchForTextRun(nsIFrame* aFrame1, nsIFrame* aFrame2);
@ -851,103 +1003,6 @@ ExpandBuffer(PRUnichar* aDest, PRUint8* aSrc, PRUint32 aCount)
return aDest;
}
static void*
TransformTextToBuffer(nsTextFrame* aFrame, PRInt32 aContentLength,
void* aBuffer, PRInt32 aCharSize, gfxSkipCharsBuilder* aBuilder,
PRPackedBool* aIncomingWhitespace)
{
const nsTextFragment* frag = aFrame->GetContent()->GetText();
PRInt32 contentStart = aFrame->GetContentOffset();
PRBool compressWhitespace = !aFrame->GetStyleText()->WhiteSpaceIsSignificant();
PRUint32 analysisFlags;
if (frag->Is2b()) {
NS_ASSERTION(aCharSize == 2, "Wrong size buffer!");
return nsTextFrameUtils::TransformText(
frag->Get2b() + contentStart, aContentLength, NS_STATIC_CAST(PRUnichar*, aBuffer),
compressWhitespace, aIncomingWhitespace, aBuilder, &analysisFlags);
} else {
if (aCharSize == 2) {
// Need to expand the text. First transform it into a temporary buffer,
// then expand.
nsAutoTArray<PRUint8,BIG_TEXT_NODE_SIZE> tempBuf;
if (!tempBuf.AppendElements(aContentLength))
return nsnull;
PRUint8* end = nsTextFrameUtils::TransformText(
NS_REINTERPRET_CAST(const PRUint8*, frag->Get1b()) + contentStart, aContentLength,
tempBuf.Elements(), compressWhitespace, aIncomingWhitespace, aBuilder, &analysisFlags);
return ExpandBuffer(NS_STATIC_CAST(PRUnichar*, aBuffer),
tempBuf.Elements(), end - tempBuf.Elements());
} else {
return nsTextFrameUtils::TransformText(
NS_REINTERPRET_CAST(const PRUint8*, frag->Get1b()) + contentStart, aContentLength,
NS_STATIC_CAST(PRUint8*, aBuffer),
compressWhitespace, aIncomingWhitespace, aBuilder, &analysisFlags);
}
}
}
static void
ReconstructTextForRun(gfxTextRun* aTextRun, PRBool aRememberText,
BuildTextRunsScanner* aSetupBreaks,
PRPackedBool* aIncomingWhitespace)
{
gfxSkipCharsBuilder builder;
nsAutoTArray<PRUint8,BIG_TEXT_NODE_SIZE> buffer;
PRUint32 charSize = (aTextRun->GetFlags() & gfxTextRunFactory::TEXT_IS_8BIT) ? 1 : 2;
PRInt32 length;
void* bufEnd;
nsTextFrame* f;
if (aTextRun->GetFlags() & nsTextFrameUtils::TEXT_IS_SIMPLE_FLOW) {
f = NS_STATIC_CAST(nsTextFrame*, aTextRun->GetUserData());
length = f->GetContentLength();
if (!buffer.AppendElements(length*charSize))
return;
bufEnd = TransformTextToBuffer(f, length, buffer.Elements(), charSize, &builder,
aIncomingWhitespace);
if (!bufEnd)
return;
} else {
TextRunUserData* userData = NS_STATIC_CAST(TextRunUserData*, aTextRun->GetUserData());
length = 0;
PRInt32 i;
for (i = 0; i < userData->mMappedFlowCount; ++i) {
TextRunMappedFlow* flow = &userData->mMappedFlows[i];
length += flow->mContentLength;
}
if (!buffer.AppendElements(length*charSize))
return;
bufEnd = buffer.Elements();
for (i = 0; i < userData->mMappedFlowCount; ++i) {
TextRunMappedFlow* flow = &userData->mMappedFlows[i];
bufEnd = TransformTextToBuffer(flow->mStartFrame, flow->mContentLength, bufEnd,
charSize, &builder, aIncomingWhitespace);
if (!bufEnd)
return;
}
f = userData->mMappedFlows[0].mStartFrame;
}
PRUint32 transformedLength = NS_STATIC_CAST(PRUint8*, bufEnd) - buffer.Elements();
if (charSize == 2) {
transformedLength >>= 1;
}
if (aRememberText) {
if (charSize == 2) {
aTextRun->RememberText(NS_REINTERPRET_CAST(PRUnichar*, buffer.Elements()), transformedLength);
} else {
aTextRun->RememberText(buffer.Elements(), transformedLength);
}
}
if (aSetupBreaks) {
aSetupBreaks->SetupBreakSinksForTextRun(aTextRun, buffer.Elements(), transformedLength,
charSize == 2, PR_TRUE);
}
}
/**
* This gets called when we need to make a text run for the current list of
* frames.
@ -967,8 +1022,9 @@ void BuildTextRunsScanner::FlushFrames(PRBool aFlushLineBreaks)
// Feed this run's text into the linebreaker to provide context. This also
// updates mTrimNextRunLeadingWhitespace appropriately.
ReconstructTextForRun(mCurrentFramesAllSameTextRun, PR_FALSE, this,
&mTrimNextRunLeadingWhitespace);
SetupBreakSinksForTextRun(mCurrentFramesAllSameTextRun, PR_TRUE);
mTrimNextRunLeadingWhitespace =
(mCurrentFramesAllSameTextRun->GetFlags() & nsTextFrameUtils::TEXT_TRAILING_WHITESPACE) != 0;
} else {
nsAutoTArray<PRUint8,BIG_TEXT_NODE_SIZE> buffer;
if (!buffer.AppendElements(mMaxTextLength*(mDoubleByteText ? 2 : 1)))
@ -1115,15 +1171,6 @@ static nscoord StyleToCoord(const nsStyleCoord& aCoord)
}
}
static void
DestroyUserData(void* aUserData)
{
TextRunUserData* userData = NS_STATIC_CAST(TextRunUserData*, aUserData);
if (userData) {
nsMemory::Free(userData);
}
}
nsTextFrame*
BuildTextRunsScanner::GetNextBreakBeforeFrame(PRUint32* aIndex)
{
@ -1164,12 +1211,24 @@ GetFontGroupForFrame(nsIFrame* aFrame)
}
static gfxTextRun*
GetSpecialString(gfxFontGroup* aFontGroup, gfxFontGroup::SpecialString aSpecial,
gfxTextRun* aTextRun)
GetHyphenTextRun(gfxTextRun* aTextRun, nsIRenderingContext* aRefContext)
{
if (!aFontGroup)
return nsnull;
return aFontGroup->GetSpecialStringTextRun(aSpecial, aTextRun);
gfxContext* ctx = NS_STATIC_CAST(gfxContext*,
aRefContext->GetNativeGraphicData(nsIRenderingContext::NATIVE_THEBES_CONTEXT));
gfxFontGroup* fontGroup = aTextRun->GetFontGroup();
PRUint32 flags = gfxFontGroup::TEXT_IS_PERSISTENT;
static const PRUnichar unicodeHyphen = 0x2010;
gfxTextRun* textRun =
gfxGlobalTextRunCache::GetTextRun(&unicodeHyphen, 1, fontGroup, ctx,
aTextRun->GetAppUnitsPerDevUnit(), flags);
if (textRun && textRun->CountMissingGlyphs() == 0)
return textRun;
static const PRUint8 dash = '-';
return gfxGlobalTextRunCache::GetTextRun(&dash, 1, fontGroup, ctx,
aTextRun->GetAppUnitsPerDevUnit(),
flags);
}
static gfxFont::Metrics
@ -1193,7 +1252,6 @@ BuildTextRunsScanner::BuildTextRunForFrames(void* aTextBuffer)
PRBool anyTextTransformStyle = PR_FALSE;
nsIContent* lastContent = nsnull;
PRInt32 endOfLastContent = 0;
PRBool anyMixedStyleFlows = PR_FALSE;
PRUint32 textFlags = gfxTextRunFactory::TEXT_NEED_BOUNDING_BOX;
if (mCurrentRunTrimLeadingWhitespace) {
@ -1265,7 +1323,6 @@ BuildTextRunsScanner::BuildTextRunForFrames(void* aTextBuffer)
contentStart = PR_MAX(contentStart, endOfLastContent);
if (contentStart >= contentEnd)
continue;
anyMixedStyleFlows = PR_TRUE;
userData->mMappedFlows[finalMappedFlowCount - 1].mContentLength += contentLength;
} else {
TextRunMappedFlow* newFlow = &userData->mMappedFlows[finalMappedFlowCount];
@ -1371,11 +1428,11 @@ BuildTextRunsScanner::BuildTextRunForFrames(void* aTextBuffer)
// Setup factory chain
nsAutoPtr<nsTransformingTextRunFactory> transformingFactory;
if (anySmallcapsStyle) {
transformingFactory = new nsFontVariantTextRunFactory(fontGroup);
transformingFactory = new nsFontVariantTextRunFactory();
}
if (anyTextTransformStyle) {
transformingFactory =
new nsCaseTransformTextRunFactory(fontGroup, transformingFactory.forget());
new nsCaseTransformTextRunFactory(transformingFactory.forget());
}
nsTArray<nsStyleContext*> styles;
if (transformingFactory) {
@ -1397,12 +1454,12 @@ BuildTextRunsScanner::BuildTextRunForFrames(void* aTextBuffer)
if (textFlags & nsTextFrameUtils::TEXT_HAS_SHY) {
textFlags |= gfxTextRunFactory::TEXT_ENABLE_HYPHEN_BREAKS;
}
if (!(textFlags & nsTextFrameUtils::TEXT_HAS_NON_ASCII)) {
textFlags |= gfxTextRunFactory::TEXT_IS_ASCII;
}
if (mBidiEnabled && (NS_GET_EMBEDDING_LEVEL(firstFrame) & 1)) {
textFlags |= gfxTextRunFactory::TEXT_IS_RTL;
}
if (mTrimNextRunLeadingWhitespace) {
textFlags |= nsTextFrameUtils::TEXT_TRAILING_WHITESPACE;
}
gfxSkipChars skipChars;
skipChars.TakeFrom(&builder);
@ -1420,59 +1477,48 @@ BuildTextRunsScanner::BuildTextRunForFrames(void* aTextBuffer)
}
gfxTextRunFactory::Parameters params =
{ mContext, finalUserData, firstFrame->GetStyleVisibility()->mLangGroup, &skipChars,
{ mContext, finalUserData, &skipChars,
textBreakPoints.Elements(), nextBreakIndex,
firstFrame->PresContext()->AppUnitsPerDevPixel(), textFlags };
firstFrame->PresContext()->AppUnitsPerDevPixel() };
gfxTextRun* textRun;
if (mDoubleByteText) {
if (textFlags & gfxTextRunFactory::TEXT_IS_ASCII) {
NS_WARNING("Hmm ... why are we taking the Unicode path when the text is all ASCII?");
}
const PRUnichar* text = NS_STATIC_CAST(const PRUnichar*, textPtr);
if (transformingFactory) {
textRun = transformingFactory->MakeTextRun(text, transformedLength, &params,
styles.Elements());
fontGroup, textFlags, styles.Elements());
if (textRun) {
transformingFactory.forget();
}
} else {
textRun = fontGroup->MakeTextRun(text, transformedLength, &params);
textRun = MakeTextRun(text, transformedLength, fontGroup, &params, textFlags);
}
if (!textRun) {
DestroyUserData(userData);
return;
}
if (anyMixedStyleFlows) {
// Make sure we're not asked to recover the text, it's too hard to do later.
textRun->RememberText(text, transformedLength);
}
} else {
const PRUint8* text = NS_STATIC_CAST(const PRUint8*, textPtr);
textFlags |= gfxFontGroup::TEXT_IS_8BIT;
if (transformingFactory) {
textRun = transformingFactory->MakeTextRun(text, transformedLength, &params,
styles.Elements());
fontGroup, textFlags, styles.Elements());
if (textRun) {
transformingFactory.forget();
}
} else {
textRun = fontGroup->MakeTextRun(text, transformedLength, &params);
textRun = MakeTextRun(text, transformedLength, fontGroup, &params, textFlags);
}
if (!textRun) {
DestroyUserData(userData);
return;
}
if (anyMixedStyleFlows) {
// Make sure we're not asked to recover the text, it's too hard to do later.
textRun->RememberText(text, transformedLength);
}
}
// We have to set these up after we've created the textrun, because
// the breaks may be stored in the textrun during this very call.
// This is a bit annoying because it requires another loop over the frames
// making up the textrun, but I don't see a way to avoid this.
SetupBreakSinksForTextRun(textRun, textPtr, transformedLength, mDoubleByteText,
PR_FALSE);
SetupBreakSinksForTextRun(textRun, PR_FALSE);
// Actually wipe out the textruns associated with the mapped frames and associate
// those frames with this text run.
@ -1480,8 +1526,8 @@ BuildTextRunsScanner::BuildTextRunForFrames(void* aTextBuffer)
}
void
BuildTextRunsScanner::SetupBreakSinksForTextRun(gfxTextRun* aTextRun, const void* aText, PRUint32 aLength,
PRBool aIs2b, PRBool aIsExistingTextRun)
BuildTextRunsScanner::SetupBreakSinksForTextRun(gfxTextRun* aTextRun,
PRBool aIsExistingTextRun)
{
// textruns have uniform language
nsIAtom* lang = mMappedFlows[0].mStartFrame->GetStyleVisibility()->mLangGroup;
@ -1495,7 +1541,8 @@ BuildTextRunsScanner::SetupBreakSinksForTextRun(gfxTextRun* aTextRun, const void
PRUint32 offset = mappedFlow->mTransformedTextOffset;
PRUint32 length =
(i == mMappedFlows.Length() - 1 ? aLength : mMappedFlows[i + 1].mTransformedTextOffset)
(i == mMappedFlows.Length() - 1 ? aTextRun->GetLength()
: mMappedFlows[i + 1].mTransformedTextOffset)
- offset;
PRUint32 flags = 0;
@ -1509,11 +1556,11 @@ BuildTextRunsScanner::SetupBreakSinksForTextRun(gfxTextRun* aTextRun, const void
// If length is zero and BREAK_WHITESPACE is active, this will notify
// the linebreaker to insert a break opportunity before the next character.
// Thus runs of entirely-skipped whitespace can still induce breaks.
if (aIs2b) {
mLineBreaker.AppendText(lang, NS_STATIC_CAST(const PRUnichar*, aText) + offset,
if (aTextRun->GetFlags() & gfxFontGroup::TEXT_IS_8BIT) {
mLineBreaker.AppendText(lang, aTextRun->GetText8Bit() + offset,
length, flags, *breakSink);
} else {
mLineBreaker.AppendText(lang, NS_STATIC_CAST(const PRUint8*, aText) + offset,
mLineBreaker.AppendText(lang, aTextRun->GetTextUnicode() + offset,
length, flags, *breakSink);
}
}
@ -1561,22 +1608,35 @@ BuildTextRunsScanner::AssignTextRun(gfxTextRun* aTextRun)
}
}
static already_AddRefed<nsIRenderingContext>
GetReferenceRenderingContext(nsTextFrame* aTextFrame, nsIRenderingContext* aRC)
{
if (aRC) {
NS_ADDREF(aRC);
return aRC;
}
nsIRenderingContext* result;
nsresult rv = aTextFrame->PresContext()->PresShell()->
CreateRenderingContext(aTextFrame, &result);
if (NS_FAILED(rv))
return nsnull;
return result;
}
gfxSkipCharsIterator
nsTextFrame::EnsureTextRun(nsIRenderingContext* aRC, nsBlockFrame* aBlock,
const nsLineList::iterator* aLine,
PRUint32* aFlowEndInTextRun)
{
if (!mTextRun) {
if (!aRC) {
nsCOMPtr<nsIRenderingContext> rendContext;
nsresult rv = PresContext()->PresShell()->
CreateRenderingContext(this, getter_AddRefs(rendContext));
if (NS_SUCCEEDED(rv)) {
BuildTextRuns(rendContext, this, aBlock, aLine);
}
} else {
BuildTextRuns(aRC, this, aBlock, aLine);
}
if (mTextRun) {
if (mTextRun->GetExpirationState()->IsTracked()) {
gTextRuns->MarkUsed(mTextRun);
}
} else {
nsCOMPtr<nsIRenderingContext> rendContext =
GetReferenceRenderingContext(this, aRC);
BuildTextRuns(rendContext, this, aBlock, aLine);
if (!mTextRun) {
// A text run was not constructed for this frame. This is bad. The caller
// will check mTextRun.
@ -1802,12 +1862,6 @@ public:
// Call this after construction if you're not going to reflow the text
void InitializeForDisplay(PRBool aTrimAfter);
virtual void ForceRememberText() {
PRPackedBool incomingWhitespace =
(mTextRun->GetFlags() & nsTextFrameUtils::TEXT_INCOMING_WHITESPACE) != 0;
ReconstructTextForRun(mTextRun, PR_TRUE, nsnull, &incomingWhitespace);
}
virtual void GetSpacing(PRUint32 aStart, PRUint32 aLength, Spacing* aSpacing);
virtual gfxFloat GetHyphenWidth();
virtual void GetHyphenationBreaks(PRUint32 aStart, PRUint32 aLength,
@ -2000,12 +2054,8 @@ PropertyProvider::GetSpacing(PRUint32 aStart, PRUint32 aLength,
// for tabs, and how many.
// ComputeTabSpaceCount takes transformed string offsets.
PRUint8* tabSpaceList = ComputeTabSpaceCount(aStart, aLength);
gfxTextRun* spaceTextRun =
GetSpecialString(GetFontGroup(), gfxFontGroup::STRING_SPACE, mTextRun);
gfxFloat spaceWidth = mLetterSpacing + mWordSpacing;
if (spaceTextRun) {
spaceWidth += spaceTextRun->GetAdvanceWidth(0, spaceTextRun->GetLength(), nsnull);
}
gfxFloat spaceWidth = mLetterSpacing + mWordSpacing +
mTextRun->GetFontGroup()->GetFontAt(0)->GetMetrics().spaceWidth*mTextRun->GetAppUnitsPerDevUnit();
for (index = 0; index < aLength; ++index) {
PRInt32 tabSpaces = tabSpaceList[index];
aSpacing[index].mAfter += spaceWidth*tabSpaces;
@ -2064,8 +2114,8 @@ gfxFloat
PropertyProvider::GetHyphenWidth()
{
if (mHyphenWidth < 0) {
gfxTextRun* hyphenTextRun =
GetSpecialString(GetFontGroup(), gfxFontGroup::STRING_HYPHEN, mTextRun);
nsCOMPtr<nsIRenderingContext> rc = GetReferenceRenderingContext(mFrame, nsnull);
gfxTextRun* hyphenTextRun = GetHyphenTextRun(mTextRun, rc);
mHyphenWidth = mLetterSpacing;
if (hyphenTextRun) {
mHyphenWidth += hyphenTextRun->GetAdvanceWidth(0, hyphenTextRun->GetLength(), nsnull);
@ -2170,11 +2220,11 @@ PropertyProvider::SetupJustificationSpacing()
mTextRun->GetAdvanceWidth(mStart.GetSkippedOffset(),
GetSkippedDistance(mStart, realEnd), this);
if (mFrame->GetStateBits() & TEXT_HYPHEN_BREAK) {
gfxTextRun* specialTextRun =
GetSpecialString(GetFontGroup(), gfxFontGroup::STRING_HYPHEN, mTextRun);
if (specialTextRun) {
nsCOMPtr<nsIRenderingContext> rc = GetReferenceRenderingContext(mFrame, nsnull);
gfxTextRun* hyphenTextRun = GetHyphenTextRun(mTextRun, rc);
if (hyphenTextRun) {
naturalWidth +=
specialTextRun->GetAdvanceWidth(0, specialTextRun->GetLength(), nsnull);
hyphenTextRun->GetAdvanceWidth(0, hyphenTextRun->GetLength(), nsnull);
}
}
gfxFloat totalJustificationSpace = mFrame->GetSize().width - naturalWidth;
@ -3042,18 +3092,6 @@ nsTextFrame::GetLastContinuation() const
return lastInFlow;
}
static void
ClearAllTextRunReferences(nsTextFrame* aFrame, gfxTextRun* aTextRun)
{
aFrame->RemoveStateBits(TEXT_IS_RUN_OWNER);
while (aFrame) {
if (aFrame->GetTextRun() != aTextRun)
break;
aFrame->SetTextRun(nsnull);
aFrame = NS_STATIC_CAST(nsTextFrame*, aFrame->GetNextContinuation());
}
}
void
nsTextFrame::ClearTextRun()
{
@ -3063,21 +3101,22 @@ nsTextFrame::ClearTextRun()
if (!textRun || !(GetStateBits() & TEXT_IS_RUN_OWNER))
return;
// Kill all references to the textrun. It could be referenced by any of its
// owners, and all their in-flows.
if (textRun->GetFlags() & nsTextFrameUtils::TEXT_IS_SIMPLE_FLOW) {
nsIFrame* firstInFlow = NS_STATIC_CAST(nsIFrame*, textRun->GetUserData());
ClearAllTextRunReferences(NS_STATIC_CAST(nsTextFrame*, firstInFlow), textRun);
} else {
TextRunUserData* userData =
NS_STATIC_CAST(TextRunUserData*, textRun->GetUserData());
PRInt32 i;
for (i = 0; i < userData->mMappedFlowCount; ++i) {
ClearAllTextRunReferences(userData->mMappedFlows[i].mStartFrame, textRun);
UnhookTextRunFromFrames(textRun);
if (textRun->GetFlags() & gfxFontGroup::TEXT_IS_PERSISTENT) {
// the textrun's text may be referencing a DOM node that's changing,
// or that will change, so we'd better kill this textrun now.
if (textRun->GetExpirationState()->IsTracked()) {
gTextRuns->RemoveFromCache(textRun);
}
DestroyUserData(userData);
delete textRun;
return;
}
// If it's not tracked (i.e. in the cache), then delete it now.
// Otherwise it stays alive in case it gets hit in the cache.
if (!textRun->GetExpirationState()->IsTracked()) {
delete textRun;
}
delete textRun;
}
NS_IMETHODIMP
@ -3619,8 +3658,10 @@ nsTextFrame::PaintTextWithSelectionColors(gfxContext* aCtx,
if (hyphenWidth) {
// Draw the hyphen
gfxFloat hyphenBaselineX = aFramePt.x + xOffset + mTextRun->GetDirection()*advance;
gfxTextRun* hyphenTextRun =
GetSpecialString(aProvider.GetFontGroup(), gfxFontGroup::STRING_HYPHEN, mTextRun);
// Get a reference rendering context because aCtx might not have the
// reference matrix currently set
nsCOMPtr<nsIRenderingContext> rc = GetReferenceRenderingContext(this, nsnull);
gfxTextRun* hyphenTextRun = GetHyphenTextRun(mTextRun, rc);
if (hyphenTextRun) {
hyphenTextRun->Draw(aCtx, gfxPoint(hyphenBaselineX, aTextBaselinePt.y),
0, hyphenTextRun->GetLength(), &aDirtyRect, nsnull, nsnull);
@ -3771,8 +3812,8 @@ nsTextFrame::PaintText(nsIRenderingContext* aRenderingContext, nsPoint aPt,
&dirtyRect, &provider, needAdvanceWidth);
if (GetStateBits() & TEXT_HYPHEN_BREAK) {
gfxFloat hyphenBaselineX = textBaselinePt.x + mTextRun->GetDirection()*advanceWidth;
gfxTextRun* hyphenTextRun =
GetSpecialString(provider.GetFontGroup(), gfxFontGroup::STRING_HYPHEN, mTextRun);
nsCOMPtr<nsIRenderingContext> rc = GetReferenceRenderingContext(this, nsnull);
gfxTextRun* hyphenTextRun = GetHyphenTextRun(mTextRun, rc);
if (hyphenTextRun) {
hyphenTextRun->Draw(ctx, gfxPoint(hyphenBaselineX, textBaselinePt.y),
0, hyphenTextRun->GetLength(), &dirtyRect, nsnull, nsnull);
@ -4541,36 +4582,31 @@ nsTextFrame::ComputeSize(nsIRenderingContext *aRenderingContext,
}
static void
AddCharToMetrics(gfxFloat aWidth, PropertyProvider* aProvider,
gfxFontGroup::SpecialString aSpecial, gfxTextRun* aTextRun,
AddCharToMetrics(gfxTextRun* aCharTextRun, gfxTextRun* aBaseTextRun,
gfxTextRun::Metrics* aMetrics, PRBool aTightBoundingBox)
{
gfxRect charRect;
// assume char does not overflow font metrics!!!
gfxFloat width = aCharTextRun->GetAdvanceWidth(0, aCharTextRun->GetLength(), nsnull);
if (aTightBoundingBox) {
gfxTextRun* specialTextRun =
GetSpecialString(aProvider->GetFontGroup(), aSpecial, aTextRun);
gfxTextRun::Metrics charMetrics;
if (specialTextRun) {
charMetrics =
specialTextRun->MeasureText(0, specialTextRun->GetLength(), PR_TRUE, nsnull);
}
gfxTextRun::Metrics charMetrics =
aCharTextRun->MeasureText(0, aCharTextRun->GetLength(), PR_TRUE, nsnull);
charRect = charMetrics.mBoundingBox;
} else {
// assume char does not overflow font metrics!!!
charRect = gfxRect(0, -aMetrics->mAscent, aWidth,
charRect = gfxRect(0, -aMetrics->mAscent, width,
aMetrics->mAscent + aMetrics->mDescent);
}
if (aTextRun->IsRightToLeft()) {
if (aBaseTextRun->IsRightToLeft()) {
// Char comes before text, so the bounding box is moved to the
// right by aWidth
aMetrics->mBoundingBox.MoveBy(gfxPoint(aWidth, 0));
aMetrics->mBoundingBox.MoveBy(gfxPoint(width, 0));
} else {
// char is moved to the right by mAdvanceWidth
charRect.MoveBy(gfxPoint(aMetrics->mAdvanceWidth, 0));
charRect.MoveBy(gfxPoint(width, 0));
}
aMetrics->mBoundingBox = aMetrics->mBoundingBox.Union(charRect);
aMetrics->mAdvanceWidth += aWidth;
aMetrics->mAdvanceWidth += width;
}
NS_IMETHODIMP
@ -4789,7 +4825,8 @@ nsTextFrame::Reflow(nsPresContext* aPresContext,
}
if (usedHyphenation) {
// Fix up metrics to include hyphen
AddCharToMetrics(provider.GetHyphenWidth(), &provider, gfxFontGroup::STRING_HYPHEN,
gfxTextRun* hyphenTextRun = GetHyphenTextRun(mTextRun, aReflowState.rendContext);
AddCharToMetrics(hyphenTextRun,
mTextRun, &textMetrics, needTightBoundingBox);
AddStateBits(TEXT_HYPHEN_BREAK);
}
@ -4981,7 +5018,6 @@ nsTextFrame::TrimTrailingWhiteSpace(nsPresContext* aPresContext,
PRUint32 trimmedEnd = iter.ConvertOriginalToSkipped(trimmed.mStart + trimmed.mLength);
const nsStyleText* textStyle = GetStyleText();
gfxFloat delta = 0;
PropertyProvider provider(mTextRun, textStyle, frag, this, iter, mContentLength);
if (GetStateBits() & TEXT_TRIMMED_TRAILING_WHITESPACE) {
aLastCharIsJustifiable = PR_TRUE;
@ -4989,6 +5025,7 @@ nsTextFrame::TrimTrailingWhiteSpace(nsPresContext* aPresContext,
gfxSkipCharsIterator end = iter;
PRUint32 endOffset = end.ConvertOriginalToSkipped(mContentOffset + mContentLength);
if (trimmedEnd < endOffset) {
PropertyProvider provider(mTextRun, textStyle, frag, this, iter, mContentLength);
delta = mTextRun->GetAdvanceWidth(trimmedEnd, endOffset - trimmedEnd, &provider);
// non-compressed whitespace being skipped at end of line -> justifiable
// XXX should we actually *count* justifiable characters that should be
@ -5000,6 +5037,7 @@ nsTextFrame::TrimTrailingWhiteSpace(nsPresContext* aPresContext,
if (!aLastCharIsJustifiable &&
NS_STYLE_TEXT_ALIGN_JUSTIFY == textStyle->mTextAlign) {
// Check if any character in the last cluster is justifiable
PropertyProvider provider(mTextRun, textStyle, frag, this, iter, mContentLength);
PRBool isCJK = IsChineseJapaneseLangGroup(this);
gfxSkipCharsIterator justificationEnd(iter);
provider.FindEndOfJustificationRange(&justificationEnd);
@ -5015,7 +5053,7 @@ nsTextFrame::TrimTrailingWhiteSpace(nsPresContext* aPresContext,
gfxFloat advanceDelta;
mTextRun->SetLineBreaks(trimmedStart, trimmedEnd - trimmedStart,
(GetStateBits() & TEXT_START_OF_LINE) != 0, PR_TRUE,
&provider, &advanceDelta);
&advanceDelta);
// aDeltaWidth is *subtracted* from our width.
// If advanceDelta is positive then setting the line break made us longer,

Просмотреть файл

@ -103,8 +103,7 @@ nsTextFrameUtils::TransformText(const PRUnichar* aText, PRUint32 aLength,
gfxSkipCharsBuilder* aSkipChars,
PRUint32* aAnalysisFlags)
{
// We're just going to assume this!
PRUint32 flags = TEXT_HAS_NON_ASCII;
PRUint32 flags = 0;
PRUnichar* outputStart = aOutput;
if (!aCompressWhitespace) {
@ -123,8 +122,6 @@ nsTextFrameUtils::TransformText(const PRUnichar* aText, PRUint32 aLength,
if (ch == CH_NBSP) {
ch = ' ';
flags |= TEXT_WAS_TRANSFORMED;
} else if (IS_SURROGATE(ch)) {
flags |= gfxTextRunFactory::TEXT_HAS_SURROGATES;
}
*aOutput++ = ch;
}
@ -161,8 +158,6 @@ nsTextFrameUtils::TransformText(const PRUnichar* aText, PRUint32 aLength,
if (ch == CH_NBSP) {
ch = ' ';
flags |= TEXT_WAS_TRANSFORMED;
} else if (IS_SURROGATE(ch)) {
flags |= gfxTextRunFactory::TEXT_HAS_SURROGATES;
}
*aOutput++ = ch;
aSkipChars->KeepChar();
@ -199,7 +194,6 @@ nsTextFrameUtils::TransformText(const PRUint8* aText, PRUint32 aLength,
PRUint32* aAnalysisFlags)
{
PRUint32 flags = 0;
PRUint8 allBits = 0;
PRUint8* outputStart = aOutput;
if (!aCompressWhitespace) {
@ -207,7 +201,6 @@ nsTextFrameUtils::TransformText(const PRUint8* aText, PRUint32 aLength,
PRUint32 i;
for (i = 0; i < aLength; ++i) {
PRUint8 ch = *aText++;
allBits |= ch;
if (ch == '\t') {
flags |= TEXT_HAS_TAB|TEXT_WAS_TRANSFORMED;
aSkipChars->KeepChar();
@ -229,7 +222,6 @@ nsTextFrameUtils::TransformText(const PRUint8* aText, PRUint32 aLength,
PRUint32 i;
for (i = 0; i < aLength; ++i) {
PRUint8 ch = *aText++;
allBits |= ch;
PRBool nowInWhitespace = ch == ' ' || ch == '\t' || ch == '\n' || ch == '\f';
if (!nowInWhitespace) {
if (IsDiscardable(ch, &flags)) {
@ -262,9 +254,6 @@ nsTextFrameUtils::TransformText(const PRUint8* aText, PRUint32 aLength,
if (outputStart + aLength != aOutput) {
flags |= TEXT_WAS_TRANSFORMED;
}
if (allBits & 0x80) {
flags |= TEXT_HAS_NON_ASCII;
}
*aAnalysisFlags = flags;
return aOutput;
}

Просмотреть файл

@ -40,6 +40,7 @@
#include "gfxFont.h"
#include "gfxSkipChars.h"
#include "gfxTextRunCache.h"
#include "nsTextFragment.h"
#define BIG_TEXT_NODE_SIZE 4096
@ -54,13 +55,14 @@ public:
TEXT_HAS_TAB = 0x010000,
// the original text has at least one soft hyphen character
TEXT_HAS_SHY = 0x020000,
TEXT_HAS_NON_ASCII = 0x040000,
TEXT_WAS_TRANSFORMED = 0x080000,
TEXT_WAS_TRANSFORMED = 0x040000,
// The following flags are set by nsTextFrame
TEXT_IS_SIMPLE_FLOW = 0x100000,
TEXT_INCOMING_WHITESPACE = 0x200000
TEXT_INCOMING_WHITESPACE = 0x200000,
TEXT_TRAILING_WHITESPACE = 0x400000,
TEXT_IS_UNCACHED = 0x800000
};
static PRBool
@ -86,6 +88,9 @@ public:
* @param aCompressWhitespace runs of consecutive whitespace (spaces not
* followed by a diacritical mark, tabs, and newlines) are compressed to a
* single space character.
* @param aIncomingWhitespace a flag indicating whether there was whitespace
* preceding this text. We set it to indicate if there's whitespace
* preceding the end of this text.
*/
static PRUnichar* TransformText(const PRUnichar* aText, PRUint32 aLength,
PRUnichar* aOutput,
@ -132,7 +137,7 @@ public:
PRInt32 aPosition, PRInt32 aDirection,
PRBool aBreakBeforePunctuation,
PRBool aBreakAfterPunctuation,
PRBool* aWordIsWhitespace);
PRBool* aWordIsWhitespace);
};
class nsSkipCharsRunIterator {

Просмотреть файл

@ -54,13 +54,13 @@
*/
class nsTransformedTextRun : public gfxTextRun {
public:
nsTransformedTextRun(gfxTextRunFactory::Parameters* aParams,
nsTransformedTextRun(const gfxTextRunFactory::Parameters* aParams,
nsTransformingTextRunFactory* aFactory,
gfxFontGroup* aFontGroup,
const PRUnichar* aString, PRUint32 aLength,
nsStyleContext** aStyles)
: gfxTextRun(aParams, aLength), mString(aString, aLength),
mFactory(aFactory), mRefContext(aParams->mContext),
mLangGroup(aParams->mLangGroup)
const PRUint32 aFlags, nsStyleContext** aStyles)
: gfxTextRun(aParams, aString, aLength, aFontGroup, aFlags),
mFactory(aFactory), mRefContext(aParams->mContext)
{
PRUint32 i;
for (i = 0; i < aLength; ++i) {
@ -80,13 +80,10 @@ public:
}
virtual PRBool SetLineBreaks(PRUint32 aStart, PRUint32 aLength,
PRBool aLineBreakBefore, PRBool aLineBreakAfter,
PropertyProvider* aProvider,
gfxFloat* aAdvanceWidthDelta);
nsString mString;
nsAutoPtr<nsTransformingTextRunFactory> mFactory;
nsRefPtr<gfxContext> mRefContext;
nsCOMPtr<nsIAtom> mLangGroup;
nsTArray<PRUint32> mLineBreaks;
nsTArray<nsRefPtr<nsStyleContext> > mStyles;
};
@ -94,7 +91,6 @@ public:
PRBool
nsTransformedTextRun::SetLineBreaks(PRUint32 aStart, PRUint32 aLength,
PRBool aLineBreakBefore, PRBool aLineBreakAfter,
PropertyProvider* aProvider,
gfxFloat* aAdvanceWidthDelta)
{
nsTArray<PRUint32> newBreaks;
@ -135,21 +131,22 @@ nsTransformedTextRun::SetLineBreaks(PRUint32 aStart, PRUint32 aLength,
newBreaks.AppendElements(mLineBreaks.Elements() + i, mLineBreaks.Length() - i);
mLineBreaks.SwapElements(newBreaks);
gfxFloat currentAdvance = GetAdvanceWidth(aStart, aLength, aProvider);
gfxFloat currentAdvance = GetAdvanceWidth(aStart, aLength, nsnull);
mFactory->RebuildTextRun(this);
if (aAdvanceWidthDelta) {
*aAdvanceWidthDelta = GetAdvanceWidth(aStart, aLength, aProvider) - currentAdvance;
*aAdvanceWidthDelta = GetAdvanceWidth(aStart, aLength, nsnull) - currentAdvance;
}
return PR_TRUE;
}
gfxTextRun*
nsTransformingTextRunFactory::MakeTextRun(const PRUnichar* aString, PRUint32 aLength,
gfxTextRunFactory::Parameters* aParams,
const gfxTextRunFactory::Parameters* aParams,
gfxFontGroup* aFontGroup, PRUint32 aFlags,
nsStyleContext** aStyles)
{
nsTransformedTextRun* textRun =
new nsTransformedTextRun(aParams, this, aString, aLength, aStyles);
new nsTransformedTextRun(aParams, this, aFontGroup, aString, aLength, aFlags, aStyles);
if (!textRun)
return nsnull;
RebuildTextRun(textRun);
@ -158,15 +155,16 @@ nsTransformingTextRunFactory::MakeTextRun(const PRUnichar* aString, PRUint32 aLe
gfxTextRun*
nsTransformingTextRunFactory::MakeTextRun(const PRUint8* aString, PRUint32 aLength,
gfxTextRunFactory::Parameters* aParams,
const gfxTextRunFactory::Parameters* aParams,
gfxFontGroup* aFontGroup, PRUint32 aFlags,
nsStyleContext** aStyles)
{
// We'll only have a Unicode code path to minimize the amount of code needed
// for these rarely used features
NS_ConvertASCIItoUTF16 unicodeString(NS_REINTERPRET_CAST(const char*, aString), aLength);
gfxTextRunFactory::Parameters params = *aParams;
params.mFlags &= ~gfxTextRunFactory::TEXT_IS_PERSISTENT;
return MakeTextRun(unicodeString.get(), aLength, &params, aStyles);
return MakeTextRun(unicodeString.get(), aLength, aParams, aFontGroup,
aFlags & ~(gfxFontGroup::TEXT_IS_PERSISTENT | gfxFontGroup::TEXT_IS_8BIT),
aStyles);
}
static PRUint32
@ -301,13 +299,13 @@ MergeCharactersInTextRun(gfxTextRun* aDest, gfxTextRun* aSrc,
}
static gfxTextRunFactory::Parameters
GetParametersForInner(nsTransformedTextRun* aTextRun,
gfxSkipChars* aDummy)
GetParametersForInner(nsTransformedTextRun* aTextRun, PRUint32* aFlags)
{
gfxTextRunFactory::Parameters params =
{ aTextRun->mRefContext, nsnull, aTextRun->mLangGroup, aDummy,
nsnull, nsnull, PRUint32(aTextRun->GetAppUnitsPerDevUnit()),
aTextRun->GetFlags() };
{ aTextRun->mRefContext, nsnull, nsnull,
nsnull, nsnull, PRUint32(aTextRun->GetAppUnitsPerDevUnit())
};
*aFlags = aTextRun->GetFlags() & ~gfxFontGroup::TEXT_IS_PERSISTENT;
return params;
}
@ -318,25 +316,26 @@ nsFontVariantTextRunFactory::RebuildTextRun(nsTransformedTextRun* aTextRun)
if (!converter)
return;
gfxFontStyle fontStyle = *mFontGroup->GetStyle();
gfxFontGroup* fontGroup = aTextRun->GetFontGroup();
gfxFontStyle fontStyle = *fontGroup->GetStyle();
fontStyle.size *= 0.8;
nsRefPtr<gfxFontGroup> smallFont = mFontGroup->Copy(&fontStyle);
nsRefPtr<gfxFontGroup> smallFont = fontGroup->Copy(&fontStyle);
if (!smallFont)
return;
gfxSkipChars dummy;
gfxTextRunFactory::Parameters innerParams = GetParametersForInner(aTextRun, &dummy);
PRUint32 flags;
gfxTextRunFactory::Parameters innerParams = GetParametersForInner(aTextRun, &flags);
PRUint32 length = aTextRun->GetLength();
const PRUnichar* str = aTextRun->mString.BeginReading();
const PRUnichar* str = aTextRun->GetTextUnicode();
nsRefPtr<nsStyleContext>* styles = aTextRun->mStyles.Elements();
// Create a textrun so we can check cluster-start properties
nsAutoPtr<gfxTextRun> inner;
inner = mFontGroup->MakeTextRun(str, length, &innerParams);
inner = fontGroup->MakeTextRun(str, length, &innerParams, flags);
if (!inner)
return;
nsCaseTransformTextRunFactory uppercaseFactory(smallFont, nsnull, PR_TRUE);
nsCaseTransformTextRunFactory uppercaseFactory(nsnull, PR_TRUE);
aTextRun->ResetGlyphRuns();
@ -379,9 +378,11 @@ nsFontVariantTextRunFactory::RebuildTextRun(nsTransformedTextRun* aTextRun)
innerParams.mInitialBreakCount = lineBreakBeforeArray.Length();
if (runIsLowercase) {
child = uppercaseFactory.MakeTextRun(str + runStart, i - runStart,
&innerParams, styleArray.Elements());
&innerParams, smallFont, flags,
styleArray.Elements());
} else {
child = mFontGroup->MakeTextRun(str + runStart, i - runStart, &innerParams);
child = fontGroup->
MakeTextRun(str + runStart, i - runStart, &innerParams, flags);
}
if (!child)
return;
@ -419,7 +420,7 @@ nsCaseTransformTextRunFactory::RebuildTextRun(nsTransformedTextRun* aTextRun)
return;
PRUint32 length = aTextRun->GetLength();
const PRUnichar* str = aTextRun->mString.BeginReading();
const PRUnichar* str = aTextRun->GetTextUnicode();
nsRefPtr<nsStyleContext>* styles = aTextRun->mStyles.Elements();
nsAutoString convertedString;
@ -491,8 +492,9 @@ nsCaseTransformTextRunFactory::RebuildTextRun(nsTransformedTextRun* aTextRun)
NS_ASSERTION(nextLineBreak == aTextRun->mLineBreaks.Length(),
"lost track of line breaks somehow");
gfxSkipChars dummy;
gfxTextRunFactory::Parameters innerParams = GetParametersForInner(aTextRun, &dummy);
PRUint32 flags;
gfxTextRunFactory::Parameters innerParams = GetParametersForInner(aTextRun, &flags);
gfxFontGroup* fontGroup = aTextRun->GetFontGroup();
nsAutoPtr<gfxTextRun> child;
// Setup actual line break data for child (which may affect shaping)
@ -501,10 +503,11 @@ nsCaseTransformTextRunFactory::RebuildTextRun(nsTransformedTextRun* aTextRun)
if (mInnerTransformingTextRunFactory) {
child = mInnerTransformingTextRunFactory->MakeTextRun(
convertedString.BeginReading(), convertedString.Length(),
&innerParams, styleArray.Elements());
&innerParams, fontGroup, flags, styleArray.Elements());
} else {
child = mFontGroup->MakeTextRun(
convertedString.BeginReading(), convertedString.Length(), &innerParams);
child = fontGroup->MakeTextRun(
convertedString.BeginReading(), convertedString.Length(), &innerParams,
flags);
}
if (!child)
return;

Просмотреть файл

@ -49,9 +49,13 @@ public:
// Default 8-bit path just transforms to Unicode and takes that path
gfxTextRun* MakeTextRun(const PRUint8* aString, PRUint32 aLength,
gfxFontGroup::Parameters* aParams, nsStyleContext** aStyles);
const gfxFontGroup::Parameters* aParams,
gfxFontGroup* aFontGroup, PRUint32 aFlags,
nsStyleContext** aStyles);
gfxTextRun* MakeTextRun(const PRUnichar* aString, PRUint32 aLength,
gfxFontGroup::Parameters* aParams, nsStyleContext** aStyles);
const gfxFontGroup::Parameters* aParams,
gfxFontGroup* aFontGroup, PRUint32 aFlags,
nsStyleContext** aStyles);
virtual void RebuildTextRun(nsTransformedTextRun* aTextRun) = 0;
};
@ -62,13 +66,7 @@ public:
*/
class nsFontVariantTextRunFactory : public nsTransformingTextRunFactory {
public:
nsFontVariantTextRunFactory(gfxFontGroup* aFontGroup)
: mFontGroup(aFontGroup) {}
virtual void RebuildTextRun(nsTransformedTextRun* aTextRun);
protected:
nsRefPtr<gfxFontGroup> mFontGroup;
};
/**
@ -83,17 +81,14 @@ public:
// just convert the string to uppercase or lowercase and create the textrun
// via the fontgroup.
nsCaseTransformTextRunFactory(gfxFontGroup* aFontGroup,
nsTransformingTextRunFactory* aInnerTransformingTextRunFactory,
nsCaseTransformTextRunFactory(nsTransformingTextRunFactory* aInnerTransformingTextRunFactory,
PRBool aAllUppercase = PR_FALSE)
: mFontGroup(aFontGroup),
mInnerTransformingTextRunFactory(aInnerTransformingTextRunFactory),
: mInnerTransformingTextRunFactory(aInnerTransformingTextRunFactory),
mAllUppercase(aAllUppercase) {}
virtual void RebuildTextRun(nsTransformedTextRun* aTextRun);
protected:
nsRefPtr<gfxFontGroup> mFontGroup;
nsAutoPtr<nsTransformingTextRunFactory> mInnerTransformingTextRunFactory;
PRPackedBool mAllUppercase;
};