mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-14 02:31:59 +00:00
Bug 397734. More parsimonious storage of glyph extents ... trying to fix private-bytes regression. r=vlad,a=pavlov
This commit is contained in:
parent
742f0cdd5b
commit
1b1c97e9d8
@ -246,8 +246,10 @@ class THEBES_API gfxGlyphExtents {
|
||||
public:
|
||||
gfxGlyphExtents(PRUint32 aAppUnitsPerDevUnit) :
|
||||
mAppUnitsPerDevUnit(aAppUnitsPerDevUnit) {
|
||||
MOZ_COUNT_CTOR(gfxGlyphExtents);
|
||||
mTightGlyphExtents.Init();
|
||||
}
|
||||
~gfxGlyphExtents();
|
||||
|
||||
enum { INVALID_WIDTH = 0xFFFF };
|
||||
|
||||
@ -256,16 +258,12 @@ public:
|
||||
// and the result is its width measured from the baseline origin, in
|
||||
// appunits.
|
||||
PRUint16 GetContainedGlyphWidthAppUnits(PRUint32 aGlyphID) const {
|
||||
if (aGlyphID >= mWidthsForContainedGlyphsAppUnits.Length())
|
||||
return INVALID_WIDTH;
|
||||
return mWidthsForContainedGlyphsAppUnits[aGlyphID];
|
||||
return mContainedGlyphWidths.Get(aGlyphID);
|
||||
}
|
||||
|
||||
PRBool IsGlyphKnown(PRUint32 aGlyphID) const {
|
||||
if (aGlyphID < mWidthsForContainedGlyphsAppUnits.Length() &&
|
||||
mWidthsForContainedGlyphsAppUnits[aGlyphID] != INVALID_WIDTH)
|
||||
return PR_TRUE;
|
||||
return mTightGlyphExtents.GetEntry(aGlyphID) != nsnull;
|
||||
return mContainedGlyphWidths.Get(aGlyphID) != INVALID_WIDTH ||
|
||||
mTightGlyphExtents.GetEntry(aGlyphID) != nsnull;
|
||||
}
|
||||
|
||||
PRBool IsGlyphKnownWithTightExtents(PRUint32 aGlyphID) const {
|
||||
@ -275,7 +273,9 @@ public:
|
||||
// Get glyph extents; a rectangle relative to the left baseline origin
|
||||
gfxRect GetTightGlyphExtentsAppUnits(gfxFont *aFont, gfxContext *aContext, PRUint32 aGlyphID);
|
||||
|
||||
void SetContainedGlyphWidthAppUnits(PRUint32 aGlyphID, PRUint16 aWidth);
|
||||
void SetContainedGlyphWidthAppUnits(PRUint32 aGlyphID, PRUint16 aWidth) {
|
||||
mContainedGlyphWidths.Set(aGlyphID, aWidth);
|
||||
}
|
||||
void SetTightGlyphExtents(PRUint32 aGlyphID, const gfxRect& aExtentsAppUnits);
|
||||
|
||||
PRUint32 GetAppUnitsPerDevUnit() { return mAppUnitsPerDevUnit; }
|
||||
@ -293,7 +293,52 @@ private:
|
||||
float x, y, width, height;
|
||||
};
|
||||
|
||||
nsTArray<PRUint16> mWidthsForContainedGlyphsAppUnits;
|
||||
typedef unsigned long PtrBits;
|
||||
enum { BLOCK_SIZE_BITS = 7, BLOCK_SIZE = 1 << BLOCK_SIZE_BITS }; // 128-glyph blocks
|
||||
|
||||
class GlyphWidths {
|
||||
public:
|
||||
void Set(PRUint32 aIndex, PRUint16 aValue);
|
||||
PRUint16 Get(PRUint32 aIndex) const {
|
||||
PRUint32 block = aIndex >> BLOCK_SIZE_BITS;
|
||||
if (block >= mBlocks.Length())
|
||||
return INVALID_WIDTH;
|
||||
PtrBits bits = mBlocks[block];
|
||||
if (!bits)
|
||||
return INVALID_WIDTH;
|
||||
PRUint32 indexInBlock = aIndex & (BLOCK_SIZE - 1);
|
||||
if (bits & 0x1) {
|
||||
if (GetGlyphOffset(bits) != indexInBlock)
|
||||
return INVALID_WIDTH;
|
||||
return GetWidth(bits);
|
||||
}
|
||||
PRUint16 *widths = reinterpret_cast<PRUint16 *>(bits);
|
||||
return widths[indexInBlock];
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
PRUint32 ComputeSize();
|
||||
#endif
|
||||
|
||||
~GlyphWidths();
|
||||
|
||||
private:
|
||||
static PRUint32 GetGlyphOffset(PtrBits aBits) {
|
||||
NS_ASSERTION(aBits & 0x1, "This is really a pointer...");
|
||||
return (aBits >> 1) & ((1 << BLOCK_SIZE_BITS) - 1);
|
||||
}
|
||||
static PRUint32 GetWidth(PtrBits aBits) {
|
||||
NS_ASSERTION(aBits & 0x1, "This is really a pointer...");
|
||||
return aBits >> (1 + BLOCK_SIZE_BITS);
|
||||
}
|
||||
static PtrBits MakeSingle(PRUint32 aGlyphOffset, PRUint16 aWidth) {
|
||||
return (aWidth << (1 + BLOCK_SIZE_BITS)) + (aGlyphOffset << 1) + 1;
|
||||
}
|
||||
|
||||
nsTArray<PtrBits> mBlocks;
|
||||
};
|
||||
|
||||
GlyphWidths mContainedGlyphWidths;
|
||||
nsTHashtable<HashEntry> mTightGlyphExtents;
|
||||
PRUint32 mAppUnitsPerDevUnit;
|
||||
};
|
||||
|
@ -64,6 +64,13 @@ gfxFontCache *gfxFontCache::gGlobalCache = nsnull;
|
||||
#ifdef DEBUG_TEXT_RUN_STORAGE_METRICS
|
||||
static PRUint32 gTextRunStorageHighWaterMark = 0;
|
||||
static PRUint32 gTextRunStorage = 0;
|
||||
static PRUint32 gFontCount = 0;
|
||||
static PRUint32 gGlyphExtentsCount = 0;
|
||||
static PRUint32 gGlyphExtentsWidthsTotalSize = 0;
|
||||
static PRUint32 gGlyphExtentsSetupEagerSimple = 0;
|
||||
static PRUint32 gGlyphExtentsSetupEagerTight = 0;
|
||||
static PRUint32 gGlyphExtentsSetupLazyTight = 0;
|
||||
static PRUint32 gGlyphExtentsSetupFallBackToTight = 0;
|
||||
#endif
|
||||
|
||||
nsresult
|
||||
@ -82,6 +89,14 @@ gfxFontCache::Shutdown()
|
||||
|
||||
#ifdef DEBUG_TEXT_RUN_STORAGE_METRICS
|
||||
printf("Textrun storage high water mark=%d\n", gTextRunStorageHighWaterMark);
|
||||
printf("Total number of fonts=%d\n", gFontCount);
|
||||
printf("Total glyph extents allocated=%d (size %d)\n", gGlyphExtentsCount,
|
||||
int(gGlyphExtentsCount*sizeof(gfxGlyphExtents)));
|
||||
printf("Total glyph extents width-storage size allocated=%d\n", gGlyphExtentsWidthsTotalSize);
|
||||
printf("Number of simple glyph extents eagerly requested=%d\n", gGlyphExtentsSetupEagerSimple);
|
||||
printf("Number of tight glyph extents eagerly requested=%d\n", gGlyphExtentsSetupEagerTight);
|
||||
printf("Number of tight glyph extents lazily requested=%d\n", gGlyphExtentsSetupLazyTight);
|
||||
printf("Number of simple glyph extent setups that fell back to tight=%d\n", gGlyphExtentsSetupFallBackToTight);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -160,6 +175,9 @@ gfxFontCache::DestroyFont(gfxFont *aFont)
|
||||
gfxFont::gfxFont(const nsAString &aName, const gfxFontStyle *aFontStyle) :
|
||||
mName(aName), mStyle(*aFontStyle)
|
||||
{
|
||||
#ifdef DEBUG_TEXT_RUN_STORAGE_METRICS
|
||||
++gFontCount;
|
||||
#endif
|
||||
}
|
||||
|
||||
gfxFont::~gfxFont()
|
||||
@ -331,8 +349,7 @@ UnionWithXPoint(gfxRect *aRect, double aX)
|
||||
static PRBool
|
||||
NeedsGlyphExtents(gfxTextRun *aTextRun)
|
||||
{
|
||||
return (aTextRun->GetFlags() & gfxTextRunFactory::TEXT_OPTIMIZE_SPEED) == 0;
|
||||
// return PR_TRUE;
|
||||
return (aTextRun->GetFlags() & gfxTextRunFactory::TEXT_NEED_BOUNDING_BOX) != 0;
|
||||
}
|
||||
|
||||
gfxFont::RunMetrics
|
||||
@ -480,6 +497,11 @@ gfxFont::SetupGlyphExtents(gfxContext *aContext, PRUint32 aGlyphID, PRBool aNeed
|
||||
return;
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG_TEXT_RUN_STORAGE_METRICS
|
||||
if (!aNeedTight) {
|
||||
++gGlyphExtentsSetupFallBackToTight;
|
||||
}
|
||||
#endif
|
||||
|
||||
double d2a = appUnitsPerDevUnit;
|
||||
gfxRect bounds(extents.x_bearing*d2a, extents.y_bearing*d2a,
|
||||
@ -487,6 +509,15 @@ gfxFont::SetupGlyphExtents(gfxContext *aContext, PRUint32 aGlyphID, PRBool aNeed
|
||||
aExtents->SetTightGlyphExtents(aGlyphID, bounds);
|
||||
}
|
||||
|
||||
gfxGlyphExtents::~gfxGlyphExtents()
|
||||
{
|
||||
#ifdef DEBUG_TEXT_RUN_STORAGE_METRICS
|
||||
gGlyphExtentsWidthsTotalSize += mContainedGlyphWidths.ComputeSize();
|
||||
gGlyphExtentsCount++;
|
||||
#endif
|
||||
MOZ_COUNT_DTOR(gfxGlyphExtents);
|
||||
}
|
||||
|
||||
gfxRect
|
||||
gfxGlyphExtents::GetTightGlyphExtentsAppUnits(gfxFont *aFont,
|
||||
gfxContext *aContext, PRUint32 aGlyphID)
|
||||
@ -494,6 +525,9 @@ gfxGlyphExtents::GetTightGlyphExtentsAppUnits(gfxFont *aFont,
|
||||
HashEntry *entry = mTightGlyphExtents.GetEntry(aGlyphID);
|
||||
if (!entry) {
|
||||
aFont->SetupCairoFont(aContext);
|
||||
#ifdef DEBUG_TEXT_RUN_STORAGE_METRICS
|
||||
++gGlyphExtentsSetupLazyTight;
|
||||
#endif
|
||||
aFont->SetupGlyphExtents(aContext, aGlyphID, PR_TRUE, this);
|
||||
entry = mTightGlyphExtents.GetEntry(aGlyphID);
|
||||
if (!entry) {
|
||||
@ -505,20 +539,65 @@ gfxGlyphExtents::GetTightGlyphExtentsAppUnits(gfxFont *aFont,
|
||||
return gfxRect(entry->x, entry->y, entry->width, entry->height);
|
||||
}
|
||||
|
||||
void
|
||||
gfxGlyphExtents::SetContainedGlyphWidthAppUnits(PRUint32 aGlyphID, PRUint16 aWidth)
|
||||
gfxGlyphExtents::GlyphWidths::~GlyphWidths()
|
||||
{
|
||||
PRUint32 len = mWidthsForContainedGlyphsAppUnits.Length();
|
||||
if (aGlyphID >= len) {
|
||||
PRUint16 *elems = mWidthsForContainedGlyphsAppUnits.AppendElements(aGlyphID + 1 - len);
|
||||
if (!elems)
|
||||
return;
|
||||
PRUint32 i;
|
||||
for (i = len; i < aGlyphID; ++i) {
|
||||
mWidthsForContainedGlyphsAppUnits[i] = INVALID_WIDTH;
|
||||
PRUint32 i;
|
||||
for (i = 0; i < mBlocks.Length(); ++i) {
|
||||
PtrBits bits = mBlocks[i];
|
||||
if (bits && !(bits & 0x1)) {
|
||||
delete[] reinterpret_cast<PRUint16 *>(bits);
|
||||
}
|
||||
}
|
||||
mWidthsForContainedGlyphsAppUnits[aGlyphID] = aWidth;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
PRUint32
|
||||
gfxGlyphExtents::GlyphWidths::ComputeSize()
|
||||
{
|
||||
PRUint32 i;
|
||||
PRUint32 size = mBlocks.Capacity()*sizeof(PtrBits);
|
||||
for (i = 0; i < mBlocks.Length(); ++i) {
|
||||
PtrBits bits = mBlocks[i];
|
||||
if (bits && !(bits & 0x1)) {
|
||||
size += BLOCK_SIZE*sizeof(PRUint16);
|
||||
}
|
||||
}
|
||||
return size;
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
gfxGlyphExtents::GlyphWidths::Set(PRUint32 aGlyphID, PRUint16 aWidth)
|
||||
{
|
||||
PRUint32 block = aGlyphID >> BLOCK_SIZE_BITS;
|
||||
PRUint32 len = mBlocks.Length();
|
||||
if (block >= len) {
|
||||
PtrBits *elems = mBlocks.AppendElements(block + 1 - len);
|
||||
if (!elems)
|
||||
return;
|
||||
memset(elems, 0, sizeof(PtrBits)*(block + 1 - len));
|
||||
}
|
||||
|
||||
PtrBits bits = mBlocks[block];
|
||||
PRUint32 glyphOffset = aGlyphID & (BLOCK_SIZE - 1);
|
||||
if (!bits) {
|
||||
mBlocks[block] = MakeSingle(glyphOffset, aWidth);
|
||||
return;
|
||||
}
|
||||
|
||||
PRUint16 *newBlock;
|
||||
if (bits & 0x1) {
|
||||
// Expand the block to a real block. We could avoid this by checking
|
||||
// glyphOffset == GetGlyphOffset(bits), but that never happens so don't bother
|
||||
newBlock = new PRUint16[BLOCK_SIZE];
|
||||
if (!newBlock)
|
||||
return;
|
||||
newBlock[GetGlyphOffset(bits)] = GetWidth(bits);
|
||||
mBlocks[block] = reinterpret_cast<PtrBits>(newBlock);
|
||||
} else {
|
||||
newBlock = reinterpret_cast<PRUint16 *>(bits);
|
||||
}
|
||||
newBlock[glyphOffset] = aWidth;
|
||||
}
|
||||
|
||||
void
|
||||
@ -1932,6 +2011,9 @@ gfxTextRun::FetchGlyphExtents(gfxContext *aRefContext)
|
||||
font->SetupCairoFont(aRefContext);
|
||||
fontIsSetup = PR_TRUE;
|
||||
}
|
||||
#ifdef DEBUG_TEXT_RUN_STORAGE_METRICS
|
||||
++gGlyphExtentsSetupEagerSimple;
|
||||
#endif
|
||||
font->SetupGlyphExtents(aRefContext, glyphIndex, PR_FALSE, extents);
|
||||
}
|
||||
}
|
||||
@ -1944,6 +2026,9 @@ gfxTextRun::FetchGlyphExtents(gfxContext *aRefContext)
|
||||
font->SetupCairoFont(aRefContext);
|
||||
fontIsSetup = PR_TRUE;
|
||||
}
|
||||
#ifdef DEBUG_TEXT_RUN_STORAGE_METRICS
|
||||
++gGlyphExtentsSetupEagerTight;
|
||||
#endif
|
||||
font->SetupGlyphExtents(aRefContext, glyphIndex, PR_TRUE, extents);
|
||||
}
|
||||
if (details->mIsLastGlyph)
|
||||
|
@ -1262,8 +1262,7 @@ BuildTextRunsScanner::BuildTextRunForFrames(void* aTextBuffer)
|
||||
PRBool anyTextTransformStyle = PR_FALSE;
|
||||
nsIContent* lastContent = nsnull;
|
||||
PRInt32 endOfLastContent = 0;
|
||||
PRUint32 textFlags = gfxTextRunFactory::TEXT_NEED_BOUNDING_BOX |
|
||||
nsTextFrameUtils::TEXT_NO_BREAKS;
|
||||
PRUint32 textFlags = nsTextFrameUtils::TEXT_NO_BREAKS;
|
||||
|
||||
if (mCurrentRunTrimLeadingWhitespace) {
|
||||
textFlags |= nsTextFrameUtils::TEXT_INCOMING_WHITESPACE;
|
||||
@ -1466,6 +1465,11 @@ BuildTextRunsScanner::BuildTextRunForFrames(void* aTextBuffer)
|
||||
// frame's style is used, so use the last frame's
|
||||
textFlags |= nsLayoutUtils::GetTextRunFlagsForStyle(lastStyleContext,
|
||||
textStyle, fontStyle);
|
||||
// XXX this is a bit of a hack. For performance reasons, if we're favouring
|
||||
// performance over quality, don't try to get accurate glyph extents.
|
||||
if (!(textFlags & gfxTextRunFactory::TEXT_OPTIMIZE_SPEED)) {
|
||||
textFlags |= gfxTextRunFactory::TEXT_NEED_BOUNDING_BOX;
|
||||
}
|
||||
|
||||
gfxSkipChars skipChars;
|
||||
skipChars.TakeFrom(&builder);
|
||||
|
@ -1340,8 +1340,8 @@ nsSVGGlyphFrame::GetTextRun(gfxContext *aCtx, const nsString &aText)
|
||||
if (!mFontGroup)
|
||||
return nsnull;
|
||||
|
||||
PRUint32 flags = nsLayoutUtils::GetTextRunFlagsForStyle(GetStyleContext(),
|
||||
GetStyleText(), GetStyleFont());
|
||||
PRUint32 flags = gfxTextRunFactory::TEXT_NEED_BOUNDING_BOX |
|
||||
nsLayoutUtils::GetTextRunFlagsForStyle(GetStyleContext(), GetStyleText(), GetStyleFont());
|
||||
return gfxTextRunCache::MakeTextRun(aText.get(), aText.Length(),
|
||||
mFontGroup, aCtx, 1, flags);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user