2007-08-02 23:10:38 +04:00
|
|
|
/*
|
|
|
|
* Copyright 2007, Haiku. All rights reserved.
|
|
|
|
* Distributed under the terms of the MIT License.
|
|
|
|
*
|
|
|
|
* Authors:
|
|
|
|
* Maxim Shemanarev <mcseemagg@yahoo.com>
|
|
|
|
* Stephan Aßmus <superstippi@gmx.de>
|
2008-07-10 12:26:38 +04:00
|
|
|
* Andrej Spielmann, <andrej.spielmann@seh.ox.ac.uk>
|
2007-08-02 23:10:38 +04:00
|
|
|
*/
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
// Anti-Grain Geometry - Version 2.4
|
|
|
|
// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
|
|
|
|
//
|
2008-07-10 12:26:38 +04:00
|
|
|
// Permission to copy, use, modify, sell and distribute this software
|
|
|
|
// is granted provided this copyright notice appears in all copies.
|
2007-08-02 23:10:38 +04:00
|
|
|
// This software is provided "as is" without express or implied
|
|
|
|
// warranty, and with no claim as to its suitability for any purpose.
|
|
|
|
//
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
// Contact: mcseem@antigrain.com
|
|
|
|
// mcseemagg@yahoo.com
|
|
|
|
// http://www.antigrain.com
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
#include "FontCacheEntry.h"
|
|
|
|
|
|
|
|
#include <string.h>
|
|
|
|
#include <agg_array.h>
|
|
|
|
|
|
|
|
#include <Autolock.h>
|
|
|
|
|
|
|
|
#include "utf8_functions.h"
|
|
|
|
|
2008-08-03 17:40:41 +04:00
|
|
|
#include "GlobalSubpixelSettings.h"
|
2007-08-02 23:10:38 +04:00
|
|
|
|
2008-07-10 12:26:38 +04:00
|
|
|
|
2008-08-03 17:40:41 +04:00
|
|
|
BLocker
|
|
|
|
FontCacheEntry::sUsageUpdateLock("FontCacheEntry usage lock");
|
2007-08-02 23:10:38 +04:00
|
|
|
|
|
|
|
class FontCacheEntry::GlyphCachePool {
|
|
|
|
public:
|
|
|
|
enum block_size_e { block_size = 16384-16 };
|
|
|
|
|
|
|
|
GlyphCachePool()
|
|
|
|
: fAllocator(block_size)
|
|
|
|
{
|
|
|
|
memset(fGlyphs, 0, sizeof(fGlyphs));
|
|
|
|
}
|
|
|
|
|
|
|
|
const GlyphCache* FindGlyph(uint16 glyphCode) const
|
|
|
|
{
|
|
|
|
unsigned msb = (glyphCode >> 8) & 0xFF;
|
2008-07-10 12:26:38 +04:00
|
|
|
if (fGlyphs[msb])
|
2007-08-02 23:10:38 +04:00
|
|
|
return fGlyphs[msb][glyphCode & 0xFF];
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
GlyphCache* CacheGlyph(uint16 glyphCode, unsigned glyphIndex,
|
|
|
|
unsigned dataSize, glyph_data_type dataType, const agg::rect_i& bounds,
|
2007-08-03 05:11:27 +04:00
|
|
|
float advanceX, float advanceY, float insetLeft, float insetRight)
|
2007-08-02 23:10:38 +04:00
|
|
|
{
|
|
|
|
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])
|
2009-01-26 22:25:58 +03:00
|
|
|
return NULL; // already exists, do not overwrite
|
2007-08-02 23:10:38 +04:00
|
|
|
|
|
|
|
GlyphCache* glyph
|
|
|
|
= (GlyphCache*)fAllocator.allocate(sizeof(GlyphCache),
|
|
|
|
sizeof(double));
|
|
|
|
|
2009-01-26 22:25:58 +03:00
|
|
|
if (glyph == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
2007-08-02 23:10:38 +04:00
|
|
|
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;
|
2007-08-03 05:11:27 +04:00
|
|
|
glyph->inset_left = insetLeft;
|
|
|
|
glyph->inset_right = insetRight;
|
2007-08-02 23:10:38 +04:00
|
|
|
|
|
|
|
return fGlyphs[msb][lsb] = glyph;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
agg::block_allocator fAllocator;
|
|
|
|
GlyphCache** fGlyphs[256];
|
|
|
|
};
|
|
|
|
|
|
|
|
// #pragma mark -
|
|
|
|
|
|
|
|
// constructor
|
|
|
|
FontCacheEntry::FontCacheEntry()
|
|
|
|
: MultiLocker("FontCacheEntry lock")
|
|
|
|
, Referenceable()
|
|
|
|
, fGlyphCache(new GlyphCachePool())
|
|
|
|
, fEngine()
|
|
|
|
, fLastUsedTime(LONGLONG_MIN)
|
|
|
|
, fUseCounter(0)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
// destructor
|
|
|
|
FontCacheEntry::~FontCacheEntry()
|
|
|
|
{
|
|
|
|
//printf("~FontCacheEntry()\n");
|
|
|
|
delete fGlyphCache;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Init
|
|
|
|
bool
|
|
|
|
FontCacheEntry::Init(const ServerFont& font)
|
|
|
|
{
|
2007-08-09 04:25:52 +04:00
|
|
|
glyph_rendering renderingType = _RenderTypeFor(font);
|
2007-08-02 23:10:38 +04:00
|
|
|
|
|
|
|
// TODO: encoding from font
|
|
|
|
FT_Encoding charMap = FT_ENCODING_NONE;
|
2008-12-31 21:44:02 +03:00
|
|
|
bool hinting = font.Hinting();
|
2007-08-02 23:10:38 +04:00
|
|
|
|
|
|
|
if (!fEngine.Init(font.Path(), 0, font.Size(), charMap,
|
|
|
|
renderingType, hinting)) {
|
|
|
|
fprintf(stderr, "FontCacheEntry::Init() - some error loading font "
|
|
|
|
"file %s\n", font.Path());
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// HasGlyphs
|
|
|
|
bool
|
2007-08-03 05:11:27 +04:00
|
|
|
FontCacheEntry::HasGlyphs(const char* utf8String, ssize_t length) const
|
2007-08-02 23:10:38 +04:00
|
|
|
{
|
|
|
|
uint32 charCode;
|
|
|
|
const char* start = utf8String;
|
|
|
|
while ((charCode = UTF8ToCharCode(&utf8String))) {
|
|
|
|
if (!fGlyphCache->FindGlyph(charCode))
|
|
|
|
return false;
|
|
|
|
if (utf8String - start + 1 > length)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Glyph
|
|
|
|
const GlyphCache*
|
|
|
|
FontCacheEntry::Glyph(uint16 glyphCode)
|
|
|
|
{
|
|
|
|
const GlyphCache* glyph = fGlyphCache->FindGlyph(glyphCode);
|
|
|
|
if (glyph) {
|
|
|
|
return glyph;
|
|
|
|
} else {
|
|
|
|
if (fEngine.PrepareGlyph(glyphCode)) {
|
|
|
|
glyph = fGlyphCache->CacheGlyph(glyphCode,
|
|
|
|
fEngine.GlyphIndex(), fEngine.DataSize(),
|
|
|
|
fEngine.DataType(), fEngine.Bounds(),
|
2007-08-03 05:11:27 +04:00
|
|
|
fEngine.AdvanceX(), fEngine.AdvanceY(),
|
|
|
|
fEngine.InsetLeft(), fEngine.InsetRight());
|
2007-08-02 23:10:38 +04:00
|
|
|
|
|
|
|
fEngine.WriteGlyphTo(glyph->data);
|
|
|
|
|
|
|
|
return glyph;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// InitAdaptors
|
|
|
|
void
|
|
|
|
FontCacheEntry::InitAdaptors(const GlyphCache* glyph,
|
|
|
|
double x, double y, GlyphMonoAdapter& monoAdapter,
|
|
|
|
GlyphGray8Adapter& gray8Adapter, GlyphPathAdapter& pathAdapter,
|
|
|
|
double scale)
|
|
|
|
{
|
|
|
|
if (!glyph)
|
|
|
|
return;
|
|
|
|
|
|
|
|
switch(glyph->data_type) {
|
|
|
|
case glyph_data_mono:
|
|
|
|
monoAdapter.init(glyph->data, glyph->data_size, x, y);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case glyph_data_gray8:
|
|
|
|
gray8Adapter.init(glyph->data, glyph->data_size, x, y);
|
|
|
|
break;
|
|
|
|
|
2008-07-10 12:26:38 +04:00
|
|
|
case glyph_data_subpix:
|
|
|
|
gray8Adapter.init(glyph->data, glyph->data_size, x, y);
|
|
|
|
break;
|
|
|
|
|
2007-08-02 23:10:38 +04:00
|
|
|
case glyph_data_outline:
|
|
|
|
pathAdapter.init(glyph->data, glyph->data_size, x, y, scale);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetKerning
|
|
|
|
bool
|
|
|
|
FontCacheEntry::GetKerning(uint16 glyphCode1, uint16 glyphCode2,
|
|
|
|
double* x, double* y)
|
|
|
|
{
|
|
|
|
return fEngine.GetKerning(glyphCode1, glyphCode2, x, y);
|
|
|
|
}
|
|
|
|
|
|
|
|
// GenerateSignature
|
|
|
|
/*static*/ void
|
2009-02-28 00:11:05 +03:00
|
|
|
FontCacheEntry::GenerateSignature(char* signature, size_t signatureSize,
|
|
|
|
const ServerFont& font)
|
2007-08-02 23:10:38 +04:00
|
|
|
{
|
2007-08-09 04:25:52 +04:00
|
|
|
glyph_rendering renderingType = _RenderTypeFor(font);
|
2007-08-02 23:10:38 +04:00
|
|
|
|
|
|
|
// TODO: read more of these from the font
|
|
|
|
FT_Encoding charMap = FT_ENCODING_NONE;
|
2008-12-31 21:44:02 +03:00
|
|
|
bool hinting = font.Hinting();
|
2008-08-03 17:40:41 +04:00
|
|
|
uint8 averageWeight = gSubpixelAverageWeight;
|
2007-08-02 23:10:38 +04:00
|
|
|
|
2009-02-28 00:11:05 +03:00
|
|
|
snprintf(signature, signatureSize, "%ld,%u,%d,%d,%.1f,%d,%d",
|
2007-08-02 23:10:38 +04:00
|
|
|
font.GetFamilyAndStyle(), charMap,
|
2008-08-03 17:40:41 +04:00
|
|
|
font.Face(), int(renderingType), font.Size(), hinting, averageWeight);
|
2007-08-02 23:10:38 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// UpdateUsage
|
|
|
|
void
|
|
|
|
FontCacheEntry::UpdateUsage()
|
|
|
|
{
|
|
|
|
// this is a static lock to prevent usage of too many semaphores,
|
|
|
|
// but on the other hand, it is not so nice to be using a lock
|
|
|
|
// here at all
|
|
|
|
// the hope is that the time is so short to hold this lock, that
|
|
|
|
// there is not much contention
|
|
|
|
BAutolock _(sUsageUpdateLock);
|
|
|
|
|
|
|
|
fLastUsedTime = system_time();
|
|
|
|
fUseCounter++;
|
|
|
|
}
|
|
|
|
|
2008-07-10 12:26:38 +04:00
|
|
|
|
2007-08-09 04:25:52 +04:00
|
|
|
// _RenderTypeFor
|
|
|
|
/*static*/ glyph_rendering
|
|
|
|
FontCacheEntry::_RenderTypeFor(const ServerFont& font)
|
|
|
|
{
|
2008-08-03 17:40:41 +04:00
|
|
|
glyph_rendering renderingType = gSubpixelAntialiasing ?
|
|
|
|
glyph_ren_subpix : glyph_ren_native_gray8;
|
|
|
|
|
2007-08-09 04:25:52 +04:00
|
|
|
if (font.Rotation() != 0.0 || font.Shear() != 90.0
|
2007-08-22 18:15:07 +04:00
|
|
|
|| font.FalseBoldWidth() != 0.0
|
2007-08-09 04:25:52 +04:00
|
|
|
|| font.Flags() & B_DISABLE_ANTIALIASING
|
2008-07-10 12:26:38 +04:00
|
|
|
|| font.Size() > 30
|
2008-12-31 21:44:02 +03:00
|
|
|
|| !font.Hinting()) {
|
2007-08-09 04:25:52 +04:00
|
|
|
renderingType = glyph_ren_outline;
|
|
|
|
}
|
2008-08-03 17:40:41 +04:00
|
|
|
|
2007-08-09 04:25:52 +04:00
|
|
|
return renderingType;
|
|
|
|
}
|