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,
const BPoint& baseLine) const;
float StringWidth( const char* utf8String,
uint32 length) const;
inline BRect ClipRect(const BRect& rect) const
{ return _Clipped(rect); }
+5 -1
View File
@@ -1215,7 +1215,11 @@ ServerApp::DispatchMessage(int32 code, LinkMsgReader &msg)
font.SetSize(size);
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.Attach<float>(width);
@@ -1005,8 +1005,7 @@ DisplayDriverPainter::StringWidth(const char *string, int32 length,
float width = 0.0;
if (Lock()) {
fPainter->SetDrawData(d);
static BPoint dummy(0.0, 0.0);
width = fPainter->BoundingBox(string, length, dummy).Width();
width = fPainter->StringWidth(string, length);
Unlock();
}
return width;
-2
View File
@@ -19,6 +19,4 @@ StaticLibrary painter :
font_support/agg_font_freetype.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);
}
// StringWidth
float
Painter::StringWidth(const char* utf8String, uint32 length) const
{
return fTextRenderer->StringWidth(utf8String, length);
}
// #pragma mark -
// _MakeEmpty
@@ -17,19 +17,8 @@
#include <agg_bounding_rect.h>
#include <agg_conv_segmentator.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 "support.h"
#include "FontManager.h"
#include "AGGTextRenderer.h"
#define FLIP_Y false
@@ -49,43 +38,18 @@ rect_to_int(BRect r,
// constructor
AGGTextRenderer::AGGTextRenderer()
: TextRenderer(),
fFontEngine(ftlib),
: fFontEngine(ftlib),
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()),
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)),
fUnicodeBufferSize(DEFAULT_UNI_CODE_BUFFER_SIZE)
fUnicodeBufferSize(DEFAULT_UNI_CODE_BUFFER_SIZE),
fHinted(true),
fAntialias(true),
fKerning(true)
{
fCurves.approximation_scale(2.0);
fContour.auto_detect_orientation(false);
@@ -99,99 +63,60 @@ AGGTextRenderer::~AGGTextRenderer()
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
bool
AGGTextRenderer::SetFont(const ServerFont &font)
{
//printf("AGGTextRenderer::SetFont(%s, %s)\n", font.GetFamily(), font.GetStyle());
if (fFontEngine.load_font(font, agg::glyph_ren_native_gray8)) {
// if (fFontEngine.load_font(font, agg::glyph_ren_outline)) {
return TextRenderer::SetFont(font);
} else {
bool success = false;
if (font.Rotation() == 0.0 && font.Shear() == 90.0)
success = fFontEngine.load_font(font, agg::glyph_ren_native_gray8);
else
success = fFontEngine.load_font(font, agg::glyph_ren_outline);
if (!success) {
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
void
AGGTextRenderer::Unset()
{
}
// 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;
// TODO ? release some kind of reference count on the ServerFont?
}
// RenderString
@@ -207,36 +132,18 @@ AGGTextRenderer::RenderString(const char* string,
{
//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);
fCurves.approximation_scale(transform.scale());
uint32 glyphCount;
if (_PrepareUnicodeBuffer(string, length, &glyphCount) >= B_OK) {
// use a transformation behind the curves
// (only if glyph->data_type == agg::glyph_data_outline)
// in the pipeline for the rasterizer
typedef agg::conv_transform<conv_font_curve_type, agg::trans_affine> conv_font_trans_type;
conv_font_trans_type ftrans(fCurves, transform);
int32 srcLength = min_c(length, strlen(string));
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) {
fCurves.approximation_scale(transform.scale());
// use a transformation behind the curves
// (only if glyph->data_type == agg::glyph_data_outline)
// in the pipeline for the rasterizer
typedef agg::conv_transform<conv_font_curve_type, agg::trans_affine> conv_font_trans_type;
conv_font_trans_type ftrans(fCurves, transform);
uint16* p = (uint16*)fUnicodeBuffer;
@@ -251,7 +158,7 @@ AGGTextRenderer::RenderString(const char* string,
BPoint transformOffset(0.0, 0.0);
transform.Transform(&transformOffset);
for (int32 i = 0; i < dstLength / 2; i++) {
for (uint32 i = 0; i < glyphCount; i++) {
/* // line break (not supported by R5)
if (*p == '\n') {
@@ -337,6 +244,14 @@ AGGTextRenderer::RenderString(const char* string,
}
if (glyphBounds.IsValid())
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
advanceX = glyph->advance_x;
@@ -350,11 +265,69 @@ AGGTextRenderer::RenderString(const char* string,
nextCharPos->x = x + advanceX;
nextCharPos->y = y + advanceY;
}
} else {
fprintf(stderr, "UTF8 -> Unicode conversion failed: %s\n", strerror(ret));
}
// return transform.TransformBounds(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 AGGTextRenderer : public TextRenderer {
class AGGTextRenderer {
public:
AGGTextRenderer();
AGGTextRenderer(BMessage* archive);
AGGTextRenderer(const AGGTextRenderer& from);
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);
virtual void Unset();
void SetHinting(bool hinting);
bool Hinting() const
{ return fHinted; }
virtual const char* Family() const;
virtual const char* Style() const;
virtual const char* PostScriptName() const;
void SetAntialiasing(bool antialiasing);
bool Antialiasing() const
{ return fAntialias; }
virtual BRect RenderString(const char* utf8String,
BRect RenderString(const char* utf8String,
uint32 length,
font_renderer_solid_type* solidRenderer,
font_renderer_bin_type* binRenderer,
@@ -41,7 +41,14 @@ class AGGTextRenderer : public TextRenderer {
bool dryRun = false,
BPoint* nextCharPos = NULL);
double StringWidth(const char* utf8String,
uint32 length);
private:
status_t _PrepareUnicodeBuffer(const char* utf8String,
uint32 length,
uint32* glyphCount);
typedef agg::font_engine_freetype_int32 font_engine_type;
typedef agg::font_cache_manager<font_engine_type> font_manager_type;
@@ -61,6 +68,10 @@ class AGGTextRenderer : public TextRenderer {
char* fUnicodeBuffer;
int32 fUnicodeBufferSize;
bool fHinted; // is glyph hinting active?
bool fAntialias; // is anti-aliasing active?
bool fKerning;
};
#endif // AGG_TEXT_RENDERER_H
@@ -189,19 +189,6 @@ TextRenderer::SetFamilyAndStyle(const char* family, const char* style)
return false;
}
// SetRotation
void
TextRenderer::SetRotation(float angle)
{
}
// Rotation
float
TextRenderer::Rotation() const
{
return 0.0;
}
// SetPointSize
void
TextRenderer::SetPointSize(float size)
@@ -31,9 +31,6 @@ class TextRenderer : public BArchivable {
virtual const char* Style() const = 0;
virtual const char* PostScriptName() const = 0;
virtual void SetRotation(float angle);
virtual float Rotation() const;
virtual void SetPointSize(float size);
float PointSize() const;