Font rendering code should be cleaner, maybe a little more efficient and better documented. Rotated text is supported again.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@12748 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -74,15 +74,12 @@ class Painter {
|
|||||||
void SetPattern(const pattern& p);
|
void SetPattern(const pattern& p);
|
||||||
|
|
||||||
void SetPenLocation(const BPoint& location);
|
void SetPenLocation(const BPoint& location);
|
||||||
void SetFont(const BFont& font);
|
|
||||||
void SetFont(const ServerFont& font);
|
void SetFont(const ServerFont& font);
|
||||||
|
|
||||||
// BView API compatibility (for easier testing)
|
// BView API compatibility (for easier testing)
|
||||||
void Sync() {}
|
void Sync() {}
|
||||||
inline void MovePenTo(const BPoint& location)
|
inline void MovePenTo(const BPoint& location)
|
||||||
{ SetPenLocation(location); }
|
{ SetPenLocation(location); }
|
||||||
inline void SetFont(const BFont* font)
|
|
||||||
{ if (font) SetFont(*font); }
|
|
||||||
|
|
||||||
// painting functions
|
// painting functions
|
||||||
|
|
||||||
@@ -310,6 +307,8 @@ class Painter {
|
|||||||
// by Family and Style
|
// by Family and Style
|
||||||
AGGTextRenderer* fTextRenderer;
|
AGGTextRenderer* fTextRenderer;
|
||||||
uint32 fLastFamilyAndStyle;
|
uint32 fLastFamilyAndStyle;
|
||||||
|
float fLastRotation;
|
||||||
|
float fLastShear;
|
||||||
};
|
};
|
||||||
|
|
||||||
// SetHighColor
|
// SetHighColor
|
||||||
|
|||||||
@@ -569,7 +569,7 @@ void ServerWindow::DispatchMessage(int32 code, LinkMsgReader &link)
|
|||||||
{
|
{
|
||||||
DTRACE(("ServerWindow %s: Message AS_LAYER_SET_STATE: Layer name: %s\n", fName, cl->fName->String()));
|
DTRACE(("ServerWindow %s: Message AS_LAYER_SET_STATE: Layer name: %s\n", fName, cl->fName->String()));
|
||||||
// SetLayerState(cl);
|
// SetLayerState(cl);
|
||||||
SetLayerState(cl,link);
|
SetLayerState(cl, link);
|
||||||
// TODO: should this be moved into SetLayerState?
|
// TODO: should this be moved into SetLayerState?
|
||||||
// If it _always_ needs to be done afterwards, then yes!
|
// If it _always_ needs to be done afterwards, then yes!
|
||||||
cl->RebuildFullRegion();
|
cl->RebuildFullRegion();
|
||||||
@@ -579,7 +579,7 @@ void ServerWindow::DispatchMessage(int32 code, LinkMsgReader &link)
|
|||||||
{
|
{
|
||||||
DTRACE(("ServerWindow %s: Message AS_LAYER_SET_FONT_STATE: Layer name: %s\n", fName, cl->fName->String()));
|
DTRACE(("ServerWindow %s: Message AS_LAYER_SET_FONT_STATE: Layer name: %s\n", fName, cl->fName->String()));
|
||||||
// SetLayerFontState(cl);
|
// SetLayerFontState(cl);
|
||||||
SetLayerFontState(cl,link);
|
SetLayerFontState(cl, link);
|
||||||
cl->RebuildFullRegion();
|
cl->RebuildFullRegion();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,7 +66,9 @@ Painter::Painter()
|
|||||||
fDrawingModeFactory(new DrawingModeFactory()),
|
fDrawingModeFactory(new DrawingModeFactory()),
|
||||||
fPatternHandler(new PatternHandler()),
|
fPatternHandler(new PatternHandler()),
|
||||||
fTextRenderer(new AGGTextRenderer()),
|
fTextRenderer(new AGGTextRenderer()),
|
||||||
fLastFamilyAndStyle(0)
|
fLastFamilyAndStyle(0),
|
||||||
|
fLastRotation(0.0),
|
||||||
|
fLastShear(90.0)
|
||||||
{
|
{
|
||||||
if (fontserver && fontserver->GetSystemPlain())
|
if (fontserver && fontserver->GetSystemPlain())
|
||||||
fFont = *fontserver->GetSystemPlain();
|
fFont = *fontserver->GetSystemPlain();
|
||||||
@@ -257,19 +259,6 @@ Painter::SetPenLocation(const BPoint& location)
|
|||||||
fPenLocation = location;
|
fPenLocation = location;
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetFont
|
|
||||||
void
|
|
||||||
Painter::SetFont(const BFont& font)
|
|
||||||
{
|
|
||||||
//fFont.SetFamilyAndStyle(font.GetFamily(), font.GetStyle());
|
|
||||||
fFont.SetSpacing(font.Spacing());
|
|
||||||
fFont.SetShear(font.Shear());
|
|
||||||
fFont.SetRotation(font.Rotation());
|
|
||||||
fFont.SetSize(font.Size());
|
|
||||||
|
|
||||||
_UpdateFont();
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetFont
|
// SetFont
|
||||||
void
|
void
|
||||||
Painter::SetFont(const ServerFont& font)
|
Painter::SetFont(const ServerFont& font)
|
||||||
@@ -1082,16 +1071,20 @@ Painter::_UpdateFont()
|
|||||||
if (fFont.InitCheck() < B_OK)
|
if (fFont.InitCheck() < B_OK)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (fLastFamilyAndStyle != fFont.GetFamilyAndStyle()) {
|
if (fLastFamilyAndStyle != fFont.GetFamilyAndStyle()
|
||||||
fLastFamilyAndStyle = fFont.GetFamilyAndStyle();
|
|| fFont.Rotation() != fLastRotation || fFont.Shear() != fLastShear) {
|
||||||
|
|
||||||
bool success = false;
|
if (fTextRenderer->SetFont(fFont)) {
|
||||||
success = fTextRenderer->SetFont(fFont);
|
fLastFamilyAndStyle = fFont.GetFamilyAndStyle();
|
||||||
if (!success)
|
fLastRotation = fFont.Rotation();
|
||||||
fprintf(stderr, "unable to set font\n");
|
fLastShear = fFont.Shear();
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "unable to set font\n");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// just update the size
|
||||||
|
fTextRenderer->SetPointSize(fFont.Size());
|
||||||
}
|
}
|
||||||
|
|
||||||
fTextRenderer->SetPointSize(fFont.Size());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// _UpdateLineWidth
|
// _UpdateLineWidth
|
||||||
@@ -1468,7 +1461,6 @@ Painter::_StrokePath(VertexSource& path) const
|
|||||||
agg::conv_stroke<VertexSource> stroke(path);
|
agg::conv_stroke<VertexSource> stroke(path);
|
||||||
stroke.line_join(agg::round_join);
|
stroke.line_join(agg::round_join);
|
||||||
stroke.width(fPenSize);
|
stroke.width(fPenSize);
|
||||||
// stroke.approximation_scale(fPenSize / 2);
|
|
||||||
|
|
||||||
fRasterizer->add_path(stroke);
|
fRasterizer->add_path(stroke);
|
||||||
agg::render_scanlines(*fRasterizer, *fScanline, *fRenderer);
|
agg::render_scanlines(*fRasterizer, *fScanline, *fRenderer);
|
||||||
@@ -1480,7 +1472,7 @@ Painter::_StrokePath(VertexSource& path) const
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
BRect touched = _BoundingBox(path);
|
BRect touched = _BoundingBox(path);
|
||||||
float penSize = ceilf(fPenSize);
|
float penSize = ceilf(fPenSize / 2.0);
|
||||||
touched.InsetBy(-penSize, -penSize);
|
touched.InsetBy(-penSize, -penSize);
|
||||||
|
|
||||||
return _Clipped(touched);
|
return _Clipped(touched);
|
||||||
|
|||||||
@@ -23,6 +23,13 @@
|
|||||||
|
|
||||||
#define FLIP_Y false
|
#define FLIP_Y false
|
||||||
|
|
||||||
|
#define SHOW_GLYPH_BOUNDS 0
|
||||||
|
|
||||||
|
#if SHOW_GLYPH_BOUNDS
|
||||||
|
# include <agg_conv_stroke.h>
|
||||||
|
# include <agg_path_storage.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
// rect_to_int
|
// rect_to_int
|
||||||
inline void
|
inline void
|
||||||
rect_to_int(BRect r,
|
rect_to_int(BRect r,
|
||||||
@@ -68,20 +75,23 @@ bool
|
|||||||
AGGTextRenderer::SetFont(const ServerFont &font)
|
AGGTextRenderer::SetFont(const ServerFont &font)
|
||||||
{
|
{
|
||||||
bool success = false;
|
bool success = false;
|
||||||
if (font.Rotation() == 0.0 && font.Shear() == 90.0)
|
if (font.Rotation() == 0.0 && font.Shear() == 90.0) {
|
||||||
|
//printf("AGGTextRenderer::SetFont() - native\n");
|
||||||
success = fFontEngine.load_font(font, agg::glyph_ren_native_gray8);
|
success = fFontEngine.load_font(font, agg::glyph_ren_native_gray8);
|
||||||
else
|
fFontEngine.hinting(fHinted);
|
||||||
|
} else {
|
||||||
|
//printf("AGGTextRenderer::SetFont() - outline\n");
|
||||||
success = fFontEngine.load_font(font, agg::glyph_ren_outline);
|
success = fFontEngine.load_font(font, agg::glyph_ren_outline);
|
||||||
|
fFontEngine.hinting(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
SetPointSize(font.Size());
|
||||||
|
|
||||||
if (!success) {
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,6 +142,9 @@ 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);
|
||||||
|
|
||||||
|
// "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);
|
BRect bounds(0.0, 0.0, -1.0, -1.0);
|
||||||
|
|
||||||
uint32 glyphCount;
|
uint32 glyphCount;
|
||||||
@@ -143,7 +156,7 @@ AGGTextRenderer::RenderString(const char* string,
|
|||||||
// (only if glyph->data_type == agg::glyph_data_outline)
|
// (only if glyph->data_type == agg::glyph_data_outline)
|
||||||
// in the pipeline for the rasterizer
|
// in the pipeline for the rasterizer
|
||||||
typedef agg::conv_transform<conv_font_curve_type, agg::trans_affine> conv_font_trans_type;
|
typedef agg::conv_transform<conv_font_curve_type, agg::trans_affine> conv_font_trans_type;
|
||||||
conv_font_trans_type ftrans(fCurves, transform);
|
conv_font_trans_type transformedOutline(fCurves, transform);
|
||||||
|
|
||||||
uint16* p = (uint16*)fUnicodeBuffer;
|
uint16* p = (uint16*)fUnicodeBuffer;
|
||||||
|
|
||||||
@@ -182,69 +195,98 @@ AGGTextRenderer::RenderString(const char* string,
|
|||||||
x += advanceX;
|
x += advanceX;
|
||||||
y += advanceY;
|
y += advanceY;
|
||||||
|
|
||||||
// calculate bounds
|
// "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".
|
||||||
const agg::rect& r = glyph->bounds;
|
const agg::rect& r = glyph->bounds;
|
||||||
BRect glyphBounds(r.x1 + x, r.y1 + y, r.x2 + x, r.y2 + y);
|
BRect glyphBounds(r.x1 + x, r.y1 + y, r.x2 + x, r.y2 + y);
|
||||||
|
|
||||||
// init the fontmanager and transform glyph bounds
|
// track bounding box
|
||||||
if (glyph->data_type != agg::glyph_data_outline) {
|
|
||||||
// we cannot use the transformation pipeline
|
|
||||||
double transformedX = x + transformOffset.x;
|
|
||||||
double transformedY = y + transformOffset.y;
|
|
||||||
fFontManager.init_embedded_adaptors(glyph,
|
|
||||||
transformedX,
|
|
||||||
transformedY);
|
|
||||||
glyphBounds.OffsetBy(transformOffset);
|
|
||||||
} else {
|
|
||||||
fFontManager.init_embedded_adaptors(glyph, x, y);
|
|
||||||
glyphBounds = transform.TransformBounds(glyphBounds);
|
|
||||||
}
|
|
||||||
|
|
||||||
// render glyph and update touched area
|
|
||||||
if (!dryRun && clippingFrame.Intersects(glyphBounds)) {
|
|
||||||
switch (glyph->data_type) {
|
|
||||||
case agg::glyph_data_mono:
|
|
||||||
agg::render_scanlines(fFontManager.mono_adaptor(),
|
|
||||||
fFontManager.mono_scanline(),
|
|
||||||
*binRenderer);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case agg::glyph_data_gray8:
|
|
||||||
agg::render_scanlines(fFontManager.gray8_adaptor(),
|
|
||||||
fFontManager.gray8_scanline(),
|
|
||||||
*solidRenderer);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case agg::glyph_data_outline:
|
|
||||||
fRasterizer.reset();
|
|
||||||
// NOTE: this function can be easily extended to handle
|
|
||||||
// conversion to contours, so that's why there is a lot of
|
|
||||||
// commented out code, I leave here because I think it
|
|
||||||
// will be needed again.
|
|
||||||
|
|
||||||
// if(fabs(0.0) <= 0.01) {
|
|
||||||
// For the sake of efficiency skip the
|
|
||||||
// contour converter if the weight is about zero.
|
|
||||||
//-----------------------
|
|
||||||
// fRasterizer.add_path(fCurves);
|
|
||||||
fRasterizer.add_path(ftrans);
|
|
||||||
/* } else {
|
|
||||||
// fRasterizer.add_path(fContour);
|
|
||||||
fRasterizer.add_path(ftrans);
|
|
||||||
}*/
|
|
||||||
if (fAntialias) {
|
|
||||||
agg::render_scanlines(fRasterizer, fScanline, *solidRenderer);
|
|
||||||
} else {
|
|
||||||
agg::render_scanlines(fRasterizer, fScanline, *binRenderer);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (glyphBounds.IsValid())
|
if (glyphBounds.IsValid())
|
||||||
bounds = bounds.IsValid() ? bounds | glyphBounds : glyphBounds;
|
bounds = bounds.IsValid() ? bounds | glyphBounds : glyphBounds;
|
||||||
|
|
||||||
|
// render the glyph if this is not a dry run
|
||||||
|
if (!dryRun) {
|
||||||
|
// init the fontmanager's embedded adaptors
|
||||||
|
// NOTE: The initialization for the "location" of
|
||||||
|
// the glyph is different depending on wether we
|
||||||
|
// deal with non-(rotated/sheared) text, in which
|
||||||
|
// case we have a native FT bitmap. For rotated or
|
||||||
|
// sheared text, we use AGG vector outlines and
|
||||||
|
// a transformation pipeline, which will be applied
|
||||||
|
// _after_ we retrieve the outline, and that's why
|
||||||
|
// we simply pass x and y, which are untransformed.
|
||||||
|
|
||||||
|
// "glyphBounds" is now transformed into screen coords
|
||||||
|
// in order to stop drawing when we are already outside
|
||||||
|
// of the clipping frame
|
||||||
|
if (glyph->data_type != agg::glyph_data_outline) {
|
||||||
|
// we cannot use the transformation pipeline
|
||||||
|
double transformedX = x + transformOffset.x;
|
||||||
|
double transformedY = y + transformOffset.y;
|
||||||
|
fFontManager.init_embedded_adaptors(glyph,
|
||||||
|
transformedX,
|
||||||
|
transformedY);
|
||||||
|
glyphBounds.OffsetBy(transformOffset);
|
||||||
|
} else {
|
||||||
|
fFontManager.init_embedded_adaptors(glyph, x, y);
|
||||||
|
glyphBounds = transform.TransformBounds(glyphBounds);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clippingFrame.Intersects(glyphBounds)) {
|
||||||
|
switch (glyph->data_type) {
|
||||||
|
case agg::glyph_data_mono:
|
||||||
|
agg::render_scanlines(fFontManager.mono_adaptor(),
|
||||||
|
fFontManager.mono_scanline(),
|
||||||
|
*binRenderer);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case agg::glyph_data_gray8:
|
||||||
|
agg::render_scanlines(fFontManager.gray8_adaptor(),
|
||||||
|
fFontManager.gray8_scanline(),
|
||||||
|
*solidRenderer);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case agg::glyph_data_outline: {
|
||||||
|
fRasterizer.reset();
|
||||||
|
// NOTE: this function can be easily extended to handle
|
||||||
|
// conversion to contours, so that's why there is a lot of
|
||||||
|
// commented out code, I leave it here because I think it
|
||||||
|
// will be needed again.
|
||||||
|
|
||||||
|
// if(fabs(0.0) <= 0.01) {
|
||||||
|
// For the sake of efficiency skip the
|
||||||
|
// contour converter if the weight is about zero.
|
||||||
|
//-----------------------
|
||||||
|
fRasterizer.add_path(transformedOutline);
|
||||||
|
#if SHOW_GLYPH_BOUNDS
|
||||||
|
agg::path_storage p;
|
||||||
|
p.move_to(glyphBounds.left + 0.5, glyphBounds.top + 0.5);
|
||||||
|
p.line_to(glyphBounds.right + 0.5, glyphBounds.top + 0.5);
|
||||||
|
p.line_to(glyphBounds.right + 0.5, glyphBounds.bottom + 0.5);
|
||||||
|
p.line_to(glyphBounds.left + 0.5, glyphBounds.bottom + 0.5);
|
||||||
|
p.close_polygon();
|
||||||
|
agg::conv_stroke<agg::path_storage> ps(p);
|
||||||
|
ps.width(1.0);
|
||||||
|
fRasterizer.add_path(ps);
|
||||||
|
#endif
|
||||||
|
/* } else {
|
||||||
|
// fRasterizer.add_path(fContour);
|
||||||
|
fRasterizer.add_path(transformedOutline);
|
||||||
|
}*/
|
||||||
|
if (fAntialias) {
|
||||||
|
agg::render_scanlines(fRasterizer, fScanline, *solidRenderer);
|
||||||
|
} else {
|
||||||
|
agg::render_scanlines(fRasterizer, fScanline, *binRenderer);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// increment pen position
|
// increment pen position
|
||||||
advanceX = glyph->advance_x;
|
advanceX = glyph->advance_x;
|
||||||
advanceY = glyph->advance_y;
|
advanceY = glyph->advance_y;
|
||||||
@@ -259,8 +301,7 @@ AGGTextRenderer::RenderString(const char* string,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// return transform.TransformBounds(bounds);
|
return transform.TransformBounds(bounds);
|
||||||
return bounds;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// StringWidth
|
// StringWidth
|
||||||
|
|||||||
Reference in New Issue
Block a user