diff --git a/src/servers/app/FontCacheEntry.cpp b/src/servers/app/FontCacheEntry.cpp index f796875be1..4bbe53f10e 100644 --- a/src/servers/app/FontCacheEntry.cpp +++ b/src/servers/app/FontCacheEntry.cpp @@ -27,6 +27,9 @@ #include "FontCacheEntry.h" #include + +#include + #include #include @@ -40,88 +43,114 @@ BLocker FontCacheEntry::sUsageUpdateLock("FontCacheEntry usage lock"); class FontCacheEntry::GlyphCachePool { - public: - enum block_size_e { block_size = 16384-16 }; - +public: GlyphCachePool() - : fAllocator(block_size) { - memset(fGlyphs, 0, sizeof(fGlyphs)); } - const GlyphCache* FindGlyph(uint16 glyphCode) const + ~GlyphCachePool() { - unsigned msb = (glyphCode >> 8) & 0xFF; - if (fGlyphs[msb]) - return fGlyphs[msb][glyphCode & 0xFF]; - return 0; + GlyphCache* glyph = fGlyphTable.Clear(true); + while (glyph != NULL) { + GlyphCache* next = glyph->fNext; + delete glyph; + glyph = next; + } } - GlyphCache* CacheGlyph(uint16 glyphCode, unsigned glyphIndex, - unsigned dataSize, glyph_data_type dataType, const agg::rect_i& bounds, + status_t Init() + { + return fGlyphTable.Init(); + } + + const GlyphCache* FindGlyph(uint32 glyphIndex) const + { + return fGlyphTable.Lookup(glyphIndex); + } + + GlyphCache* CacheGlyph(uint32 glyphIndex, + uint32 dataSize, glyph_data_type dataType, const agg::rect_i& bounds, float advanceX, float advanceY, float insetLeft, float insetRight) { - unsigned msb = (glyphCode >> 8) & 0xFF; - if (fGlyphs[msb] == 0) { - fGlyphs[msb] - = (GlyphCache**)fAllocator.allocate(sizeof(GlyphCache*) * 256, - sizeof(GlyphCache*)); - memset(fGlyphs[msb], 0, sizeof(GlyphCache*) * 256); - } - - unsigned lsb = glyphCode & 0xFF; - if (fGlyphs[msb][lsb]) - return NULL; // already exists, do not overwrite - - GlyphCache* glyph - = (GlyphCache*)fAllocator.allocate(sizeof(GlyphCache), - sizeof(double)); - - if (glyph == NULL) + GlyphCache* glyph = fGlyphTable.Lookup(glyphIndex); + if (glyph != NULL) return NULL; - glyph->glyph_index = glyphIndex; - glyph->data = fAllocator.allocate(dataSize); - glyph->data_size = dataSize; - glyph->data_type = dataType; - glyph->bounds = bounds; - glyph->advance_x = advanceX; - glyph->advance_y = advanceY; - glyph->inset_left = insetLeft; - glyph->inset_right = insetRight; + glyph = new(std::nothrow) GlyphCache(glyphIndex, dataSize, dataType, + bounds, advanceX, advanceY, insetLeft, insetRight); + if (glyph == NULL || glyph->data == NULL) { + delete glyph; + return NULL; + } - return fGlyphs[msb][lsb] = glyph; + // TODO: The HashTable grows without bounds. We should cleanup + // older entries from time to time. + + fGlyphTable.Insert(glyph); + + return glyph; } - private: - agg::block_allocator fAllocator; - GlyphCache** fGlyphs[256]; +private: + struct GlyphHashTableDefinition { + typedef uint32 KeyType; + typedef GlyphCache ValueType; + + size_t HashKey(uint32 key) const + { + return key; + } + + size_t Hash(GlyphCache* value) const + { + return value->glyph_index; + } + + bool Compare(uint32 key, GlyphCache* value) const + { + return value->glyph_index == key; + } + + HashTableLink* GetLink(GlyphCache* value) const + { + return value; + } + }; + + typedef OpenHashTable GlyphTable; + + GlyphTable fGlyphTable; }; + // #pragma mark - -// constructor + FontCacheEntry::FontCacheEntry() - : MultiLocker("FontCacheEntry lock") - , Referenceable() - , fGlyphCache(new GlyphCachePool()) - , fEngine() - , fLastUsedTime(LONGLONG_MIN) - , fUseCounter(0) + : + MultiLocker("FontCacheEntry lock"), + Referenceable(), + fGlyphCache(new(std::nothrow) GlyphCachePool()), + fEngine(), + fLastUsedTime(LONGLONG_MIN), + fUseCounter(0) { } -// destructor + FontCacheEntry::~FontCacheEntry() { //printf("~FontCacheEntry()\n"); delete fGlyphCache; } -// Init + bool FontCacheEntry::Init(const ServerFont& font) { + if (fGlyphCache == NULL) + return false; + glyph_rendering renderingType = _RenderTypeFor(font); // TODO: encoding from font @@ -134,17 +163,24 @@ FontCacheEntry::Init(const ServerFont& font) "file %s\n", font.Path()); return false; } + if (fGlyphCache->Init() != B_OK) { + fprintf(stderr, "FontCacheEntry::Init() - failed to allocate " + "GlyphCache table for font file %s\n", font.Path()); + return false; + } + return true; } -// HasGlyphs + bool FontCacheEntry::HasGlyphs(const char* utf8String, ssize_t length) const { uint32 charCode; const char* start = utf8String; while ((charCode = UTF8ToCharCode(&utf8String))) { - if (!fGlyphCache->FindGlyph(charCode)) + uint32 glyphIndex = fEngine.GlyphIndexForGlyphCode(charCode); + if (!fGlyphCache->FindGlyph(glyphIndex)) return false; if (utf8String - start + 1 > length) break; @@ -152,30 +188,31 @@ FontCacheEntry::HasGlyphs(const char* utf8String, ssize_t length) const return true; } -// Glyph + const GlyphCache* -FontCacheEntry::Glyph(uint16 glyphCode) +FontCacheEntry::Glyph(uint32 glyphCode) { - const GlyphCache* glyph = fGlyphCache->FindGlyph(glyphCode); + uint32 glyphIndex = fEngine.GlyphIndexForGlyphCode(glyphCode); + const GlyphCache* glyph = fGlyphCache->FindGlyph(glyphIndex); if (glyph) { return glyph; } else { - if (fEngine.PrepareGlyph(glyphCode)) { - glyph = fGlyphCache->CacheGlyph(glyphCode, - fEngine.GlyphIndex(), fEngine.DataSize(), - fEngine.DataType(), fEngine.Bounds(), + if (fEngine.PrepareGlyph(glyphIndex)) { + glyph = fGlyphCache->CacheGlyph(glyphIndex, + fEngine.DataSize(), fEngine.DataType(), fEngine.Bounds(), fEngine.AdvanceX(), fEngine.AdvanceY(), fEngine.InsetLeft(), fEngine.InsetRight()); - fEngine.WriteGlyphTo(glyph->data); + if (glyph != NULL) + fEngine.WriteGlyphTo(glyph->data); return glyph; } } - return 0; + return NULL; } -// InitAdaptors + void FontCacheEntry::InitAdaptors(const GlyphCache* glyph, double x, double y, GlyphMonoAdapter& monoAdapter, @@ -207,15 +244,15 @@ FontCacheEntry::InitAdaptors(const GlyphCache* glyph, } } -// GetKerning + bool -FontCacheEntry::GetKerning(uint16 glyphCode1, uint16 glyphCode2, +FontCacheEntry::GetKerning(uint32 glyphCode1, uint32 glyphCode2, double* x, double* y) { return fEngine.GetKerning(glyphCode1, glyphCode2, x, y); } -// GenerateSignature + /*static*/ void FontCacheEntry::GenerateSignature(char* signature, size_t signatureSize, const ServerFont& font) @@ -232,7 +269,7 @@ FontCacheEntry::GenerateSignature(char* signature, size_t signatureSize, font.Face(), int(renderingType), font.Size(), hinting, averageWeight); } -// UpdateUsage + void FontCacheEntry::UpdateUsage() { @@ -248,7 +285,6 @@ FontCacheEntry::UpdateUsage() } -// _RenderTypeFor /*static*/ glyph_rendering FontCacheEntry::_RenderTypeFor(const ServerFont& font) { diff --git a/src/servers/app/FontCacheEntry.h b/src/servers/app/FontCacheEntry.h index 954fe481ec..f2e8bddba6 100644 --- a/src/servers/app/FontCacheEntry.h +++ b/src/servers/app/FontCacheEntry.h @@ -12,8 +12,8 @@ // Anti-Grain Geometry - Version 2.4 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) // -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. +// Permission to copy, use, modify, sell and distribute this software +// is granted provided this copyright notice appears in all copies. // This software is provided "as is" without express or implied // warranty, and with no claim as to its suitability for any purpose. // @@ -33,6 +33,8 @@ #include #include +#include + #include "ServerFont.h" #include "FontEngine.h" #include "MultiLocker.h" @@ -40,10 +42,31 @@ #include "Transformable.h" -struct GlyphCache { - unsigned glyph_index; +struct GlyphCache : public HashTableLink { + GlyphCache(uint32 glyphIndex, uint32 dataSize, glyph_data_type dataType, + const agg::rect_i& bounds, float advanceX, float advanceY, + float insetLeft, float insetRight) + : + glyph_index(glyphIndex), + data((uint8*)malloc(dataSize)), + data_size(dataSize), + data_type(dataType), + bounds(bounds), + advance_x(advanceX), + advance_y(advanceY), + inset_left(insetLeft), + inset_right(insetRight) + { + } + + ~GlyphCache() + { + free(data); + } + + uint32 glyph_index; uint8* data; - unsigned data_size; + uint32 data_size; glyph_data_type data_type; agg::rect_i bounds; float advance_x; @@ -80,7 +103,7 @@ class FontCacheEntry : public MultiLocker, public Referenceable { bool HasGlyphs(const char* utf8String, ssize_t glyphCount) const; - const GlyphCache* Glyph(uint16 glyphCode); + const GlyphCache* Glyph(uint32 glyphCode); void InitAdaptors(const GlyphCache* glyph, double x, double y, @@ -89,8 +112,8 @@ class FontCacheEntry : public MultiLocker, public Referenceable { GlyphPathAdapter& pathAdapter, double scale = 1.0); - bool GetKerning(uint16 glyphCode1, - uint16 glyphCode2, double* x, double* y); + bool GetKerning(uint32 glyphCode1, + uint32 glyphCode2, double* x, double* y); static void GenerateSignature(char* signature, size_t signatureSize, diff --git a/src/servers/app/FontEngine.cpp b/src/servers/app/FontEngine.cpp index 7cf4b0373f..dd84d4e0d9 100644 --- a/src/servers/app/FontEngine.cpp +++ b/src/servers/app/FontEngine.cpp @@ -42,14 +42,13 @@ static const bool kFlipY = true; -// int26p6_to_dbl static inline double int26p6_to_dbl(int p) { return double(p) / 64.0; } -// dbl_to_int26p6 + static inline int dbl_to_int26p6(double p) { @@ -57,7 +56,6 @@ dbl_to_int26p6(double p) } -// decompose_ft_outline template bool decompose_ft_outline(const FT_Outline& outline, bool flip_y, PathStorage& path) @@ -289,7 +287,6 @@ decompose_ft_outline(const FT_Outline& outline, bool flip_y, PathStorage& path) } -// decompose_ft_bitmap_mono template void decompose_ft_bitmap_mono(const FT_Bitmap& bitmap, int x, int y, @@ -321,7 +318,6 @@ decompose_ft_bitmap_mono(const FT_Bitmap& bitmap, int x, int y, } -// decompose_ft_bitmap_gray8 template void decompose_ft_bitmap_gray8(const FT_Bitmap& bitmap, int x, int y, @@ -365,7 +361,6 @@ decompose_ft_bitmap_gray8(const FT_Bitmap& bitmap, int x, int y, } -// decompose_ft_bitmap_subpix template void decompose_ft_bitmap_subpix(const FT_Bitmap& bitmap, int x, int y, @@ -557,36 +552,36 @@ decompose_ft_bitmap_subpix(const FT_Bitmap& bitmap, int x, int y, #endif } + // #pragma mark - -// constructor FontEngine::FontEngine() - : fLastError(0) - , fLibraryInitialized(false) - , fLibrary(0) - , fFace(NULL) + : + fLastError(0), + fLibraryInitialized(false), + fLibrary(0), + fFace(NULL), - , fGlyphRendering(glyph_ren_native_gray8) - , fHinting(true) + fGlyphRendering(glyph_ren_native_gray8), + fHinting(true), - , fGlyphIndex(0) - , fDataSize(0) - , fDataType(glyph_data_invalid) - , fBounds(1, 1, 0, 0) - , fAdvanceX(0.0) - , fAdvanceY(0.0) - , fInsetLeft(0.0) - , fInsetRight(0.0) + fDataSize(0), + fDataType(glyph_data_invalid), + fBounds(1, 1, 0, 0), + fAdvanceX(0.0), + fAdvanceY(0.0), + fInsetLeft(0.0), + fInsetRight(0.0), - , fPath() - , fCurves(fPath) - , fScanlineAA() - , fScanlineBin() - , fScanlineSubpix() - , fScanlineStorageAA() - , fScanlineStorageBin() - , fScanlineStorageSubpix() + fPath(), + fCurves(fPath), + fScanlineAA(), + fScanlineBin(), + fScanlineSubpix(), + fScanlineStorageAA(), + fScanlineStorageBin(), + fScanlineStorageSubpix() { fCurves.approximation_scale(4.0); @@ -596,7 +591,6 @@ FontEngine::FontEngine() } -// destructor FontEngine::~FontEngine() { FT_Done_Face(fFace); @@ -606,7 +600,6 @@ FontEngine::~FontEngine() } -// CountFaces unsigned FontEngine::CountFaces() const { @@ -617,13 +610,19 @@ FontEngine::CountFaces() const } -// PrepareGlyph -bool -FontEngine::PrepareGlyph(unsigned glyphCode) +uint32 +FontEngine::GlyphIndexForGlyphCode(uint32 glyphCode) const { - fGlyphIndex = FT_Get_Char_Index(fFace, glyphCode); - fLastError = FT_Load_Glyph(fFace, fGlyphIndex, - (fHinting ? (FT_LOAD_DEFAULT | FT_LOAD_TARGET_LCD) : FT_LOAD_NO_HINTING)); + FT_Get_Char_Index(fFace, glyphCode); +} + + +bool +FontEngine::PrepareGlyph(uint32 glyphIndex) +{ + fLastError = FT_Load_Glyph(fFace, glyphIndex, + (fHinting ? (FT_LOAD_DEFAULT | FT_LOAD_TARGET_LCD) + : FT_LOAD_NO_HINTING)); if (fLastError != 0) return false; @@ -740,8 +739,7 @@ FontEngine::WriteGlyphTo(uint8* data) const // GetKerning bool -FontEngine::GetKerning(unsigned first, unsigned second, - double* x, double* y) +FontEngine::GetKerning(uint32 first, uint32 second, double* x, double* y) { if (fFace && first && second && FT_HAS_KERNING(fFace)) { FT_Vector delta; diff --git a/src/servers/app/FontEngine.h b/src/servers/app/FontEngine.h index b0e5f7e473..b401102b04 100644 --- a/src/servers/app/FontEngine.h +++ b/src/servers/app/FontEngine.h @@ -92,11 +92,10 @@ class FontEngine { { return fHinting; } - bool PrepareGlyph(unsigned glyphCode); + uint32 GlyphIndexForGlyphCode(uint32 glyphCode) const; + bool PrepareGlyph(uint32 glyphIndex); - unsigned GlyphIndex() const - { return fGlyphIndex; } - unsigned DataSize() const + uint32 DataSize() const { return fDataSize; } glyph_data_type DataType() const { return fDataType; } @@ -114,7 +113,7 @@ class FontEngine { void WriteGlyphTo(uint8* data) const; - bool GetKerning(unsigned first, unsigned second, + bool GetKerning(uint32 first, uint32 second, double* x, double* y); private: @@ -132,8 +131,7 @@ class FontEngine { // members needed to generate individual glyphs according // to glyph rendering type - unsigned fGlyphIndex; - unsigned fDataSize; + uint32 fDataSize; glyph_data_type fDataType; agg::rect_i fBounds; double fAdvanceX; diff --git a/src/servers/app/drawing/Jamfile b/src/servers/app/drawing/Jamfile index df50ba0abb..c34276d202 100644 --- a/src/servers/app/drawing/Jamfile +++ b/src/servers/app/drawing/Jamfile @@ -1,7 +1,7 @@ SubDir HAIKU_TOP src servers app drawing ; UseLibraryHeaders agg ; -UsePrivateHeaders app graphics interface shared ; +UsePrivateHeaders app graphics interface kernel shared ; UsePrivateHeaders [ FDirName graphics common ] ; UsePrivateSystemHeaders ; diff --git a/src/servers/app/drawing/Painter/Jamfile b/src/servers/app/drawing/Painter/Jamfile index a36cdf9747..18146324d8 100644 --- a/src/servers/app/drawing/Painter/Jamfile +++ b/src/servers/app/drawing/Painter/Jamfile @@ -4,7 +4,7 @@ SetSubDirSupportedPlatformsBeOSCompatible ; AddSubDirSupportedPlatforms libbe_test ; UseLibraryHeaders agg ; -UsePrivateHeaders app graphics interface shared ; +UsePrivateHeaders app graphics interface kernel shared ; UseHeaders [ FDirName $(HAIKU_TOP) src servers app ] ; UseHeaders [ FDirName $(HAIKU_TOP) src servers app drawing ] ; UseHeaders [ FDirName $(HAIKU_TOP) src servers app drawing Painter drawing_modes ] ;