diff --git a/headers/private/servers/app/Painter.h b/headers/private/servers/app/Painter.h index 9deabe7fcb..eca4176e31 100644 --- a/headers/private/servers/app/Painter.h +++ b/headers/private/servers/app/Painter.h @@ -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); } diff --git a/src/servers/app/ServerApp.cpp b/src/servers/app/ServerApp.cpp index 6c6d1ee7a1..075d5b59fc 100644 --- a/src/servers/app/ServerApp.cpp +++ b/src/servers/app/ServerApp.cpp @@ -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(width); diff --git a/src/servers/app/drawing/DisplayDriverPainter.cpp b/src/servers/app/drawing/DisplayDriverPainter.cpp index f61e18b036..ba8ac58249 100644 --- a/src/servers/app/drawing/DisplayDriverPainter.cpp +++ b/src/servers/app/drawing/DisplayDriverPainter.cpp @@ -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; diff --git a/src/servers/app/drawing/Painter/Jamfile b/src/servers/app/drawing/Painter/Jamfile index bb16e5f954..34d35e0d02 100644 --- a/src/servers/app/drawing/Painter/Jamfile +++ b/src/servers/app/drawing/Painter/Jamfile @@ -19,6 +19,4 @@ StaticLibrary painter : font_support/agg_font_freetype.cpp font_support/AGGTextRenderer.cpp - font_support/FontManager.cpp - font_support/TextRenderer.cpp ; diff --git a/src/servers/app/drawing/Painter/Painter.cpp b/src/servers/app/drawing/Painter/Painter.cpp index 5c0ad0c64a..9f90e46e5e 100644 --- a/src/servers/app/drawing/Painter/Painter.cpp +++ b/src/servers/app/drawing/Painter/Painter.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 diff --git a/src/servers/app/drawing/Painter/font_support/AGGTextRenderer.cpp b/src/servers/app/drawing/Painter/font_support/AGGTextRenderer.cpp index 14e4def7b2..7c945cc205 100644 --- a/src/servers/app/drawing/Painter/font_support/AGGTextRenderer.cpp +++ b/src/servers/app/drawing/Painter/font_support/AGGTextRenderer.cpp @@ -17,19 +17,8 @@ #include #include #include -//#include -//#include -//#include -//#include -//#include -//#include -//#include #include -//#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(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_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_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; +} diff --git a/src/servers/app/drawing/Painter/font_support/AGGTextRenderer.h b/src/servers/app/drawing/Painter/font_support/AGGTextRenderer.h index 92c1b2795a..1ba2e17fbb 100644 --- a/src/servers/app/drawing/Painter/font_support/AGGTextRenderer.h +++ b/src/servers/app/drawing/Painter/font_support/AGGTextRenderer.h @@ -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_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 diff --git a/src/servers/app/drawing/Painter/font_support/TextRenderer.cpp b/src/servers/app/drawing/Painter/font_support/TextRenderer.cpp index 04d53c30c8..d83c57268b 100644 --- a/src/servers/app/drawing/Painter/font_support/TextRenderer.cpp +++ b/src/servers/app/drawing/Painter/font_support/TextRenderer.cpp @@ -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) diff --git a/src/servers/app/drawing/Painter/font_support/TextRenderer.h b/src/servers/app/drawing/Painter/font_support/TextRenderer.h index b983f62bbd..18ccaab693 100644 --- a/src/servers/app/drawing/Painter/font_support/TextRenderer.h +++ b/src/servers/app/drawing/Painter/font_support/TextRenderer.h @@ -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;