Create uncached glyphs on demand instead of checking glyph availability upfront.
This safes a HasGlyphs() call which would convert the whole string to glyph codes and look each of the glyphs up in the cache entry, just to do the same again during the loop where they are actually used. Instead we now simply switch to the write lock and look up the fallback entry when hitting the first uncached glyph. This benefits the normal case of having all glyphs cached without any drawbacks. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@40186 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
27997edca9
commit
427427bc82
@ -256,7 +256,15 @@ render_as_zero_width(uint32 glyphCode)
|
||||
|
||||
|
||||
const GlyphCache*
|
||||
FontCacheEntry::Glyph(uint32 glyphCode, FontCacheEntry* fallbackEntry)
|
||||
FontCacheEntry::CachedGlyph(uint32 glyphCode)
|
||||
{
|
||||
// Only requires a read lock.
|
||||
return fGlyphCache->FindGlyph(glyphCode);
|
||||
}
|
||||
|
||||
|
||||
const GlyphCache*
|
||||
FontCacheEntry::CreateGlyph(uint32 glyphCode, FontCacheEntry* fallbackEntry)
|
||||
{
|
||||
// We cache the glyph by the requested glyphCode. The FontEngine of this
|
||||
// FontCacheEntry may not contain a glyph for the given code, in which case
|
||||
|
@ -103,7 +103,8 @@ class FontCacheEntry : public MultiLocker, public BReferenceable {
|
||||
bool HasGlyphs(const char* utf8String,
|
||||
ssize_t glyphCount) const;
|
||||
|
||||
const GlyphCache* Glyph(uint32 glyphCode,
|
||||
const GlyphCache* CachedGlyph(uint32 glyphCode);
|
||||
const GlyphCache* CreateGlyph(uint32 glyphCode,
|
||||
FontCacheEntry* fallbackEntry = NULL);
|
||||
|
||||
void InitAdaptors(const GlyphCache* glyph,
|
||||
|
@ -97,6 +97,14 @@ public:
|
||||
FontCacheReference* cacheReference = NULL);
|
||||
|
||||
private:
|
||||
static bool _WriteLockAndAcquireFallbackEntry(
|
||||
FontCacheReference& cacheReference,
|
||||
FontCacheEntry* entry,
|
||||
const ServerFont& font,
|
||||
const char* utf8String, int32 length,
|
||||
FontCacheReference& fallbackCacheReference,
|
||||
FontCacheEntry*& fallbackEntry);
|
||||
|
||||
GlyphLayoutEngine();
|
||||
virtual ~GlyphLayoutEngine();
|
||||
};
|
||||
@ -189,52 +197,6 @@ GlyphLayoutEngine::LayoutGlyphs(GlyphConsumer& consumer,
|
||||
|
||||
if (entry == NULL)
|
||||
return false;
|
||||
|
||||
// See if the entry already has the glyphs cached. Switch to a write
|
||||
// lock if not.
|
||||
bool needsWriteLock = !entry->HasGlyphs(utf8String, length);
|
||||
if (needsWriteLock) {
|
||||
// This also means we need the fallback font, since potentially,
|
||||
// we have to obtain missing glyphs from it. We need to obtain
|
||||
// the fallback font while we have not locked anything, since
|
||||
// locking the FontManager with the write-lock held can obvisouly
|
||||
// lead to a deadlock.
|
||||
|
||||
cacheReference.SetTo(NULL, false);
|
||||
entry->ReadUnlock();
|
||||
|
||||
if (gFontManager->Lock()) {
|
||||
// TODO: We always get the fallback glyphs from VL Gothic at the
|
||||
// moment, but of course the fallback font should a) contain the
|
||||
// missing glyphs at all and b) be similar to the original font.
|
||||
// So there should be a mapping of some kind to know the most
|
||||
// suitable fallback font.
|
||||
FontStyle* fallbackStyle = gFontManager->GetStyleByIndex(
|
||||
"VL Gothic", 0);
|
||||
if (fallbackStyle != NULL) {
|
||||
ServerFont fallbackFont(*fallbackStyle, font.Size());
|
||||
gFontManager->Unlock();
|
||||
// Force the write-lock on the fallback entry, since we
|
||||
// don't transfer or copy GlyphCache objects from one cache
|
||||
// to the other, but create new glyphs which are stored in
|
||||
// "entry" in any case, which requires the write cache for
|
||||
// sure (used FontEngine of fallbackEntry).
|
||||
fallbackEntry = FontCacheEntryFor(fallbackFont, entry,
|
||||
utf8String, length, fallbackCacheReference, true);
|
||||
// NOTE: We don't care if fallbackEntry is NULL, fetching
|
||||
// alternate glyphs will simply not work.
|
||||
} else
|
||||
gFontManager->Unlock();
|
||||
}
|
||||
|
||||
if (!entry->WriteLock()) {
|
||||
FontCache::Default()->Recycle(entry);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Update the FontCacheReference, since the locking kind changed.
|
||||
cacheReference.SetTo(entry, needsWriteLock);
|
||||
}
|
||||
} // else the entry was already used and is still locked
|
||||
|
||||
consumer.Start();
|
||||
@ -252,6 +214,7 @@ GlyphLayoutEngine::LayoutGlyphs(GlyphConsumer& consumer,
|
||||
uint32 lastCharCode = 0;
|
||||
uint32 charCode;
|
||||
int32 index = 0;
|
||||
bool writeLocked = false;
|
||||
const char* start = utf8String;
|
||||
while ((charCode = UTF8ToCharCode(&utf8String))) {
|
||||
|
||||
@ -273,7 +236,22 @@ GlyphLayoutEngine::LayoutGlyphs(GlyphConsumer& consumer,
|
||||
x += IsWhiteSpace(charCode) ? delta->space : delta->nonspace;
|
||||
}
|
||||
|
||||
const GlyphCache* glyph = entry->Glyph(charCode, fallbackEntry);
|
||||
const GlyphCache* glyph = entry->CachedGlyph(charCode);
|
||||
if (glyph == NULL) {
|
||||
// The glyph has not been cached yet, switch to a write lock,
|
||||
// acquire the fallback entry and create the glyph. Note that
|
||||
// the write lock will persist (in the cacheReference) so that
|
||||
// we only have to do this switch once for the whole string.
|
||||
if (!writeLocked) {
|
||||
writeLocked = _WriteLockAndAcquireFallbackEntry(cacheReference,
|
||||
entry, font, utf8String, length, fallbackCacheReference,
|
||||
fallbackEntry);
|
||||
}
|
||||
|
||||
if (writeLocked)
|
||||
glyph = entry->CreateGlyph(charCode, fallbackEntry);
|
||||
}
|
||||
|
||||
if (glyph == NULL) {
|
||||
consumer.ConsumeEmptyGlyph(index++, charCode, x, y);
|
||||
advanceX = 0;
|
||||
@ -312,4 +290,53 @@ GlyphLayoutEngine::LayoutGlyphs(GlyphConsumer& consumer,
|
||||
}
|
||||
|
||||
|
||||
inline bool
|
||||
GlyphLayoutEngine::_WriteLockAndAcquireFallbackEntry(
|
||||
FontCacheReference& cacheReference, FontCacheEntry* entry,
|
||||
const ServerFont& font, const char* utf8String, int32 length,
|
||||
FontCacheReference& fallbackCacheReference, FontCacheEntry*& fallbackEntry)
|
||||
{
|
||||
// We need the fallback font, since potentially, we have to obtain missing
|
||||
// glyphs from it. We need to obtain the fallback font while we have not
|
||||
// locked anything, since locking the FontManager with the write-lock held
|
||||
// can obvisouly lead to a deadlock.
|
||||
|
||||
cacheReference.SetTo(NULL, false);
|
||||
entry->ReadUnlock();
|
||||
|
||||
if (gFontManager->Lock()) {
|
||||
// TODO: We always get the fallback glyphs from VL Gothic at the
|
||||
// moment, but of course the fallback font should a) contain the
|
||||
// missing glyphs at all and b) be similar to the original font.
|
||||
// So there should be a mapping of some kind to know the most
|
||||
// suitable fallback font.
|
||||
FontStyle* fallbackStyle = gFontManager->GetStyleByIndex(
|
||||
"VL Gothic", 0);
|
||||
if (fallbackStyle != NULL) {
|
||||
ServerFont fallbackFont(*fallbackStyle, font.Size());
|
||||
gFontManager->Unlock();
|
||||
// Force the write-lock on the fallback entry, since we
|
||||
// don't transfer or copy GlyphCache objects from one cache
|
||||
// to the other, but create new glyphs which are stored in
|
||||
// "entry" in any case, which requires the write cache for
|
||||
// sure (used FontEngine of fallbackEntry).
|
||||
fallbackEntry = FontCacheEntryFor(fallbackFont, entry,
|
||||
utf8String, length, fallbackCacheReference, true);
|
||||
// NOTE: We don't care if fallbackEntry is NULL, fetching
|
||||
// alternate glyphs will simply not work.
|
||||
} else
|
||||
gFontManager->Unlock();
|
||||
}
|
||||
|
||||
if (!entry->WriteLock()) {
|
||||
FontCache::Default()->Recycle(entry);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Update the FontCacheReference, since the locking kind changed.
|
||||
cacheReference.SetTo(entry, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
#endif // GLYPH_LAYOUT_ENGINE_H
|
||||
|
@ -146,6 +146,7 @@ public:
|
||||
fRenderer.fRasterizer.reset();
|
||||
fRenderer.fSubpixRasterizer.reset();
|
||||
}
|
||||
|
||||
void Finish(double x, double y)
|
||||
{
|
||||
if (fVector) {
|
||||
|
Loading…
Reference in New Issue
Block a user