diff --git a/src/servers/app/FontCacheEntry.cpp b/src/servers/app/FontCacheEntry.cpp index a22a90a01e..b7943cafe1 100644 --- a/src/servers/app/FontCacheEntry.cpp +++ b/src/servers/app/FontCacheEntry.cpp @@ -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 diff --git a/src/servers/app/FontCacheEntry.h b/src/servers/app/FontCacheEntry.h index 879e127ce6..e5da3e3402 100644 --- a/src/servers/app/FontCacheEntry.h +++ b/src/servers/app/FontCacheEntry.h @@ -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, diff --git a/src/servers/app/GlyphLayoutEngine.h b/src/servers/app/GlyphLayoutEngine.h index c8150c6ba8..7717fc22ed 100644 --- a/src/servers/app/GlyphLayoutEngine.h +++ b/src/servers/app/GlyphLayoutEngine.h @@ -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 diff --git a/src/servers/app/drawing/Painter/AGGTextRenderer.cpp b/src/servers/app/drawing/Painter/AGGTextRenderer.cpp index 6fb794d049..7c4a0775c2 100644 --- a/src/servers/app/drawing/Painter/AGGTextRenderer.cpp +++ b/src/servers/app/drawing/Painter/AGGTextRenderer.cpp @@ -146,6 +146,7 @@ public: fRenderer.fRasterizer.reset(); fRenderer.fSubpixRasterizer.reset(); } + void Finish(double x, double y) { if (fVector) {