* 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
@@ -586,7 +586,8 @@ AccelerantHWInterface::ProposeMode(display_mode *candidate, const display_mode *
sem_id sem_id
AccelerantHWInterface::RetraceSemaphore() 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) if (!AccelerantRetraceSemaphore)
return B_UNSUPPORTED; return B_UNSUPPORTED;
+6 -4
View File
@@ -997,9 +997,10 @@ DrawingEngine::DrawString(const char* string, int32 length,
escapement_delta* delta) escapement_delta* delta)
{ {
// TODO: use delta // TODO: use delta
FontLocker locker(d);
BPoint penLocation = pt; BPoint penLocation = pt;
if (Lock()) { if (Lock()) {
FontLocker locker(d);
fPainter->SetDrawState(d, true); fPainter->SetDrawState(d, true);
//bigtime_t now = system_time(); //bigtime_t now = system_time();
// TODO: BoundingBox is quite slow!! Optimizing it will be beneficial. // 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) const DrawState* d, escapement_delta* delta)
{ {
// TODO: use delta // TODO: use delta
FontLocker locker(d);
float width = 0.0; float width = 0.0;
// if (Lock()) { // if (Lock()) {
// NOTE: For now it is enough to block on the // 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 // deadlock in case another thread holds the font
// lock already and then tries to lock the drawing // lock already and then tries to lock the drawing
// engine after it is already locked here (race condition) // engine after it is already locked here (race condition)
FontLocker locker(d);
width = fPainter->StringWidth(string, length, d); width = fPainter->StringWidth(string, length, d);
// Unlock(); // Unlock();
// } // }
@@ -1054,7 +1056,6 @@ float
DrawingEngine::StringWidth(const char* string, int32 length, DrawingEngine::StringWidth(const char* string, int32 length,
const ServerFont& font, escapement_delta* delta) const ServerFont& font, escapement_delta* delta)
{ {
FontLocker locker(&font);
DrawState d; DrawState d;
d.SetFont(font); d.SetFont(font);
return StringWidth(string, length, &d, delta); return StringWidth(string, length, &d, delta);
@@ -1065,6 +1066,8 @@ float
DrawingEngine::StringHeight(const char *string, int32 length, DrawingEngine::StringHeight(const char *string, int32 length,
const DrawState *d) const DrawState *d)
{ {
FontLocker locker(d);
float height = 0.0; float height = 0.0;
// if (Lock()) { // if (Lock()) {
// NOTE: For now it is enough to block on the // 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 // deadlock in case another thread holds the font
// lock already and then tries to lock the drawing // lock already and then tries to lock the drawing
// engine after it is already locked here (race condition) // engine after it is already locked here (race condition)
FontLocker locker(d);
fPainter->SetDrawState(d, true); fPainter->SetDrawState(d, true);
BPoint dummy1(0.0, 0.0); BPoint dummy1(0.0, 0.0);
BPoint dummy2(0.0, 0.0); BPoint dummy2(0.0, 0.0);
@@ -83,12 +83,7 @@ AGGTextRenderer::AGGTextRenderer()
fHinted(true), fHinted(true),
fAntialias(true), fAntialias(true),
fKerning(true), fKerning(true),
fEmbeddedTransformation(), fEmbeddedTransformation()
fFont(),
fLastFamilyAndStyle(0xffffffff),
fLastPointSize(-1.0),
fLastHinted(false)
{ {
fCurves.approximation_scale(2.0); fCurves.approximation_scale(2.0);
fContour.auto_detect_orientation(false); fContour.auto_detect_orientation(false);
@@ -106,37 +101,19 @@ AGGTextRenderer::~AGGTextRenderer()
bool bool
AGGTextRenderer::SetFont(const ServerFont &font) AGGTextRenderer::SetFont(const ServerFont &font)
{ {
bool success = true;
// construct an embedded transformation (rotate & shear) // construct an embedded transformation (rotate & shear)
Transformable transform; fEmbeddedTransformation.Reset();
transform.ShearBy(B_ORIGIN, (90.0 - font.Shear()) * PI / 180.0, 0.0); fEmbeddedTransformation.ShearBy(B_ORIGIN,
transform.RotateBy(B_ORIGIN, -font.Rotation() * PI / 180.0); (90.0 - font.Shear()) * PI / 180.0, 0.0);
fEmbeddedTransformation.RotateBy(B_ORIGIN,
-font.Rotation() * PI / 180.0);
bool load = font.GetFamilyAndStyle() != fLastFamilyAndStyle || agg::glyph_rendering glyphType =
transform != fEmbeddedTransformation; fHinted && fEmbeddedTransformation.IsIdentity() ?
agg::glyph_ren_native_gray8 :
agg::glyph_ren_outline;
if (load) { fFontEngine.load_font(font, glyphType, font.Size());
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;
}
return true; return true;
} }
@@ -145,10 +122,8 @@ AGGTextRenderer::SetFont(const ServerFont &font)
void void
AGGTextRenderer::SetHinting(bool hinting) AGGTextRenderer::SetHinting(bool hinting)
{ {
if (fHinted != hinting) { fHinted = hinting;
fHinted = hinting; fFontEngine.hinting(fEmbeddedTransformation.IsIdentity() && fHinted);
_UpdateSizeAndHinting(fLastPointSize, fEmbeddedTransformation.IsIdentity() && fHinted);
}
} }
// SetAntialiasing // SetAntialiasing
@@ -214,6 +189,8 @@ AGGTextRenderer::RenderString(const char* string,
BPoint transformOffset(0.0, 0.0); BPoint transformOffset(0.0, 0.0);
transform.Transform(&transformOffset); transform.Transform(&transformOffset);
fFontCache.reset();
uint32 charCode; uint32 charCode;
while ((charCode = UTF8ToCharCode(&string)) > 0) { while ((charCode = UTF8ToCharCode(&string)) > 0) {
// line break (not supported by R5) // line break (not supported by R5)
@@ -370,6 +347,8 @@ AGGTextRenderer::StringWidth(const char* string, uint32 length)
const agg::glyph_cache* glyph; const agg::glyph_cache* glyph;
bool firstLoop = true; bool firstLoop = true;
fFontCache.reset();
while ((charCode = UTF8ToCharCode(&string)) > 0) { while ((charCode = UTF8ToCharCode(&string)) > 0) {
glyph = fFontCache.glyph(charCode); glyph = fFontCache.glyph(charCode);
if (glyph) { if (glyph) {
@@ -384,18 +363,3 @@ AGGTextRenderer::StringWidth(const char* string, uint32 length)
return width; 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);
}
}
@@ -50,9 +50,6 @@ class AGGTextRenderer {
uint32 length); uint32 length);
private: private:
void _UpdateSizeAndHinting(float size, bool hinted,
bool force = false);
typedef agg::font_engine_freetype_int32 font_engine_type; typedef agg::font_engine_freetype_int32 font_engine_type;
typedef agg::font_cache_manager<font_engine_type> font_cache_type; typedef agg::font_cache_manager<font_engine_type> font_cache_type;
@@ -79,12 +76,6 @@ class AGGTextRenderer {
bool fAntialias; bool fAntialias;
bool fKerning; bool fKerning;
Transformable fEmbeddedTransformation; // rotated or sheared font? 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 #endif // AGG_TEXT_RENDERER_H
@@ -113,19 +113,19 @@ namespace agg {
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
static unsigned calc_crc32(const unsigned char* buf, unsigned size) // static unsigned calc_crc32(const unsigned char* buf, unsigned size)
{ // {
unsigned crc = (unsigned)~0; // unsigned crc = (unsigned)~0;
const unsigned char* p; // const unsigned char* p;
unsigned len = 0; // unsigned len = 0;
unsigned nr = size; // unsigned nr = size;
//
for (len += nr, p = buf; nr--; ++p) // for (len += nr, p = buf; nr--; ++p)
{ // {
crc = (crc >> 8) ^ crc32tab[(crc ^ *p) & 0xff]; // crc = (crc >> 8) ^ crc32tab[(crc ^ *p) & 0xff];
} // }
return ~crc; // return ~crc;
} // }
//------------------------------------------------------------------------ //------------------------------------------------------------------------
@@ -417,7 +417,7 @@ namespace agg {
//------------------------------------------------------------------------ //------------------------------------------------------------------------
font_engine_freetype_base::~font_engine_freetype_base() font_engine_freetype_base::~font_engine_freetype_base()
{ {
delete [] m_face_ids; // delete [] m_face_ids;
delete [] m_signature; delete [] m_signature;
} }
@@ -432,14 +432,13 @@ namespace agg {
m_face_index(0), m_face_index(0),
m_char_map(FT_ENCODING_NONE), m_char_map(FT_ENCODING_NONE),
m_signature(new char [256+256-16]), m_signature(new char [256+256-16]),
m_height(0), m_size(0),
m_width(0),
m_hinting(true), m_hinting(true),
m_flip_y(false), m_flip_y(false),
m_library(library), m_library(library),
m_face_ids(new unsigned [max_faces]), // m_face_ids(new unsigned [max_faces]),
m_num_faces(0), // m_num_faces(0),
m_max_faces(max_faces), // m_max_faces(max_faces),
m_cur_face(0), m_cur_face(0),
m_resolution(0), m_resolution(0),
m_glyph_rendering(glyph_ren_native_gray8), 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, 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()); m_size = unsigned(size * 64.0);
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_face_ids[m_num_faces] = font.GetFamilyAndStyle(); switch(ren_type) {
m_cur_face = font.GetFTFace(); case glyph_ren_native_mono:
m_cur_id = m_face_ids[m_num_faces]; m_glyph_rendering = glyph_ren_native_mono;
++m_num_faces; 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) // NOTE: Freetype (embedded) transformation not used
{ // (and it would result in update_signature() being called twice
ret = true; // update_transform();
update_char_size();
switch(ren_type) return true;
{
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;
} }
@@ -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); m_size = int(size * 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);
if(m_cur_face) if(m_cur_face)
{ {
update_char_size(); update_char_size();
@@ -684,11 +635,14 @@ namespace agg {
//------------------------------------------------------------------------ //------------------------------------------------------------------------
void font_engine_freetype_base::hinting(bool h) void font_engine_freetype_base::hinting(bool h)
{ {
m_hinting = h; if(m_hinting != h)
if(m_cur_face) {
{ m_hinting = h;
update_signature(); if(m_cur_face)
} {
update_signature();
}
}
} }
//------------------------------------------------------------------------ //------------------------------------------------------------------------
@@ -706,36 +660,46 @@ namespace agg {
{ {
if(m_cur_face) if(m_cur_face)
{ {
unsigned gamma_hash = 0; // NOTE: gamma is fixed for now, so no need to switch
if(m_glyph_rendering == glyph_ren_native_gray8 || // font cache based on gamma
m_glyph_rendering == glyph_ren_agg_mono || // unsigned gamma_hash = 0;
m_glyph_rendering == glyph_ren_agg_gray8) // if(m_glyph_rendering == glyph_ren_native_gray8 ||
{ // m_glyph_rendering == glyph_ren_agg_mono ||
unsigned char gamma_table[rasterizer_scanline_aa<>::aa_num]; // m_glyph_rendering == glyph_ren_agg_gray8)
unsigned i; // {
for(i = 0; i < rasterizer_scanline_aa<>::aa_num; ++i) // unsigned char gamma_table[rasterizer_scanline_aa<>::aa_num];
{ // unsigned i;
gamma_table[i] = m_rasterizer.apply_gamma(i); // for(i = 0; i < rasterizer_scanline_aa<>::aa_num; ++i)
} // {
gamma_hash = calc_crc32(gamma_table, sizeof(gamma_table)); // 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, 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_cur_id,
m_char_map, m_char_map,
m_face_index, m_face_index,
int(m_glyph_rendering), int(m_glyph_rendering),
m_resolution, m_size,
m_height, int(m_hinting));
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_change_stamp; ++m_change_stamp;
} }
} }
@@ -749,16 +713,16 @@ namespace agg {
if(m_resolution) if(m_resolution)
{ {
FT_Set_Char_Size(m_cur_face, FT_Set_Char_Size(m_cur_face,
m_width, // char_width in 1/64th of points m_size, // char_width in 1/64th of points
m_height, // char_height in 1/64th of points m_size, // char_height in 1/64th of points
m_resolution, // horizontal device resolution m_resolution, // horizontal device resolution
m_resolution); // vertical device resolution m_resolution); // vertical device resolution
} }
else else
{ {
FT_Set_Pixel_Sizes(m_cur_face, FT_Set_Pixel_Sizes(m_cur_face,
m_width >> 6, // pixel_width m_size >> 6, // pixel_width
m_height >> 6); // pixel_height m_size >> 6); // pixel_height
} }
update_signature(); update_signature();
} }
@@ -57,11 +57,11 @@ namespace agg
// Set font parameters // Set font parameters
//-------------------------------------------------------------------- //--------------------------------------------------------------------
void resolution(unsigned dpi); 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 attach(const char* file_name);
bool char_map(FT_Encoding map); bool char_map(FT_Encoding map);
bool height(double h); bool size(double size);
bool width(double w);
void transform(const trans_affine& mtx); void transform(const trans_affine& mtx);
void transform(double xx, double xy, double yx, double yy); void transform(double xx, double xy, double yx, double yy);
void hinting(bool h); void hinting(bool h);
@@ -81,8 +81,7 @@ namespace agg
unsigned cur_id() const { return m_cur_id; } unsigned cur_id() const { return m_cur_id; }
unsigned num_faces() const; unsigned num_faces() const;
FT_Encoding char_map() const { return m_char_map; } FT_Encoding char_map() const { return m_char_map; }
double height() const { return double(m_height) / 64.0; } double size() const { return double(m_size) / 64.0; }
double width() const { return double(m_width) / 64.0; }
bool hinting() const { return m_hinting; } bool hinting() const { return m_hinting; }
bool flip_y() const { return m_flip_y; } bool flip_y() const { return m_flip_y; }
@@ -110,7 +109,6 @@ namespace agg
void update_char_size(); void update_char_size();
void update_signature(); void update_signature();
void update_transform(); void update_transform();
int find_face(unsigned face_id) const;
bool m_flag32; bool m_flag32;
int m_change_stamp; int m_change_stamp;
@@ -119,16 +117,12 @@ namespace agg
unsigned m_face_index; unsigned m_face_index;
FT_Encoding m_char_map; FT_Encoding m_char_map;
char* m_signature; char* m_signature;
unsigned m_height; unsigned m_size;
unsigned m_width;
FT_Matrix m_matrix; FT_Matrix m_matrix;
bool m_hinting; bool m_hinting;
bool m_flip_y; bool m_flip_y;
bool m_library_initialized; bool m_library_initialized;
FT_Library m_library; // handle to library 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 FT_Face m_cur_face; // handle to the current face object
int m_resolution; int m_resolution;
glyph_rendering m_glyph_rendering; glyph_rendering m_glyph_rendering;