Many efficiency improvements to text rendering. Moved stuff from Painter into AGGTextRenderer which didn't belong in Painter. AGGTextRenderer now has an embedded transformation, which expresses the font rotation and (in future) shear settings. Removed direct support for BBitmaps from Painter (supposed to draw ServerBitmaps). Tested drawing of bitmaps other than B_RGB32. (only B_CMAP8 and B_GRAY8 so far, but they work). Right now, these colorspaces are supported by on the fly conversion. So every colorspace supported by BBitmap::ImportBits() should work, which are a lot more than the R5 app_server can display.

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@12815 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Stephan Aßmus 2005-05-25 18:20:45 +00:00
parent 85b226041a
commit 55d6f1b792
8 changed files with 153 additions and 143 deletions

View File

@ -193,11 +193,7 @@ class Painter {
const escapement_delta* delta = NULL);
// bitmaps
void DrawBitmap( const BBitmap* bitmap,
BRect bitmapRect,
BRect viewRect) const;
void DrawBitmap( const ServerBitmap* bitmap,
BRect DrawBitmap( const ServerBitmap* bitmap,
BRect bitmapRect,
BRect viewRect) const;
@ -306,9 +302,6 @@ class Painter {
// font file, it uses the FontManager to locate a file
// by Family and Style
AGGTextRenderer* fTextRenderer;
uint32 fLastFamilyAndStyle;
float fLastRotation;
float fLastShear;
};
// SetHighColor

View File

@ -104,6 +104,8 @@ Desktop::AddDriver(DisplayDriver *driver)
if (driver->Initialize()) {
// TODO: be careful of screen initialization - monitor may not support 640x480
Screen *sc = new Screen(driver, BPoint(640, 480), B_RGB32, fScreenList.CountItems()+1);
// Screen *sc = new Screen(driver, BPoint(1400, 1050), B_RGB32, fScreenList.CountItems()+1);
// Screen *sc = new Screen(driver, BPoint(640, 480), B_CMAP8, fScreenList.CountItems()+1);
// Screen *sc = new Screen(driver, BPoint(640, 480), B_GRAY8, fScreenList.CountItems()+1);
// Screen *sc = new Screen(driver, BPoint(640, 480), B_RGB15, fScreenList.CountItems()+1);

View File

@ -2020,7 +2020,6 @@ void ServerWindow::DispatchGraphicsMessage(int32 code, LinkMsgReader &link)
case AS_DRAW_STRING:
{
DTRACE(("ServerWindow %s: Message AS_DRAW_STRING\n",fName));
char *string;
int32 length;
BPoint location;
@ -2031,9 +2030,10 @@ void ServerWindow::DispatchGraphicsMessage(int32 code, LinkMsgReader &link)
link.Read<escapement_delta>(&delta);
link.ReadString(&string);
if(cl && cl->fLayerData)
desktop->GetDisplayDriver()->DrawString(string,length,cl->ConvertToTop(location),
cl->fLayerData);
if (cl && cl->fLayerData)
desktop->GetDisplayDriver()->DrawString(string, length,
cl->ConvertToTop(location),
cl->fLayerData);
free(string);
break;

View File

@ -387,9 +387,9 @@ DisplayDriverPainter::DrawBitmap(ServerBitmap *bitmap,
fGraphicsCard->HideSoftwareCursor(clipped);
fPainter->SetDrawData(d);
fPainter->DrawBitmap(bitmap, source, dest);
BRect touched = fPainter->DrawBitmap(bitmap, source, dest);
fGraphicsCard->Invalidate(clipped);
fGraphicsCard->Invalidate(touched);
fGraphicsCard->ShowSoftwareCursor();
Unlock();
@ -969,7 +969,8 @@ DisplayDriverPainter::DrawString(const char *string, const int32 &length,
{
static DrawData d;
d.SetHighColor(color);
// TODO: Why is escapement_delta a part of the state stack?
if (delta)
d.SetEscapementDelta(*delta);
@ -985,21 +986,23 @@ DisplayDriverPainter::DrawString(const char *string, const int32 &length,
fPainter->SetDrawData(d);
//bigtime_t now = system_time();
// TODO: BoundingBox is quite slow!! Optimizing it will be beneficial.
// Cursiously, the actual DrawString after it is actually faster!?!
// Cursiously, the DrawString after it is actually faster!?!
// TODO: make the availability of the hardware cursor part of the
// HW acceleration flags and skip all calculations for HideSoftwareCursor
// in case we don't need one.
// in case we don't have one.
BRect b = fPainter->BoundingBox(string, length, pt);
// stop here if we're supposed to render outside of the clipping
if (fPainter->ClippingRegion()->Frame().Intersects(b)) {
//printf("bounding box '%s': %lld µs\n", string, system_time() - now);
fGraphicsCard->HideSoftwareCursor(b);
fGraphicsCard->HideSoftwareCursor(b);
//now = system_time();
BRect touched = fPainter->DrawString(string, length, pt);
BRect touched = fPainter->DrawString(string, length, pt);
//printf("drawing string: %lld µs\n", system_time() - now);
fGraphicsCard->Invalidate(touched);
fGraphicsCard->ShowSoftwareCursor();
fGraphicsCard->Invalidate(touched);
fGraphicsCard->ShowSoftwareCursor();
}
Unlock();
}
}

View File

@ -80,10 +80,7 @@ Painter::Painter()
fPenLocation(0.0, 0.0),
fDrawingModeFactory(new DrawingModeFactory()),
fPatternHandler(new PatternHandler()),
fTextRenderer(new AGGTextRenderer()),
fLastFamilyAndStyle(0),
fLastRotation(0.0),
fLastShear(90.0)
fTextRenderer(new AGGTextRenderer())
{
if (fontserver && fontserver->GetSystemPlain())
fFont = *fontserver->GetSystemPlain();
@ -883,25 +880,14 @@ Painter::DrawString(const char* utf8String, uint32 length,
if (fBuffer) {
Transformable transform;
// TODO: convert BFont::Shear(), which is in degrees 45°...135° to whatever AGG is using
// transform.ShearBy(B_ORIGIN, fFont.Shear(), 0.0);
transform.RotateBy(B_ORIGIN, -fFont.Rotation());
transform.TranslateBy(baseLine);
BRect clippingFrame;
if (fClippingRegion)
clippingFrame = fClippingRegion->Frame();
bounds = fTextRenderer->RenderString(utf8String,
length,
fFontRendererSolid,
fFontRendererBin,
transform,
clippingFrame,
baseLine,
fClippingRegion->Frame(),
false,
&fPenLocation);
transform.Transform(&fPenLocation);
}
return _Clipped(bounds);
}
@ -926,31 +912,15 @@ Painter::DrawString(const char* utf8String, BPoint baseLine,
// #pragma mark -
// DrawBitmap
void
Painter::DrawBitmap(const BBitmap* bitmap,
BRect bitmapRect, BRect viewRect) const
{
if (bitmap && bitmap->IsValid()) {
// the native bitmap coordinate system
// (can have left top corner offset)
BRect actualBitmapRect(bitmap->Bounds());
agg::rendering_buffer srcBuffer;
srcBuffer.attach((uint8*)bitmap->Bits(),
(uint32)actualBitmapRect.IntegerWidth() + 1,
(uint32)actualBitmapRect.IntegerHeight() + 1,
bitmap->BytesPerRow());
_DrawBitmap(srcBuffer, bitmap->ColorSpace(), actualBitmapRect, bitmapRect, viewRect);
}
}
// DrawBitmap
void
BRect
Painter::DrawBitmap(const ServerBitmap* bitmap,
BRect bitmapRect, BRect viewRect) const
{
if (bitmap && bitmap->InitCheck()) {
CHECK_CLIPPING
BRect touched = _Clipped(viewRect);
if (bitmap && bitmap->InitCheck() && touched.IsValid()) {
// the native bitmap coordinate system
BRect actualBitmapRect(bitmap->Bounds());
@ -962,6 +932,7 @@ Painter::DrawBitmap(const ServerBitmap* bitmap,
_DrawBitmap(srcBuffer, bitmap->ColorSpace(), actualBitmapRect, bitmapRect, viewRect);
}
return touched;
}
// #pragma mark -
@ -1004,15 +975,12 @@ BRect
Painter::BoundingBox(const char* utf8String, uint32 length,
const BPoint& baseLine) const
{
Transformable transform;
transform.TranslateBy(baseLine);
static BRect dummy;
return fTextRenderer->RenderString(utf8String,
length,
fFontRendererSolid,
fFontRendererBin,
transform, dummy, true);
baseLine, dummy, true);
}
// StringWidth
@ -1106,20 +1074,7 @@ Painter::_UpdateFont()
if (fFont.InitCheck() < B_OK)
return;
if (fLastFamilyAndStyle != fFont.GetFamilyAndStyle()
|| fFont.Rotation() != fLastRotation || fFont.Shear() != fLastShear) {
if (fTextRenderer->SetFont(fFont)) {
fLastFamilyAndStyle = fFont.GetFamilyAndStyle();
fLastRotation = fFont.Rotation();
fLastShear = fFont.Shear();
} else {
fprintf(stderr, "unable to set font\n");
}
} else {
// just update the size
fTextRenderer->SetPointSize(fFont.Size());
}
fTextRenderer->SetFont(fFont);
}
// _UpdateLineWidth
@ -1176,7 +1131,6 @@ Painter::_UpdateDrawingMode()
void
Painter::_SetRendererColor(const rgb_color& color) const
{
if (fOutlineRenderer)
#if ALIASED_DRAWING
fOutlineRenderer->line_color(agg::rgba(color.red / 255.0,
@ -1340,14 +1294,13 @@ Painter::_DrawBitmap(const agg::rendering_buffer& srcBuffer, color_space format,
_DrawBitmap32(srcBuffer, actualBitmapRect, bitmapRect, viewRect);
break;
default:
fprintf(stderr, "Painter::_DrawBitmap() - non-native colorspace: %d\n", format);
#ifdef __HAIKU__
//printf("Painter::_DrawBitmap() - non-native colorspace: %d\n", format);
// TODO: this is only a temporary implementation,
// to really handle other colorspaces, one would
// rather do the conversion with much less overhead,
// for example in the nn filter (hm), or in the
// scanline generator
BBitmap temp(actualBitmapRect, 0, B_RGB32);
// scanline generator (better)
BBitmap temp(actualBitmapRect, B_BITMAP_NO_SERVER_LINK, B_RGB32);
status_t err = temp.ImportBits(srcBuffer.buf(),
srcBuffer.height() * srcBuffer.stride(),
srcBuffer.stride(),
@ -1360,9 +1313,8 @@ fprintf(stderr, "Painter::_DrawBitmap() - non-native colorspace: %d\n", format);
temp.BytesPerRow());
_DrawBitmap32(convertedBuffer, actualBitmapRect, bitmapRect, viewRect);
} else {
fprintf(stderr, "Painter::_DrawBitmap() - colorspace conversion failed: %s\n", strerror(err));
printf("Painter::_DrawBitmap() - colorspace conversion failed: %s\n", strerror(err));
}
#endif // __HAIKU__
break;
}
}
@ -1373,10 +1325,17 @@ Painter::_DrawBitmap32(const agg::rendering_buffer& srcBuffer,
BRect actualBitmapRect, BRect bitmapRect, BRect viewRect) const
{
typedef agg::span_allocator<agg::rgba8> span_alloc_type;
// pipeline for non-scaled bitmaps
//typedef agg::span_generator<agg::rgba8, span_alloc_type> span_gen_type;
//typedef agg::renderer_scanline_aa<renderer_base, span_gen_type> image_renderer_type;
// pipeline for scaled bitmaps
typedef agg::span_interpolator_linear<> interpolator_type;
typedef agg::span_image_filter_rgba32_nn<agg::order_bgra32,
interpolator_type> span_gen_type;
typedef agg::renderer_scanline_aa<renderer_base, span_gen_type> image_renderer_type;
interpolator_type> scaled_span_gen_type;
typedef agg::renderer_scanline_aa<renderer_base, scaled_span_gen_type> scaled_image_renderer_type;
if (bitmapRect.IsValid() && bitmapRect.Intersects(actualBitmapRect)
&& viewRect.IsValid()) {
@ -1429,10 +1388,6 @@ typedef agg::renderer_scanline_aa<renderer_base, span_gen_type> image_renderer_t
span_alloc_type sa;
interpolator_type interpolator(imgMatrix);
span_gen_type sg(sa, srcBuffer, agg::rgba(0, 0, 0, 0), interpolator);
image_renderer_type ri(*fBaseRenderer, sg);
agg::rasterizer_scanline_aa<> pf;
agg::scanline_u8 sl;
@ -1447,7 +1402,22 @@ typedef agg::renderer_scanline_aa<renderer_base, span_gen_type> image_renderer_t
agg::conv_transform<agg::path_storage> tr(path, srcMatrix);
pf.add_path(tr);
agg::render_scanlines(pf, sl, ri);
// if (xScale != 1.0 || yScale != 1.0) {
//printf("scaled\n");
scaled_span_gen_type sg(sa, srcBuffer, agg::rgba(0, 0, 0, 0), interpolator);
scaled_image_renderer_type ri(*fBaseRenderer, sg);
agg::render_scanlines(pf, sl, ri);
/* } else {
// TODO: Does not even compile, find out how to construct a pipeline without
// scaling
printf("non scaled scaled\n");
span_gen_type sg(sa);
image_renderer_type ri(*fBaseRenderer, sg);
agg::render_scanlines(pf, sl, ri);
}*/
}
}

View File

@ -74,7 +74,7 @@ namespace agg
m_curr_cb = 0;
if(m_region && m_region->CountRects() > 0)
{
BRect cb = m_region->RectAt(0);
clipping_rect cb = m_region->RectAtInt(0);
m_ren.clip_box_naked(cb.left, cb.top, cb.right, cb.bottom);
}
else
@ -86,7 +86,7 @@ namespace agg
{
if(m_region && (int)(++m_curr_cb) < m_region->CountRects())
{
BRect cb = m_region->RectAt(m_curr_cb);
clipping_rect cb = m_region->RectAtInt(m_curr_cb);
m_ren.clip_box_naked(cb.left, cb.top, cb.right, cb.bottom);
return true;
}
@ -107,16 +107,18 @@ namespace agg
{
m_region = region;
if (m_region) {
BRect r = m_region->Frame();
if (r.IsValid()) {
r = r & BRect(0, 0, width() - 1, height() - 1);
// a BRegion actually keeps integer clipping_rects
// so just converting to int without rounding is
// fine
if(r.left < m_bounds.x1) m_bounds.x1 = (int)r.left;
if(r.top < m_bounds.y1) m_bounds.y1 = (int)r.top;
if(r.right > m_bounds.x2) m_bounds.x2 = (int)r.right;
if(r.bottom > m_bounds.y2) m_bounds.y2 = (int)r.bottom;
clipping_rect r = m_region->FrameInt();
if (r.left <= r.right && r.top <= r.bottom) {
// clip rect to frame buffer bounds
r.left = max_c(0, r.left);
r.top = max_c(0, r.top);
r.right = min_c((int)width() - 1, r.right);
r.bottom = min_c((int)height() - 1, r.bottom);
if(r.left < m_bounds.x1) m_bounds.x1 = r.left;
if(r.top < m_bounds.y1) m_bounds.y1 = r.top;
if(r.right > m_bounds.x2) m_bounds.x2 = r.right;
if(r.bottom > m_bounds.y2) m_bounds.y2 = r.bottom;
}
}
}

View File

@ -56,7 +56,12 @@ AGGTextRenderer::AGGTextRenderer()
fHinted(true),
fAntialias(true),
fKerning(true)
fKerning(true),
fEmbeddedTransformation(),
fLastFamilyAndStyle(0),
fLastPointSize(-1.0),
fLastHinted(false)
{
fCurves.approximation_scale(2.0);
fContour.auto_detect_orientation(false);
@ -74,18 +79,30 @@ AGGTextRenderer::~AGGTextRenderer()
bool
AGGTextRenderer::SetFont(const ServerFont &font)
{
bool success = false;
if (font.Rotation() == 0.0 && font.Shear() == 90.0) {
bool success = true;
// construct an embedded transformation (rotate & shear)
Transformable transform;
// TODO: convert BFont::Shear(), which is in degrees 45°...135° to whatever AGG is using
// transform.ShearBy(B_ORIGIN, fFont.Shear(), 0.0);
transform.RotateBy(B_ORIGIN, -font.Rotation());
bool load = font.GetFamilyAndStyle() != fLastFamilyAndStyle ||
transform != fEmbeddedTransformation;
if (load) {
if (transform.IsIdentity()) {
//printf("AGGTextRenderer::SetFont() - native\n");
success = fFontEngine.load_font(font, agg::glyph_ren_native_gray8);
fFontEngine.hinting(fHinted);
} else {
success = fFontEngine.load_font(font, agg::glyph_ren_native_gray8);
} else {
//printf("AGGTextRenderer::SetFont() - outline\n");
success = fFontEngine.load_font(font, agg::glyph_ren_outline);
fFontEngine.hinting(false);
success = fFontEngine.load_font(font, agg::glyph_ren_outline);
}
}
SetPointSize(font.Size());
fLastFamilyAndStyle = font.GetFamilyAndStyle();
fEmbeddedTransformation = transform;
_UpdateSizeAndHinting(font.Size(), fEmbeddedTransformation.IsIdentity() && fHinted, load);
if (!success) {
fprintf(stderr, "font could not be loaded\n");
@ -95,23 +112,13 @@ AGGTextRenderer::SetFont(const ServerFont &font)
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);
_UpdateSizeAndHinting(fLastPointSize, fEmbeddedTransformation.IsIdentity() && fHinted);
}
}
@ -135,26 +142,23 @@ AGGTextRenderer::RenderString(const char* string,
uint32 length,
font_renderer_solid_type* solidRenderer,
font_renderer_bin_type* binRenderer,
const Transformable& transform,
BRect clippingFrame,
const BPoint& baseLine,
const BRect& clippingFrame,
bool dryRun,
BPoint* nextCharPos)
{
//printf("RenderString(\"%s\", length: %ld, dry: %d)\n", string, length, dryRun);
// ToDo: this is a temporary fix for some drawing problems
// Please remove when the real cause has been found :-)
float size = fFontEngine.height();
fFontEngine.height(size);
fFontEngine.width(size);
fFontEngine.hinting(fHinted);
// "bounds" will track the bounding box arround all glyphs that are actually drawn
// it will be calculated in untransformed coordinates within the loop and then
// it is transformed to the real location at the exit of the function.
BRect bounds(0.0, 0.0, -1.0, -1.0);
Transformable transform(fEmbeddedTransformation);
transform.TranslateBy(baseLine);
uint32 glyphCount;
if (_PrepareUnicodeBuffer(string, length, &glyphCount) >= B_OK) {
fCurves.approximation_scale(transform.scale());
@ -194,7 +198,6 @@ AGGTextRenderer::RenderString(const char* string,
const agg::glyph_cache* glyph = fFontManager.glyph(*p);
if (glyph) {
if (i > 0 && fKerning) {
fFontManager.add_kerning(&advanceX, &advanceY);
}
@ -240,7 +243,7 @@ AGGTextRenderer::RenderString(const char* string,
glyphBounds = transform.TransformBounds(glyphBounds);
}
if (clippingFrame.Intersects(glyphBounds)) {
if (true /*clippingFrame.Intersects(glyphBounds)*/) {
switch (glyph->data_type) {
case agg::glyph_data_mono:
agg::render_scanlines(fFontManager.mono_adaptor(),
@ -297,6 +300,15 @@ AGGTextRenderer::RenderString(const char* string,
// increment pen position
advanceX = glyph->advance_x;
advanceY = glyph->advance_y;
} else {
if (*p < 128) {
char c[2];
c[0] = (uint8)*p;
c[1] = 0;
fprintf(stderr, "failed to load glyph for '%s'\n", c);
} else {
fprintf(stderr, "failed to load glyph for %d\n", *p);
}
}
++p;
}
@ -305,6 +317,8 @@ AGGTextRenderer::RenderString(const char* string,
if (nextCharPos) {
nextCharPos->x = x + advanceX;
nextCharPos->y = y + advanceY;
transform.Transform(nextCharPos);
}
}
@ -371,3 +385,19 @@ AGGTextRenderer::_PrepareUnicodeBuffer(const char* utf8String,
return ret;
}
// _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);
}
}

View File

@ -22,8 +22,6 @@ class AGGTextRenderer {
bool SetFont(const ServerFont &font);
void Unset();
void SetPointSize(float size);
void SetHinting(bool hinting);
bool Hinting() const
{ return fHinted; }
@ -32,12 +30,16 @@ class AGGTextRenderer {
bool Antialiasing() const
{ return fAntialias; }
void SetKerning(bool kerning);
bool Kerning() const
{ return fKerning; }
BRect RenderString(const char* utf8String,
uint32 length,
font_renderer_solid_type* solidRenderer,
font_renderer_bin_type* binRenderer,
const Transformable& transform,
BRect clippingFrame,
const BPoint& baseLine,
const BRect& clippingFrame,
bool dryRun = false,
BPoint* nextCharPos = NULL);
@ -48,6 +50,8 @@ class AGGTextRenderer {
status_t _PrepareUnicodeBuffer(const char* utf8String,
uint32 length,
uint32* glyphCount);
void _UpdateSizeAndHinting(float size, bool hinted,
bool force = false);
typedef agg::font_engine_freetype_int32 font_engine_type;
@ -70,8 +74,14 @@ class AGGTextRenderer {
int32 fUnicodeBufferSize;
bool fHinted; // is glyph hinting active?
bool fAntialias; // is anti-aliasing active?
bool fAntialias;
bool fKerning;
Transformable fEmbeddedTransformation; // rotated or sheared font?
// caching to avoid loading a font unnecessarily
uint32 fLastFamilyAndStyle;
float fLastPointSize;
bool fLastHinted;
};
#endif // AGG_TEXT_RENDERER_H