* cleaned up and optimized a lot setting the font in Painter and

AGGTextRenderer (when switching the DrawState for font stuff)
* removed unused stuff from the font signature generation that
  is used to synchronize the font cache
* finally nailed that bug that made glyphs of the wrong size appear
  within lines of text (the problem basically was that outside code
  messed with the freetype library instance while our glyph cache
  thought the library was last setup by itself)


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@17217 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Stephan Aßmus 2006-04-23 21:50:05 +00:00
parent 9d35303f63
commit 3ca1310ac7
6 changed files with 143 additions and 227 deletions

View File

@ -586,7 +586,8 @@ AccelerantHWInterface::ProposeMode(display_mode *candidate, const display_mode *
sem_id
AccelerantHWInterface::RetraceSemaphore()
{
accelerant_retrace_semaphore AccelerantRetraceSemaphore = (accelerant_retrace_semaphore)fAccelerantHook(B_ACCELERANT_RETRACE_SEMAPHORE, NULL);
accelerant_retrace_semaphore AccelerantRetraceSemaphore =
(accelerant_retrace_semaphore)fAccelerantHook(B_ACCELERANT_RETRACE_SEMAPHORE, NULL);
if (!AccelerantRetraceSemaphore)
return B_UNSUPPORTED;

View File

@ -997,9 +997,10 @@ DrawingEngine::DrawString(const char* string, int32 length,
escapement_delta* delta)
{
// TODO: use delta
FontLocker locker(d);
BPoint penLocation = pt;
if (Lock()) {
FontLocker locker(d);
fPainter->SetDrawState(d, true);
//bigtime_t now = system_time();
// TODO: BoundingBox is quite slow!! Optimizing it will be beneficial.
@ -1034,6 +1035,8 @@ DrawingEngine::StringWidth(const char* string, int32 length,
const DrawState* d, escapement_delta* delta)
{
// TODO: use delta
FontLocker locker(d);
float width = 0.0;
// if (Lock()) {
// NOTE: For now it is enough to block on the
@ -1042,7 +1045,6 @@ DrawingEngine::StringWidth(const char* string, int32 length,
// deadlock in case another thread holds the font
// lock already and then tries to lock the drawing
// engine after it is already locked here (race condition)
FontLocker locker(d);
width = fPainter->StringWidth(string, length, d);
// Unlock();
// }
@ -1054,7 +1056,6 @@ float
DrawingEngine::StringWidth(const char* string, int32 length,
const ServerFont& font, escapement_delta* delta)
{
FontLocker locker(&font);
DrawState d;
d.SetFont(font);
return StringWidth(string, length, &d, delta);
@ -1065,6 +1066,8 @@ float
DrawingEngine::StringHeight(const char *string, int32 length,
const DrawState *d)
{
FontLocker locker(d);
float height = 0.0;
// if (Lock()) {
// NOTE: For now it is enough to block on the
@ -1073,7 +1076,6 @@ DrawingEngine::StringHeight(const char *string, int32 length,
// deadlock in case another thread holds the font
// lock already and then tries to lock the drawing
// engine after it is already locked here (race condition)
FontLocker locker(d);
fPainter->SetDrawState(d, true);
BPoint dummy1(0.0, 0.0);
BPoint dummy2(0.0, 0.0);

View File

@ -83,12 +83,7 @@ AGGTextRenderer::AGGTextRenderer()
fHinted(true),
fAntialias(true),
fKerning(true),
fEmbeddedTransformation(),
fFont(),
fLastFamilyAndStyle(0xffffffff),
fLastPointSize(-1.0),
fLastHinted(false)
fEmbeddedTransformation()
{
fCurves.approximation_scale(2.0);
fContour.auto_detect_orientation(false);
@ -106,37 +101,19 @@ AGGTextRenderer::~AGGTextRenderer()
bool
AGGTextRenderer::SetFont(const ServerFont &font)
{
bool success = true;
// construct an embedded transformation (rotate & shear)
Transformable transform;
transform.ShearBy(B_ORIGIN, (90.0 - font.Shear()) * PI / 180.0, 0.0);
transform.RotateBy(B_ORIGIN, -font.Rotation() * PI / 180.0);
fEmbeddedTransformation.Reset();
fEmbeddedTransformation.ShearBy(B_ORIGIN,
(90.0 - font.Shear()) * PI / 180.0, 0.0);
fEmbeddedTransformation.RotateBy(B_ORIGIN,
-font.Rotation() * PI / 180.0);
bool load = font.GetFamilyAndStyle() != fLastFamilyAndStyle ||
transform != fEmbeddedTransformation;
agg::glyph_rendering glyphType =
fHinted && fEmbeddedTransformation.IsIdentity() ?
agg::glyph_ren_native_gray8 :
agg::glyph_ren_outline;
if (load) {
if (transform.IsIdentity()) {
success = fFontEngine.load_font(font, agg::glyph_ren_native_gray8);
//printf("AGGTextRenderer::SetFont() - native: %d\n", success);
} else {
success = fFontEngine.load_font(font, agg::glyph_ren_outline);
//printf("AGGTextRenderer::SetFont() - outline: %d\n", success);
}
// } else {
//printf("AGGTextRenderer::SetFont() - already loaded\n");
}
fLastFamilyAndStyle = font.GetFamilyAndStyle();
fEmbeddedTransformation = transform;
fFont = font;
_UpdateSizeAndHinting(font.Size(), fEmbeddedTransformation.IsIdentity() && fHinted, load);
if (!success) {
fprintf(stderr, "font could not be loaded\n");
return false;
}
fFontEngine.load_font(font, glyphType, font.Size());
return true;
}
@ -145,10 +122,8 @@ AGGTextRenderer::SetFont(const ServerFont &font)
void
AGGTextRenderer::SetHinting(bool hinting)
{
if (fHinted != hinting) {
fHinted = hinting;
_UpdateSizeAndHinting(fLastPointSize, fEmbeddedTransformation.IsIdentity() && fHinted);
}
fHinted = hinting;
fFontEngine.hinting(fEmbeddedTransformation.IsIdentity() && fHinted);
}
// SetAntialiasing
@ -214,6 +189,8 @@ AGGTextRenderer::RenderString(const char* string,
BPoint transformOffset(0.0, 0.0);
transform.Transform(&transformOffset);
fFontCache.reset();
uint32 charCode;
while ((charCode = UTF8ToCharCode(&string)) > 0) {
// line break (not supported by R5)
@ -370,6 +347,8 @@ AGGTextRenderer::StringWidth(const char* string, uint32 length)
const agg::glyph_cache* glyph;
bool firstLoop = true;
fFontCache.reset();
while ((charCode = UTF8ToCharCode(&string)) > 0) {
glyph = fFontCache.glyph(charCode);
if (glyph) {
@ -384,18 +363,3 @@ AGGTextRenderer::StringWidth(const char* string, uint32 length)
return width;
}
// _UpdateSizeAndHinting
void
AGGTextRenderer::_UpdateSizeAndHinting(float size, bool hinted, bool force)
{
if (force || size != fLastPointSize || hinted != fLastHinted) {
//printf("AGGTextRenderer::_UpdateSizeAndHinting(%.1f, %d, %d)\n", size, hinted, force);
fLastPointSize = size;
fLastHinted = hinted;
fFontEngine.height(size);
fFontEngine.width(size);
fFontEngine.hinting(hinted);
}
}

View File

@ -50,9 +50,6 @@ class AGGTextRenderer {
uint32 length);
private:
void _UpdateSizeAndHinting(float size, bool hinted,
bool force = false);
typedef agg::font_engine_freetype_int32 font_engine_type;
typedef agg::font_cache_manager<font_engine_type> font_cache_type;
@ -79,12 +76,6 @@ class AGGTextRenderer {
bool fAntialias;
bool fKerning;
Transformable fEmbeddedTransformation; // rotated or sheared font?
// caching to avoid loading a font unnecessarily
ServerFont fFont;
uint32 fLastFamilyAndStyle;
float fLastPointSize;
bool fLastHinted;
};
#endif // AGG_TEXT_RENDERER_H

View File

@ -113,19 +113,19 @@ namespace agg {
//------------------------------------------------------------------------------
static unsigned calc_crc32(const unsigned char* buf, unsigned size)
{
unsigned crc = (unsigned)~0;
const unsigned char* p;
unsigned len = 0;
unsigned nr = size;
for (len += nr, p = buf; nr--; ++p)
{
crc = (crc >> 8) ^ crc32tab[(crc ^ *p) & 0xff];
}
return ~crc;
}
// static unsigned calc_crc32(const unsigned char* buf, unsigned size)
// {
// unsigned crc = (unsigned)~0;
// const unsigned char* p;
// unsigned len = 0;
// unsigned nr = size;
//
// for (len += nr, p = buf; nr--; ++p)
// {
// crc = (crc >> 8) ^ crc32tab[(crc ^ *p) & 0xff];
// }
// return ~crc;
// }
//------------------------------------------------------------------------
@ -417,7 +417,7 @@ namespace agg {
//------------------------------------------------------------------------
font_engine_freetype_base::~font_engine_freetype_base()
{
delete [] m_face_ids;
// delete [] m_face_ids;
delete [] m_signature;
}
@ -432,14 +432,13 @@ namespace agg {
m_face_index(0),
m_char_map(FT_ENCODING_NONE),
m_signature(new char [256+256-16]),
m_height(0),
m_width(0),
m_size(0),
m_hinting(true),
m_flip_y(false),
m_library(library),
m_face_ids(new unsigned [max_faces]),
m_num_faces(0),
m_max_faces(max_faces),
// m_face_ids(new unsigned [max_faces]),
// m_num_faces(0),
// m_max_faces(max_faces),
m_cur_face(0),
m_resolution(0),
m_glyph_rendering(glyph_ren_native_gray8),
@ -479,96 +478,60 @@ namespace agg {
}
//------------------------------------------------------------------------
int font_engine_freetype_base::find_face(unsigned face_id) const
{
unsigned i;
for(i = 0; i < m_num_faces; ++i)
{
if(m_face_ids[i] == face_id) return i;
}
return -1;
}
//------------------------------------------------------------------------
bool font_engine_freetype_base::load_font(const ServerFont &font,
glyph_rendering ren_type)
glyph_rendering ren_type,
double size)
{
bool ret = false;
if (m_cur_face == font.GetFTFace()
&& m_cur_id == font.GetFamilyAndStyle()
&& m_glyph_rendering == ren_type
&& m_size == unsigned(size * 64.0)) {
// make sure the freetype lib is in sync too
FT_Set_Pixel_Sizes(m_cur_face,
m_size >> 6, // pixel_width
m_size >> 6); // pixel_height
return true;
}
m_last_error = 0;
m_cur_face = font.GetFTFace();
m_cur_id = font.GetFamilyAndStyle();
int idx = find_face(font.GetFamilyAndStyle());
if(idx >= 0)
{
m_cur_face = font.GetFTFace();
m_cur_id = m_face_ids[idx];
}
else
{
if(m_num_faces >= m_max_faces)
{
memcpy(m_face_ids,
m_face_ids + 1,
(m_max_faces - 1) * sizeof(unsigned));
m_num_faces = m_max_faces - 1;
}
m_size = unsigned(size * 64.0);
m_face_ids[m_num_faces] = font.GetFamilyAndStyle();
m_cur_face = font.GetFTFace();
m_cur_id = m_face_ids[m_num_faces];
++m_num_faces;
switch(ren_type) {
case glyph_ren_native_mono:
m_glyph_rendering = glyph_ren_native_mono;
break;
case glyph_ren_native_gray8:
m_hinting = true;
m_glyph_rendering = glyph_ren_native_gray8;
break;
case glyph_ren_outline:
if(FT_IS_SCALABLE(m_cur_face))
m_glyph_rendering = glyph_ren_outline;
else
m_glyph_rendering = glyph_ren_native_gray8;
break;
case glyph_ren_agg_mono:
if(FT_IS_SCALABLE(m_cur_face))
m_glyph_rendering = glyph_ren_agg_mono;
else
m_glyph_rendering = glyph_ren_native_mono;
break;
case glyph_ren_agg_gray8:
if(FT_IS_SCALABLE(m_cur_face))
m_glyph_rendering = glyph_ren_agg_gray8;
else
m_glyph_rendering = glyph_ren_native_gray8;
break;
}
if(m_last_error == 0)
{
ret = true;
switch(ren_type)
{
case glyph_ren_native_mono:
m_glyph_rendering = glyph_ren_native_mono;
break;
case glyph_ren_native_gray8:
m_glyph_rendering = glyph_ren_native_gray8;
break;
case glyph_ren_outline:
if(FT_IS_SCALABLE(m_cur_face))
{
m_glyph_rendering = glyph_ren_outline;
}
else
{
m_glyph_rendering = glyph_ren_native_gray8;
}
break;
case glyph_ren_agg_mono:
if(FT_IS_SCALABLE(m_cur_face))
{
m_glyph_rendering = glyph_ren_agg_mono;
}
else
{
m_glyph_rendering = glyph_ren_native_mono;
}
break;
case glyph_ren_agg_gray8:
if(FT_IS_SCALABLE(m_cur_face))
{
m_glyph_rendering = glyph_ren_agg_gray8;
}
else
{
m_glyph_rendering = glyph_ren_native_gray8;
}
break;
}
update_transform();
update_char_size();
}
return ret;
// NOTE: Freetype (embedded) transformation not used
// (and it would result in update_signature() being called twice
// update_transform();
update_char_size();
return true;
}
@ -609,21 +572,9 @@ namespace agg {
}
//------------------------------------------------------------------------
bool font_engine_freetype_base::height(double h)
bool font_engine_freetype_base::size(double size)
{
m_height = int(h * 64.0);
if(m_cur_face)
{
update_char_size();
return true;
}
return false;
}
//------------------------------------------------------------------------
bool font_engine_freetype_base::width(double w)
{
m_width = int(w * 64.0);
m_size = int(size * 64.0);
if(m_cur_face)
{
update_char_size();
@ -684,11 +635,14 @@ namespace agg {
//------------------------------------------------------------------------
void font_engine_freetype_base::hinting(bool h)
{
m_hinting = h;
if(m_cur_face)
{
update_signature();
}
if(m_hinting != h)
{
m_hinting = h;
if(m_cur_face)
{
update_signature();
}
}
}
//------------------------------------------------------------------------
@ -706,36 +660,46 @@ namespace agg {
{
if(m_cur_face)
{
unsigned gamma_hash = 0;
if(m_glyph_rendering == glyph_ren_native_gray8 ||
m_glyph_rendering == glyph_ren_agg_mono ||
m_glyph_rendering == glyph_ren_agg_gray8)
{
unsigned char gamma_table[rasterizer_scanline_aa<>::aa_num];
unsigned i;
for(i = 0; i < rasterizer_scanline_aa<>::aa_num; ++i)
{
gamma_table[i] = m_rasterizer.apply_gamma(i);
}
gamma_hash = calc_crc32(gamma_table, sizeof(gamma_table));
}
// NOTE: gamma is fixed for now, so no need to switch
// font cache based on gamma
// unsigned gamma_hash = 0;
// if(m_glyph_rendering == glyph_ren_native_gray8 ||
// m_glyph_rendering == glyph_ren_agg_mono ||
// m_glyph_rendering == glyph_ren_agg_gray8)
// {
// unsigned char gamma_table[rasterizer_scanline_aa<>::aa_num];
// unsigned i;
// for(i = 0; i < rasterizer_scanline_aa<>::aa_num; ++i)
// {
// gamma_table[i] = m_rasterizer.apply_gamma(i);
// }
// gamma_hash = calc_crc32(gamma_table, sizeof(gamma_table));
// }
//
// sprintf(m_signature,
// "%u,%u,%d,%d,%d:%dx%d,%d,%d,%d,%d,%d,%d,%08X",
// m_cur_id,
// m_char_map,
// m_face_index,
// int(m_glyph_rendering),
// m_resolution,
// m_height,
// m_width,
// int(m_matrix.xx),
// int(m_matrix.xy),
// int(m_matrix.yx),
// int(m_matrix.yy),
// int(m_hinting),
// int(m_flip_y),
// gamma_hash);
sprintf(m_signature,
"%u,%u,%d,%d,%d:%dx%d,%d,%d,%d,%d,%d,%d,%08X",
"%u,%u,%d,%d,%d,%d",
m_cur_id,
m_char_map,
m_face_index,
int(m_glyph_rendering),
m_resolution,
m_height,
m_width,
int(m_matrix.xx),
int(m_matrix.xy),
int(m_matrix.yx),
int(m_matrix.yy),
int(m_hinting),
int(m_flip_y),
gamma_hash);
m_size,
int(m_hinting));
++m_change_stamp;
}
}
@ -749,16 +713,16 @@ namespace agg {
if(m_resolution)
{
FT_Set_Char_Size(m_cur_face,
m_width, // char_width in 1/64th of points
m_height, // char_height in 1/64th of points
m_size, // char_width in 1/64th of points
m_size, // char_height in 1/64th of points
m_resolution, // horizontal device resolution
m_resolution); // vertical device resolution
}
else
{
FT_Set_Pixel_Sizes(m_cur_face,
m_width >> 6, // pixel_width
m_height >> 6); // pixel_height
m_size >> 6, // pixel_width
m_size >> 6); // pixel_height
}
update_signature();
}

View File

@ -57,11 +57,11 @@ namespace agg
// Set font parameters
//--------------------------------------------------------------------
void resolution(unsigned dpi);
bool load_font(const ServerFont &font, glyph_rendering ren_type);
bool load_font(const ServerFont &font, glyph_rendering ren_type,
double size);
bool attach(const char* file_name);
bool char_map(FT_Encoding map);
bool height(double h);
bool width(double w);
bool size(double size);
void transform(const trans_affine& mtx);
void transform(double xx, double xy, double yx, double yy);
void hinting(bool h);
@ -81,8 +81,7 @@ namespace agg
unsigned cur_id() const { return m_cur_id; }
unsigned num_faces() const;
FT_Encoding char_map() const { return m_char_map; }
double height() const { return double(m_height) / 64.0; }
double width() const { return double(m_width) / 64.0; }
double size() const { return double(m_size) / 64.0; }
bool hinting() const { return m_hinting; }
bool flip_y() const { return m_flip_y; }
@ -110,7 +109,6 @@ namespace agg
void update_char_size();
void update_signature();
void update_transform();
int find_face(unsigned face_id) const;
bool m_flag32;
int m_change_stamp;
@ -119,16 +117,12 @@ namespace agg
unsigned m_face_index;
FT_Encoding m_char_map;
char* m_signature;
unsigned m_height;
unsigned m_width;
unsigned m_size;
FT_Matrix m_matrix;
bool m_hinting;
bool m_flip_y;
bool m_library_initialized;
FT_Library m_library; // handle to library
unsigned* m_face_ids;
unsigned m_num_faces;
unsigned m_max_faces;
FT_Face m_cur_face; // handle to the current face object
int m_resolution;
glyph_rendering m_glyph_rendering;