* after my last changes to font rendering, it was about 15% slower than

before (although there should be much less lock contention)
* with this change, there is quite a bit of cleanup, text drawing is now
  about 20% faster than before the original changes to font caching,
  mostly due to turning off the kerning feature, which at the moment
  gives absolutely no benefit. The correct way of doing it might be to
  use kerning depending on the provided glyph spacing mode
* removed fPenLocation from Painter, the usage should be more correct now,
  since it is now consistently applied before the coordinate transformation
  from view to screen (also for DrawShape() now, before any view scaling
  and origin offset)
* Painter no longer has it's own instance of a ServerFont, instead it uses
  its AGGTextRenderer instance, which was per Painter again after the
  last change, and not global anymore, made _UpdateFont() useless
* When using GlyphLayoutEngine, it supports a second pass with the same
  FontCacheEntry through the introduction of a FontCacheReference. This
  speeds up DrawString a little, since it needs to calculate the bounding
  box for the string, and then draw the string in a second pass. This is
  now done with only one FontCacheEntry lookup
* I also tried to optimize the on-the-fly conversion of UTF8->CharCode away,
  since it was done four times per DrawString, but surprisingly, it proofed
  to be a slight slowdown.
* introduced a shortcut in DrawingEngine::DrawString() which avoids
  calculating the bounding box, we are now a tiny bit faster to figure
  out that we don't need to draw any string than Dano

In the test environment (drawing to offscreen bitmap and blitting to
screen eventually), text rendering is now about 3.7 times _faster_ than Dano
text rendering (directly to screen), for untransformed text. Unfortunately
I cannot test on the same machine in accelerant using version of the test
environment.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@21822 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Stephan Aßmus 2007-08-04 11:37:16 +00:00
parent 94a48ae276
commit c9d2046fe5
9 changed files with 166 additions and 127 deletions

View File

@ -48,7 +48,7 @@ FontCache::Default()
return &sDefaultInstance;
}
// SetFont
// FontCacheEntryFor
FontCacheEntry*
FontCache::FontCacheEntryFor(const ServerFont& font)
{
@ -62,6 +62,7 @@ FontCache::FontCacheEntryFor(const ServerFont& font)
if (entry) {
// the entry was already there
entry->AddReference();
//printf("FontCacheEntryFor(%ld): %p\n", font.GetFamilyAndStyle(), entry);
return entry;
}
@ -91,6 +92,7 @@ FontCache::FontCacheEntryFor(const ServerFont& font)
return NULL;
}
}
//printf("FontCacheEntryFor(%ld): %p (insert)\n", font.GetFamilyAndStyle(), entry);
entry->AddReference();
return entry;
@ -100,6 +102,7 @@ FontCache::FontCacheEntryFor(const ServerFont& font)
void
FontCache::Recycle(FontCacheEntry* entry)
{
//printf("Recycle(%p)\n", entry);
entry->UpdateUsage();
entry->RemoveReference();
}

View File

@ -212,8 +212,11 @@ FontCacheEntry::GetKerning(uint16 glyphCode1, uint16 glyphCode2,
FontCacheEntry::GenerateSignature(char* signature, const ServerFont& font)
{
glyph_rendering renderingType = glyph_ren_native_gray8;
if (font.Rotation() != 0.0 || font.Shear() != 90.0)
if (font.Rotation() != 0.0 || font.Shear() != 90.0
|| font.Flags() & B_DISABLE_ANTIALIASING
|| font.Size() > 30) {
renderingType = glyph_ren_outline;
}
// TODO: read more of these from the font
FT_Encoding charMap = FT_ENCODING_NONE;

View File

@ -16,6 +16,42 @@
#include "ServerFont.h"
class FontCacheReference {
public:
FontCacheReference()
: fCacheEntry(NULL)
, fWriteLocked(false)
{
}
~FontCacheReference()
{
if (fCacheEntry) {
if (fWriteLocked)
fCacheEntry->WriteUnlock();
else
fCacheEntry->ReadUnlock();
FontCache::Default()->Recycle(
fCacheEntry);
}
}
void SetTo(FontCacheEntry* entry,
bool writeLocked)
{
fCacheEntry = entry;
fWriteLocked = writeLocked;
}
inline FontCacheEntry* Entry() const
{ return fCacheEntry; }
inline bool WriteLocked() const
{ return fWriteLocked; }
private:
FontCacheEntry* fCacheEntry;
bool fWriteLocked;
};
class GlyphLayoutEngine {
public:
@ -26,7 +62,8 @@ class GlyphLayoutEngine {
int32 length,
const escapement_delta* delta = NULL,
bool kerning = true,
uint8 spacing = B_BITMAP_SPACING);
uint8 spacing = B_BITMAP_SPACING,
FontCacheReference* cacheReference = NULL);
static bool IsWhiteSpace(uint32 glyphCode);
@ -62,27 +99,37 @@ inline bool
GlyphLayoutEngine::LayoutGlyphs(GlyphConsumer& consumer,
const ServerFont& font,
const char* utf8String, int32 length,
const escapement_delta* delta, bool kerning, uint8 spacing)
const escapement_delta* delta, bool kerning, uint8 spacing,
FontCacheReference* cacheReference)
{
// TODO: implement spacing modes
FontCache* cache = FontCache::Default();
FontCacheEntry* entry = cache->FontCacheEntryFor(font);
if (!entry || !entry->ReadLock()) {
cache->Recycle(entry);
return false;
FontCacheEntry* entry = NULL;
bool needsWriteLock = false;
if (cacheReference) {
entry = cacheReference->Entry();
needsWriteLock = cacheReference->WriteLocked();
}
bool needsWriteLock
= !entry->HasGlyphs(utf8String, length);
if (needsWriteLock) {
entry->ReadUnlock();
if (!entry->WriteLock()) {
if (!entry) {
FontCache* cache = FontCache::Default();
entry = cache->FontCacheEntryFor(font);
if (!entry || !entry->ReadLock()) {
cache->Recycle(entry);
return false;
}
}
needsWriteLock = !entry->HasGlyphs(utf8String, length);
if (needsWriteLock) {
entry->ReadUnlock();
if (!entry->WriteLock()) {
cache->Recycle(entry);
return false;
}
}
} // else the entry was already used and is still locked
consumer.Start();
@ -107,8 +154,8 @@ GlyphLayoutEngine::LayoutGlyphs(GlyphConsumer& consumer,
continue;
}
if (kerning)
entry->GetKerning(lastCharCode, charCode, &advanceX, &advanceY);
// if (kerning)
// entry->GetKerning(lastCharCode, charCode, &advanceX, &advanceY);
x += advanceX;
y += advanceY;
@ -133,12 +180,18 @@ GlyphLayoutEngine::LayoutGlyphs(GlyphConsumer& consumer,
y += advanceY;
consumer.Finish(x, y);
if (needsWriteLock)
entry->WriteUnlock();
else
entry->ReadUnlock();
cache->Recycle(entry);
if (!cacheReference) {
if (needsWriteLock)
entry->WriteUnlock();
else
entry->ReadUnlock();
FontCache::Default()->Recycle(entry);
} else {
// the reference will take care of locking
if (!cacheReference->Entry())
cacheReference->SetTo(entry, needsWriteLock);
}
return true;
}

View File

@ -201,6 +201,7 @@ string_for_message_code(uint32 code, BString& string)
case AS_FILL_TRIANGLE: string = "AS_FILL_TRIANGLE"; break;
case AS_DRAW_STRING: string = "AS_DRAW_STRING"; break;
case AS_DRAW_STRING_WITH_DELTA: string = "AS_DRAW_STRING_WITH_DELTA"; break;
case AS_SYNC: string = "AS_SYNC"; break;

View File

@ -185,7 +185,7 @@ DrawingEngine::ConstrainClippingRegion(const BRegion* region)
void
DrawingEngine::SetDrawState(const DrawState* state, int32 xOffset, int32 yOffset)
{
fPainter->SetDrawState(state, true, xOffset, yOffset);
fPainter->SetDrawState(state, xOffset, yOffset);
}
@ -665,18 +665,12 @@ DrawingEngine::StrokeLine(const BPoint &start, const BPoint &end,
bool cursorTouched = fGraphicsCard->HideSoftwareCursor(touched);
if (!fPainter->StraightLine(start, end, color.GetColor32())) {
// TODO: all this is quite expensive, but it is currently
// used only for the "gradient" decorator tab buttons
rgb_color previousColor = fPainter->HighColor();
drawing_mode previousMode = fPainter->DrawingMode();
fPainter->SetHighColor(color);
fPainter->SetDrawingMode(B_OP_OVER);
fPainter->StrokeLine(start, end);
fPainter->SetHighColor(previousColor);
fPainter->SetDrawingMode(previousMode);
} else {
fGraphicsCard->Invalidate(touched);
}
fGraphicsCard->Invalidate(touched);
if (cursorTouched)
fGraphicsCard->ShowSoftwareCursor();
}
@ -742,17 +736,12 @@ DrawingEngine::FillRegion(BRegion& r, const RGBColor& color)
BRect frame = r.Frame();
bool cursorTouched = fGraphicsCard->HideSoftwareCursor(frame);
bool doInSoftware = true;
// try hardware optimized version first
if ((fAvailableHWAccleration & HW_ACC_FILL_REGION) != 0
&& frame.Width() * frame.Height() > 100) {
fGraphicsCard->FillRegion(r, color, fSuspendSyncLevel == 0
|| cursorTouched);
doInSoftware = false;
}
if (doInSoftware) {
} else {
int32 count = r.CountRects();
for (int32 i = 0; i < count; i++) {
fPainter->FillRectNoClipping(r.RectAt(i), color.GetColor32());
@ -1037,6 +1026,19 @@ DrawingEngine::DrawString(const char* string, int32 length,
BPoint penLocation = pt;
// try a fast clipping path
float fontSize = fPainter->Font().Size();
BRect clippingFrame = fPainter->ClippingRegion()->Frame();
if (pt.x > clippingFrame.right || pt.y + fontSize < clippingFrame.top
|| pt.y - fontSize > clippingFrame.bottom) {
penLocation.x += StringWidth(string, length, delta);
return penLocation;
}
// use a FontCacheRefernece to speed up the second pass of
// drawing the string
FontCacheReference cacheReference;
//bigtime_t now = system_time();
// TODO: BoundingBox is quite slow!! Optimizing it will be beneficial.
// Cursiously, the DrawString after it is actually faster!?!
@ -1045,7 +1047,8 @@ DrawingEngine::DrawString(const char* string, int32 length,
// in case we don't have one.
// TODO: Watch out about penLocation and use Painter::PenLocation() when
// not using BoundindBox anymore.
BRect b = fPainter->BoundingBox(string, length, pt, &penLocation, delta);
BRect b = fPainter->BoundingBox(string, length, pt, &penLocation, delta,
&cacheReference);
// stop here if we're supposed to render outside of the clipping
b = fPainter->ClipRect(b);
if (b.IsValid()) {
@ -1053,7 +1056,8 @@ DrawingEngine::DrawString(const char* string, int32 length,
bool cursorTouched = fGraphicsCard->HideSoftwareCursor(b);
//now = system_time();
BRect touched = fPainter->DrawString(string, length, pt, delta);
BRect touched = fPainter->DrawString(string, length, pt, delta,
&cacheReference);
//printf("drawing string: %lld µs\n", system_time() - now);
fGraphicsCard->Invalidate(touched);

View File

@ -29,7 +29,8 @@
// constructor
AGGTextRenderer::AGGTextRenderer()
AGGTextRenderer::AGGTextRenderer(renderer_type& solidRenderer,
renderer_bin_type& binRenderer, scanline_unpacked_type& scanline)
: fPathAdaptor()
, fGray8Adaptor()
, fGray8Scanline()
@ -39,6 +40,11 @@ AGGTextRenderer::AGGTextRenderer()
, fCurves(fPathAdaptor)
, fContour(fCurves)
, fSolidRenderer(solidRenderer)
, fBinRenderer(binRenderer)
, fScanline(scanline)
, fRasterizer()
, fHinted(true)
, fAntialias(true)
, fKerning(true)
@ -101,9 +107,6 @@ typedef agg::conv_transform<FontCacheEntry::ContourConverter, Transformable>
class AGGTextRenderer::StringRenderer {
public:
StringRenderer(const IntRect& clippingFrame, bool dryRun,
renderer_type& solidRenderer,
renderer_bin_type& binRenderer,
scanline_unpacked_type& scanline,
FontCacheEntry::TransformedOutline& transformedGlyph,
FontCacheEntry::TransformedContourOutline& transformedContour,
const Transformable& transform,
@ -119,10 +122,6 @@ class AGGTextRenderer::StringRenderer {
, fNextCharPos(nextCharPos)
, fVector(false)
, fSolidRenderer(solidRenderer)
, fBinRenderer(binRenderer)
, fScanline(scanline)
, fTransformedGlyph(transformedGlyph)
, fTransformedContour(transformedContour)
@ -137,8 +136,8 @@ class AGGTextRenderer::StringRenderer {
void Finish(double x, double y)
{
if (fVector) {
agg::render_scanlines(fRenderer.fRasterizer, fScanline,
fSolidRenderer);
agg::render_scanlines(fRenderer.fRasterizer, fRenderer.fScanline,
fRenderer.fSolidRenderer);
}
if (fNextCharPos) {
@ -157,7 +156,8 @@ class AGGTextRenderer::StringRenderer {
{
// "glyphBounds" is the bounds of the glyph transformed
// by the x y location of the glyph along the base line,
// it is therefor yet "untransformed".
// it is therefor yet "untransformed" in case there is an
// embedded transformation.
const agg::rect_i& r = glyph->bounds;
IntRect glyphBounds(r.x1 + x, r.y1 + y - 1,
r.x2 + x + 1, r.y2 + y + 1);
@ -211,12 +211,12 @@ class AGGTextRenderer::StringRenderer {
switch (glyph->data_type) {
case glyph_data_mono:
agg::render_scanlines(fRenderer.fMonoAdaptor,
fRenderer.fMonoScanline, fBinRenderer);
fRenderer.fMonoScanline, fRenderer.fBinRenderer);
break;
case glyph_data_gray8:
agg::render_scanlines(fRenderer.fGray8Adaptor,
fRenderer.fGray8Scanline, fSolidRenderer);
fRenderer.fGray8Scanline, fRenderer.fSolidRenderer);
break;
case glyph_data_outline: {
@ -262,9 +262,6 @@ class AGGTextRenderer::StringRenderer {
BPoint* fNextCharPos;
bool fVector;
renderer_type& fSolidRenderer;
renderer_bin_type& fBinRenderer;
scanline_unpacked_type& fScanline;
FontCacheEntry::TransformedOutline& fTransformedGlyph;
FontCacheEntry::TransformedContourOutline& fTransformedContour;
AGGTextRenderer& fRenderer;
@ -274,14 +271,12 @@ class AGGTextRenderer::StringRenderer {
BRect
AGGTextRenderer::RenderString(const char* string,
uint32 length,
renderer_type* solidRenderer,
renderer_bin_type* binRenderer,
scanline_unpacked_type& scanline,
const BPoint& baseLine,
const BRect& clippingFrame,
bool dryRun,
BPoint* nextCharPos,
const escapement_delta* delta)
const escapement_delta* delta,
FontCacheReference* cacheReference)
{
//printf("RenderString(\"%s\", length: %ld, dry: %d)\n", string, length, dryRun);
@ -303,12 +298,11 @@ AGGTextRenderer::RenderString(const char* string,
transform.Transform(&transformOffset);
StringRenderer renderer(clippingFrame, dryRun,
*solidRenderer, *binRenderer, scanline,
transformedOutline, transformedContourOutline,
transform, transformOffset, nextCharPos, *this);
GlyphLayoutEngine::LayoutGlyphs(renderer, fFont, string, length, delta,
fKerning, B_BITMAP_SPACING);
fKerning, B_BITMAP_SPACING, cacheReference);
return transform.TransformBounds(renderer.Bounds());
}

View File

@ -1,10 +1,11 @@
/*
* Copyright 2005-2006, Stephan Aßmus <superstippi@gmx.de>. All rights reserved.
* Copyright 2005-2007, Stephan Aßmus <superstippi@gmx.de>. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef AGG_TEXT_RENDERER_H
#define AGG_TEXT_RENDERER_H
#include "defines.h"
#include "FontCacheEntry.h"
@ -16,12 +17,18 @@
#include <agg_scanline_u.h>
class FontCacheReference;
class AGGTextRenderer {
public:
AGGTextRenderer();
AGGTextRenderer(renderer_type& solidRenderer,
renderer_bin_type& binRenderer,
scanline_unpacked_type& scanline);
virtual ~AGGTextRenderer();
void SetFont(const ServerFont &font);
inline const ServerFont& Font() const
{ return fFont; }
void SetHinting(bool hinting);
bool Hinting() const
@ -37,14 +44,12 @@ class AGGTextRenderer {
BRect RenderString(const char* utf8String,
uint32 length,
renderer_type* solidRenderer,
renderer_bin_type* binRenderer,
scanline_unpacked_type& scanline,
const BPoint& baseLine,
const BRect& clippingFrame,
bool dryRun = false,
BPoint* nextCharPos = NULL,
const escapement_delta* delta = NULL);
bool dryRun,
BPoint* nextCharPos,
const escapement_delta* delta,
FontCacheReference* cacheReference);
private:
@ -61,6 +66,9 @@ class AGGTextRenderer {
FontCacheEntry::CurveConverter fCurves;
FontCacheEntry::ContourConverter fContour;
renderer_type& fSolidRenderer;
renderer_bin_type& fBinRenderer;
scanline_unpacked_type& fScanline;
rasterizer_type fRasterizer;
// NOTE: the object has it's own rasterizer object
// since it might be using a different gamma setting

View File

@ -72,13 +72,12 @@ Painter::Painter()
fDrawingText(false),
fAlphaSrcMode(B_PIXEL_ALPHA),
fAlphaFncMode(B_ALPHA_OVERLAY),
fPenLocation(0.0, 0.0),
fLineCapMode(B_BUTT_CAP),
fLineJoinMode(B_MITER_JOIN),
fMiterLimit(B_DEFAULT_MITER_LIMIT),
fPatternHandler(),
fTextRenderer()
fTextRenderer(fRenderer, fRendererBin, fUnpackedScanline)
{
fPixelFormat.SetDrawingMode(fDrawingMode, fAlphaSrcMode, fAlphaFncMode, false);
@ -122,21 +121,18 @@ Painter::DetachFromBuffer()
// SetDrawState
void
Painter::SetDrawState(const DrawState* data, bool updateFont,
int32 xOffset, int32 yOffset)
Painter::SetDrawState(const DrawState* data, int32 xOffset, int32 yOffset)
{
// NOTE: The custom clipping in "data" is ignored, because it has already been
// taken into account elsewhere
// NOTE: The custom clipping in "data" is ignored, because it has already
// been taken into account elsewhere
// TODO: optimize "context switch" for speed...
// but for now...
SetPenSize(data->PenSize());
SetPenLocation(data->PenLocation());
if (updateFont)
SetFont(data->Font());
fTextRenderer.SetAntialiasing(!(data->ForceFontAliasing() || data->Font().Flags() & B_DISABLE_ANTIALIASING));
SetFont(data->Font());
fTextRenderer.SetAntialiasing(!(data->ForceFontAliasing()
|| data->Font().Flags() & B_DISABLE_ANTIALIASING));
fSubpixelPrecise = data->SubPixelPrecise();
@ -259,18 +255,11 @@ Painter::SetPattern(const pattern& p, bool drawingText)
}
}
// SetPenLocation
void
Painter::SetPenLocation(const BPoint& location)
{
fPenLocation = location;
}
// SetFont
void
Painter::SetFont(const ServerFont& font)
{
fFont = font;
fTextRenderer.SetFont(font);
}
// #pragma mark - drawing
@ -524,14 +513,14 @@ Painter::DrawShape(const int32& opCount, const uint32* opList,
for (int32 i = 0; i < opCount; i++) {
uint32 op = opList[i] & 0xFF000000;
if (op & OP_MOVETO) {
fPath.move_to(points->x + fPenLocation.x, points->y + fPenLocation.y);
fPath.move_to(points->x, points->y);
points++;
}
if (op & OP_LINETO) {
int32 count = opList[i] & 0x00FFFFFF;
while (count--) {
fPath.line_to(points->x + fPenLocation.x, points->y + fPenLocation.y);
fPath.line_to(points->x, points->y);
points++;
}
}
@ -539,9 +528,9 @@ Painter::DrawShape(const int32& opCount, const uint32* opList,
if (op & OP_BEZIERTO) {
int32 count = opList[i] & 0x00FFFFFF;
while (count) {
fPath.curve4(points[0].x + fPenLocation.x, points[0].y + fPenLocation.y,
points[1].x + fPenLocation.x, points[1].y + fPenLocation.y,
points[2].x + fPenLocation.x, points[2].y + fPenLocation.y);
fPath.curve4(points[0].x, points[0].y,
points[1].x, points[1].y,
points[2].x, points[2].y);
points += 3;
count -= 3;
}
@ -972,7 +961,8 @@ Painter::FillArc(BPoint center, float xRadius, float yRadius,
// DrawString
BRect
Painter::DrawString(const char* utf8String, uint32 length,
BPoint baseLine, const escapement_delta* delta)
BPoint baseLine, const escapement_delta* delta,
FontCacheReference* cacheReference)
{
CHECK_CLIPPING
@ -987,14 +977,10 @@ Painter::DrawString(const char* utf8String, uint32 length,
// make sure that the previous pattern is restored
pattern oldPattern = *fPatternHandler.GetR5Pattern();
SetPattern(B_SOLID_HIGH, true);
// make sure the text renderer is using our font (the global
// instance of the text renderer is used by everyone)
_UpdateFont();
bounds = fTextRenderer.RenderString(utf8String, length,
&fRenderer, &fRendererBin, fUnpackedScanline,
baseLine, fClippingRegion->Frame(), false,
&fPenLocation, delta);
baseLine, fClippingRegion->Frame(), false, NULL, delta,
cacheReference);
SetPattern(oldPattern);
@ -1005,21 +991,17 @@ Painter::DrawString(const char* utf8String, uint32 length,
BRect
Painter::BoundingBox(const char* utf8String, uint32 length,
BPoint baseLine, BPoint* penLocation,
const escapement_delta* delta) const
const escapement_delta* delta,
FontCacheReference* cacheReference) const
{
if (!fSubpixelPrecise) {
baseLine.x = roundf(baseLine.x);
baseLine.y = roundf(baseLine.y);
}
// make sure the text renderer is using our font (the global
// instance of the text renderer is used by everyone)
_UpdateFont();
static BRect dummy;
return fTextRenderer.RenderString(utf8String, length,
&fRenderer, &fRendererBin, fUnpackedScanline,
baseLine, dummy, true, penLocation, delta);
baseLine, dummy, true, penLocation, delta, cacheReference);
}
// StringWidth
@ -1027,7 +1009,7 @@ float
Painter::StringWidth(const char* utf8String, uint32 length,
const escapement_delta* delta)
{
return fFont.StringWidth(utf8String, length, delta);
return Font().StringWidth(utf8String, length, delta);
}
// #pragma mark -
@ -1051,7 +1033,8 @@ Painter::DrawBitmap(const ServerBitmap* bitmap,
bitmap->Height(),
bitmap->BytesPerRow());
_DrawBitmap(srcBuffer, bitmap->ColorSpace(), actualBitmapRect, bitmapRect, viewRect);
_DrawBitmap(srcBuffer, bitmap->ColorSpace(), actualBitmapRect,
bitmapRect, viewRect);
}
return touched;
}
@ -1131,13 +1114,6 @@ Painter::_Clipped(const BRect& rect) const
return BRect(rect);
}
// _UpdateFont
void
Painter::_UpdateFont() const
{
fTextRenderer.SetFont(fFont);
}
// _UpdateDrawingMode
void
Painter::_UpdateDrawingMode(bool drawingText)

View File

@ -27,6 +27,7 @@
class BBitmap;
class BRegion;
class DrawState;
class FontCacheReference;
class RenderingBuffer;
class ServerBitmap;
class ServerFont;
@ -47,7 +48,6 @@ class Painter {
{ return fClippingRegion; }
void SetDrawState(const DrawState* data,
bool updateFont = false,
int32 xOffset = 0,
int32 yOffset = 0);
@ -84,12 +84,9 @@ class Painter {
void SetBlendingMode(source_alpha srcAlpha,
alpha_function alphaFunc);
void SetPenLocation(const BPoint& location);
inline BPoint PenLocation() const
{ return fPenLocation; }
void SetFont(const ServerFont& font);
inline const ServerFont& Font() const
{ return fFont; }
{ return fTextRenderer.Font(); }
// painting functions
@ -178,13 +175,15 @@ class Painter {
BRect DrawString( const char* utf8String,
uint32 length,
BPoint baseLine,
const escapement_delta* delta = NULL);
const escapement_delta* delta,
FontCacheReference* cacheReference = NULL);
BRect BoundingBox( const char* utf8String,
uint32 length,
BPoint baseLine,
BPoint* penLocation,
const escapement_delta* delta = NULL) const;
const escapement_delta* delta,
FontCacheReference* cacheReference = NULL) const;
float StringWidth( const char* utf8String,
uint32 length,
@ -278,14 +277,12 @@ mutable agg::conv_curve<agg::path_storage> fCurve;
bool fDrawingText;
source_alpha fAlphaSrcMode;
alpha_function fAlphaFncMode;
BPoint fPenLocation;
cap_mode fLineCapMode;
join_mode fLineJoinMode;
float fMiterLimit;
PatternHandler fPatternHandler;
ServerFont fFont;
// a class handling rendering and caching of glyphs
// it is setup to load from a specific Freetype supported
// font file which it gets from ServerFont