Work in progress... improvements on font stuff, reverted to using Painter to get the string width. Since it actually uses glyph caching, it is about 20 times faster than the implementation in ServerFont (and a about twice the time as R5). I added a StringWidth method to Painter and AGGTextRenderer which works as correct as ServerFont::StringWidth, which btw was broken, because I mixed up glyph count and byte count...

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@12745 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Stephan Aßmus
2005-05-20 19:52:38 +00:00
parent 38c5a7b7fa
commit 2762b0cecd
9 changed files with 164 additions and 185 deletions
+3
View File
@@ -213,6 +213,9 @@ class Painter {
uint32 length, uint32 length,
const BPoint& baseLine) const; const BPoint& baseLine) const;
float StringWidth( const char* utf8String,
uint32 length) const;
inline BRect ClipRect(const BRect& rect) const inline BRect ClipRect(const BRect& rect) const
{ return _Clipped(rect); } { return _Clipped(rect); }
+5 -1
View File
@@ -1215,7 +1215,11 @@ ServerApp::DispatchMessage(int32 code, LinkMsgReader &msg)
font.SetSize(size); font.SetSize(size);
font.SetSpacing(spacing); font.SetSpacing(spacing);
width = font.StringWidth(string, length); width = desktop->GetDisplayDriver()->StringWidth(string, length, font);
// NOTE: The line below will return the exact same thing. However,
// the line above uses the AGG rendering backend, for which glyph caching
// actually works. It is about 20 times faster!
//width = font.StringWidth(string, length);
replylink.StartMessage(SERVER_TRUE); replylink.StartMessage(SERVER_TRUE);
replylink.Attach<float>(width); replylink.Attach<float>(width);
@@ -1005,8 +1005,7 @@ DisplayDriverPainter::StringWidth(const char *string, int32 length,
float width = 0.0; float width = 0.0;
if (Lock()) { if (Lock()) {
fPainter->SetDrawData(d); fPainter->SetDrawData(d);
static BPoint dummy(0.0, 0.0); width = fPainter->StringWidth(string, length);
width = fPainter->BoundingBox(string, length, dummy).Width();
Unlock(); Unlock();
} }
return width; return width;
-2
View File
@@ -19,6 +19,4 @@ StaticLibrary painter :
font_support/agg_font_freetype.cpp font_support/agg_font_freetype.cpp
font_support/AGGTextRenderer.cpp font_support/AGGTextRenderer.cpp
font_support/FontManager.cpp
font_support/TextRenderer.cpp
; ;
@@ -992,6 +992,13 @@ Painter::BoundingBox(const char* utf8String, uint32 length,
transform, dummy, true); transform, dummy, true);
} }
// StringWidth
float
Painter::StringWidth(const char* utf8String, uint32 length) const
{
return fTextRenderer->StringWidth(utf8String, length);
}
// #pragma mark - // #pragma mark -
// _MakeEmpty // _MakeEmpty
@@ -17,19 +17,8 @@
#include <agg_bounding_rect.h> #include <agg_bounding_rect.h>
#include <agg_conv_segmentator.h> #include <agg_conv_segmentator.h>
#include <agg_conv_transform.h> #include <agg_conv_transform.h>
//#include <agg_rendering_buffer.h>
//#include <agg_scanline_bin.h>
//#include <agg_renderer_mclip.h>
//#include <agg_renderer_scanline.h>
//#include <agg_renderer_primitives.h>
//#include <agg_rasterizer_scanline_aa.h>
//#include <agg_pixfmt_gray8.h>
#include <agg_trans_affine.h> #include <agg_trans_affine.h>
//#include "support.h"
#include "FontManager.h"
#include "AGGTextRenderer.h" #include "AGGTextRenderer.h"
#define FLIP_Y false #define FLIP_Y false
@@ -49,43 +38,18 @@ rect_to_int(BRect r,
// constructor // constructor
AGGTextRenderer::AGGTextRenderer() AGGTextRenderer::AGGTextRenderer()
: TextRenderer(), : fFontEngine(ftlib),
fFontEngine(ftlib),
fFontManager(fFontEngine), fFontManager(fFontEngine),
fCurves(fFontManager.path_adaptor()),
fContour(fCurves),
fUnicodeBuffer((char*)malloc(DEFAULT_UNI_CODE_BUFFER_SIZE)),
fUnicodeBufferSize(DEFAULT_UNI_CODE_BUFFER_SIZE)
{
fCurves.approximation_scale(2.0);
fContour.auto_detect_orientation(false);
fFontEngine.flip_y(FLIP_Y);
}
AGGTextRenderer::AGGTextRenderer(BMessage* archive)
: TextRenderer(archive),
fFontEngine(ftlib),
fFontManager(fFontEngine),
fCurves(fFontManager.path_adaptor()), fCurves(fFontManager.path_adaptor()),
fContour(fCurves), fContour(fCurves),
fUnicodeBuffer((char*)malloc(DEFAULT_UNI_CODE_BUFFER_SIZE)),
fUnicodeBufferSize(DEFAULT_UNI_CODE_BUFFER_SIZE)
{
//printf("AGGTextRenderer::AGGTextRenderer(BMessage*)\n");
fCurves.approximation_scale(2.0);
fContour.auto_detect_orientation(false);
fFontEngine.flip_y(FLIP_Y);
}
// constructor
AGGTextRenderer::AGGTextRenderer(const AGGTextRenderer& from)
: TextRenderer(from),
fFontEngine(ftlib),
fFontManager(fFontEngine),
fCurves(fFontManager.path_adaptor()),
fContour(fCurves),
fUnicodeBuffer((char*)malloc(DEFAULT_UNI_CODE_BUFFER_SIZE)), fUnicodeBuffer((char*)malloc(DEFAULT_UNI_CODE_BUFFER_SIZE)),
fUnicodeBufferSize(DEFAULT_UNI_CODE_BUFFER_SIZE) fUnicodeBufferSize(DEFAULT_UNI_CODE_BUFFER_SIZE),
fHinted(true),
fAntialias(true),
fKerning(true)
{ {
fCurves.approximation_scale(2.0); fCurves.approximation_scale(2.0);
fContour.auto_detect_orientation(false); fContour.auto_detect_orientation(false);
@@ -99,99 +63,60 @@ AGGTextRenderer::~AGGTextRenderer()
free(fUnicodeBuffer); free(fUnicodeBuffer);
} }
// SetTo
void
AGGTextRenderer::SetTo(const TextRenderer* other)
{
const AGGTextRenderer* casted = dynamic_cast<const AGGTextRenderer*>(other);
if (casted) {
TextRenderer::SetTo(other);
}
}
// Archive
status_t
AGGTextRenderer::Archive(BMessage* into, bool deep) const
{
status_t status = TextRenderer::Archive(into, deep);
if (status >= B_OK) {
status = into->AddString("class", "AGGTextRenderer");
}
return status;
}
// SetFont // SetFont
bool bool
AGGTextRenderer::SetFont(const ServerFont &font) AGGTextRenderer::SetFont(const ServerFont &font)
{ {
//printf("AGGTextRenderer::SetFont(%s, %s)\n", font.GetFamily(), font.GetStyle()); bool success = false;
if (fFontEngine.load_font(font, agg::glyph_ren_native_gray8)) { if (font.Rotation() == 0.0 && font.Shear() == 90.0)
// if (fFontEngine.load_font(font, agg::glyph_ren_outline)) { success = fFontEngine.load_font(font, agg::glyph_ren_native_gray8);
return TextRenderer::SetFont(font); else
} else { success = fFontEngine.load_font(font, agg::glyph_ren_outline);
if (!success) {
fprintf(stderr, "font could not be loaded\n"); fprintf(stderr, "font could not be loaded\n");
return false;
} }
return false;
fFontEngine.hinting(fHinted);
SetPointSize(font.Size());
return true;
}
// SetPointSize
void
AGGTextRenderer::SetPointSize(float size)
{
if (size != fFontEngine.height()) {
fFontEngine.height(size);
fFontEngine.width(size);
}
}
// SetHinting
void
AGGTextRenderer::SetHinting(bool hinting)
{
if (fHinted != hinting) {
fHinted = hinting;
fFontEngine.hinting(fHinted);
}
}
// SetAntialiasing
void
AGGTextRenderer::SetAntialiasing(bool antialiasing)
{
fAntialias = antialiasing;
} }
// Unset // Unset
void void
AGGTextRenderer::Unset() AGGTextRenderer::Unset()
{ {
} // TODO ? release some kind of reference count on the ServerFont?
// Family
const char*
AGGTextRenderer::Family() const
{
const char* family = NULL;
if (fFontFilePath) {
entry_ref ref;
if (get_ref_for_path(fFontFilePath, &ref) >= B_OK) {
FontManager* fm = FontManager::Default();
if (fm->Lock()) {
family = fm->FamilyFor(&ref);
fm->Unlock();
}
}
}
return family;
}
// Style
const char*
AGGTextRenderer::Style() const
{
const char* style = NULL;
if (fFontFilePath) {
entry_ref ref;
if (get_ref_for_path(fFontFilePath, &ref) >= B_OK) {
FontManager* fm = FontManager::Default();
if (fm->Lock()) {
style = fm->StyleFor(&ref);
fm->Unlock();
}
}
}
return style;
}
// PostScriptName
const char*
AGGTextRenderer::PostScriptName() const
{
const char* name = NULL;
if (fFontFilePath) {
entry_ref ref;
if (get_ref_for_path(fFontFilePath, &ref) >= B_OK) {
FontManager* fm = FontManager::Default();
if (fm->Lock()) {
name = fm->PostScriptNameFor(&ref);
fm->Unlock();
}
}
}
return name;
} }
// RenderString // RenderString
@@ -207,36 +132,18 @@ AGGTextRenderer::RenderString(const char* string,
{ {
//printf("RenderString(\"%s\", length: %ld, dry: %d)\n", string, length, dryRun); //printf("RenderString(\"%s\", length: %ld, dry: %d)\n", string, length, dryRun);
fFontEngine.hinting(fHinted);
fFontEngine.height((int32)(fPtSize));
fFontEngine.width((int32)(fPtSize));
BRect bounds(0.0, 0.0, -1.0, -1.0); BRect bounds(0.0, 0.0, -1.0, -1.0);
fCurves.approximation_scale(transform.scale()); uint32 glyphCount;
if (_PrepareUnicodeBuffer(string, length, &glyphCount) >= B_OK) {
// use a transformation behind the curves fCurves.approximation_scale(transform.scale());
// (only if glyph->data_type == agg::glyph_data_outline)
// in the pipeline for the rasterizer // use a transformation behind the curves
typedef agg::conv_transform<conv_font_curve_type, agg::trans_affine> conv_font_trans_type; // (only if glyph->data_type == agg::glyph_data_outline)
conv_font_trans_type ftrans(fCurves, transform); // in the pipeline for the rasterizer
typedef agg::conv_transform<conv_font_curve_type, agg::trans_affine> conv_font_trans_type;
int32 srcLength = min_c(length, strlen(string)); conv_font_trans_type ftrans(fCurves, transform);
int32 dstLength = srcLength * 4;
if (dstLength > fUnicodeBufferSize) {
fUnicodeBufferSize = dstLength;
fUnicodeBuffer = (char*)realloc((void*)fUnicodeBuffer, fUnicodeBufferSize);
}
int32 state = 0;
status_t ret;
if ((ret = convert_from_utf8(B_UNICODE_CONVERSION,
string, &srcLength,
fUnicodeBuffer, &dstLength,
&state, B_SUBSTITUTE)) >= B_OK
&& (ret = swap_data(B_INT16_TYPE, fUnicodeBuffer, dstLength,
B_SWAP_BENDIAN_TO_HOST)) >= B_OK) {
uint16* p = (uint16*)fUnicodeBuffer; uint16* p = (uint16*)fUnicodeBuffer;
@@ -251,7 +158,7 @@ AGGTextRenderer::RenderString(const char* string,
BPoint transformOffset(0.0, 0.0); BPoint transformOffset(0.0, 0.0);
transform.Transform(&transformOffset); transform.Transform(&transformOffset);
for (int32 i = 0; i < dstLength / 2; i++) { for (uint32 i = 0; i < glyphCount; i++) {
/* // line break (not supported by R5) /* // line break (not supported by R5)
if (*p == '\n') { if (*p == '\n') {
@@ -337,6 +244,14 @@ AGGTextRenderer::RenderString(const char* string,
} }
if (glyphBounds.IsValid()) if (glyphBounds.IsValid())
bounds = bounds.IsValid() ? bounds | glyphBounds : glyphBounds; bounds = bounds.IsValid() ? bounds | glyphBounds : glyphBounds;
else {
if (bounds.IsValid()) {
bounds.right += glyph->advance_x;
bounds.bottom += glyph->advance_y;
} else {
bounds.Set(0.0, 0.0, glyph->advance_x, glyph->advance_y);
}
}
// increment pen position // increment pen position
advanceX = glyph->advance_x; advanceX = glyph->advance_x;
@@ -350,11 +265,69 @@ AGGTextRenderer::RenderString(const char* string,
nextCharPos->x = x + advanceX; nextCharPos->x = x + advanceX;
nextCharPos->y = y + advanceY; nextCharPos->y = y + advanceY;
} }
} else {
fprintf(stderr, "UTF8 -> Unicode conversion failed: %s\n", strerror(ret));
} }
// return transform.TransformBounds(bounds); // return transform.TransformBounds(bounds);
return bounds; return bounds;
} }
// StringWidth
double
AGGTextRenderer::StringWidth(const char* utf8String, uint32 length)
{
double width = 0.0;
uint32 glyphCount;
if (_PrepareUnicodeBuffer(utf8String, length, &glyphCount) >= B_OK) {
uint16* p = (uint16*)fUnicodeBuffer;
double y = 0.0;
const agg::glyph_cache* glyph;
for (uint32 i = 0; i < glyphCount; i++) {
if ((glyph = fFontManager.glyph(*p))) {
if (i > 0 && fKerning) {
fFontManager.add_kerning(&width, &y);
}
width += glyph->advance_x;
}
++p;
}
}
return width;
}
// _PrepareUnicodeBuffer
status_t
AGGTextRenderer::_PrepareUnicodeBuffer(const char* utf8String,
uint32 length, uint32* glyphCount)
{
int32 srcLength = length;
int32 dstLength = srcLength * 4;
// take care of buffer size
if (dstLength > fUnicodeBufferSize) {
fUnicodeBufferSize = dstLength;
fUnicodeBuffer = (char*)realloc((void*)fUnicodeBuffer, fUnicodeBufferSize);
}
int32 state = 0;
status_t ret = convert_from_utf8(B_UNICODE_CONVERSION,
utf8String, &srcLength,
fUnicodeBuffer, &dstLength,
&state, B_SUBSTITUTE);
if (ret >= B_OK) {
*glyphCount = (uint32)(dstLength / 2);
ret = swap_data(B_INT16_TYPE, fUnicodeBuffer, dstLength,
B_SWAP_BENDIAN_TO_HOST);
} else {
*glyphCount = 0;
fprintf(stderr, "AGGTextRenderer::_PrepareUnicodeBuffer() - UTF8 -> Unicode conversion failed: %s\n", strerror(ret));
}
return ret;
}
@@ -14,25 +14,25 @@
class ServerFont; class ServerFont;
class AGGTextRenderer : public TextRenderer { class AGGTextRenderer {
public: public:
AGGTextRenderer(); AGGTextRenderer();
AGGTextRenderer(BMessage* archive);
AGGTextRenderer(const AGGTextRenderer& from);
virtual ~AGGTextRenderer(); virtual ~AGGTextRenderer();
virtual void SetTo(const TextRenderer* other); bool SetFont(const ServerFont &font);
void Unset();
virtual status_t Archive(BMessage* into, bool deep = true) const; void SetPointSize(float size);
virtual bool SetFont(const ServerFont &font); void SetHinting(bool hinting);
virtual void Unset(); bool Hinting() const
{ return fHinted; }
virtual const char* Family() const; void SetAntialiasing(bool antialiasing);
virtual const char* Style() const; bool Antialiasing() const
virtual const char* PostScriptName() const; { return fAntialias; }
virtual BRect RenderString(const char* utf8String, BRect RenderString(const char* utf8String,
uint32 length, uint32 length,
font_renderer_solid_type* solidRenderer, font_renderer_solid_type* solidRenderer,
font_renderer_bin_type* binRenderer, font_renderer_bin_type* binRenderer,
@@ -41,7 +41,14 @@ class AGGTextRenderer : public TextRenderer {
bool dryRun = false, bool dryRun = false,
BPoint* nextCharPos = NULL); BPoint* nextCharPos = NULL);
double StringWidth(const char* utf8String,
uint32 length);
private: private:
status_t _PrepareUnicodeBuffer(const char* utf8String,
uint32 length,
uint32* glyphCount);
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_manager_type; typedef agg::font_cache_manager<font_engine_type> font_manager_type;
@@ -61,6 +68,10 @@ class AGGTextRenderer : public TextRenderer {
char* fUnicodeBuffer; char* fUnicodeBuffer;
int32 fUnicodeBufferSize; int32 fUnicodeBufferSize;
bool fHinted; // is glyph hinting active?
bool fAntialias; // is anti-aliasing active?
bool fKerning;
}; };
#endif // AGG_TEXT_RENDERER_H #endif // AGG_TEXT_RENDERER_H
@@ -189,19 +189,6 @@ TextRenderer::SetFamilyAndStyle(const char* family, const char* style)
return false; return false;
} }
// SetRotation
void
TextRenderer::SetRotation(float angle)
{
}
// Rotation
float
TextRenderer::Rotation() const
{
return 0.0;
}
// SetPointSize // SetPointSize
void void
TextRenderer::SetPointSize(float size) TextRenderer::SetPointSize(float size)
@@ -31,9 +31,6 @@ class TextRenderer : public BArchivable {
virtual const char* Style() const = 0; virtual const char* Style() const = 0;
virtual const char* PostScriptName() const = 0; virtual const char* PostScriptName() const = 0;
virtual void SetRotation(float angle);
virtual float Rotation() const;
virtual void SetPointSize(float size); virtual void SetPointSize(float size);
float PointSize() const; float PointSize() const;