#include <stdio.h>
#include <string.h>
#include <Bitmap.h>
#include <GraphicsDefs.h>
#include <Region.h>
#include <agg_bezier_arc.h>
#include <agg_bounding_rect.h>
#include <agg_conv_curve.h>
#include <agg_conv_stroke.h>
#include <agg_ellipse.h>
#include <agg_path_storage.h>
#include <agg_rounded_rect.h>
#include <agg_span_image_filter_rgba32.h>
#include <agg_span_interpolator_linear.h>
#include "LayerData.h"
#include "AGGTextRenderer.h"
#include "DrawingMode.h"
#include "DrawingModeFactory.h"
#include "FontManager.h"
#include "PatternHandler.h"
#include "RenderingBuffer.h"
#include "ShapeConverter.h"
#include "ServerBitmap.h"
#include "ServerFont.h"
#include "Painter.h"
int
roundf(float v)
{
if (v >= 0.0)
return (int)floorf(v + 0.5);
else
return (int)floorf(v - 0.5);
}
Painter::Painter()
: fBuffer(NULL),
fPixelFormat(NULL),
fBaseRenderer(NULL),
fOutlineRenderer(NULL),
fOutlineRasterizer(NULL),
fScanline(NULL),
fRasterizer(NULL),
fRenderer(NULL),
fFontRendererSolid(NULL),
fFontRendererBin(NULL),
fLineProfile(),
fSubpixelPrecise(false),
fScale(1.0),
fPenSize(1.0),
fOrigin(0.0, 0.0),
fClippingRegion(NULL),
fDrawingMode(B_OP_COPY),
fAlphaSrcMode(B_PIXEL_ALPHA),
fAlphaFncMode(B_ALPHA_OVERLAY),
fPenLocation(0.0, 0.0),
fPatternHandler(new PatternHandler()),
fTextRenderer(new AGGTextRenderer()),
fLastFamilyAndStyle(0)
{
if (fontserver)
fFont = *fontserver->GetSystemPlain();
_UpdateFont();
_UpdateLineWidth();
}
Painter::~Painter()
{
_MakeEmpty();
delete fClippingRegion;
delete fPatternHandler;
delete fTextRenderer;
}
void
Painter::AttachToBuffer(RenderingBuffer* buffer)
{
if (buffer && buffer->InitCheck() >= B_OK) {
_MakeEmpty();
fBuffer = new agg::rendering_buffer();
fBuffer->attach((uint8*)buffer->Bits(),
buffer->Width(),
buffer->Height(),
buffer->BytesPerRow());
fPixelFormat = new pixfmt(*fBuffer, fPatternHandler);
fPixelFormat->set_drawing_mode(DrawingModeFactory::DrawingModeFor(fDrawingMode,
fAlphaSrcMode,
fAlphaFncMode,
false));
fBaseRenderer = new renderer_base(*fPixelFormat);
rgb_color color = fPatternHandler->HighColor().GetColor32();
#if ALIASED_DRAWING
fOutlineRenderer = new outline_renderer_type(*fBaseRenderer);
fOutlineRasterizer = new outline_rasterizer_type(*fOutlineRenderer);
#else
fOutlineRenderer = new outline_renderer_type(*fBaseRenderer, fLineProfile);
fOutlineRasterizer = new outline_rasterizer_type(*fOutlineRenderer);
fOutlineRenderer->profile(fLineProfile);
#endif
fRenderer = new renderer_type(*fBaseRenderer);
fRasterizer = new rasterizer_type();
fScanline = new scanline_type();
#if ALIASED_DRAWING
fRasterizer->gamma(agg::gamma_threshold(0.5));
#endif
fFontRendererSolid = new font_renderer_solid_type(*fBaseRenderer);
fFontRendererBin = new font_renderer_bin_type(*fBaseRenderer);
_SetRendererColor(fPatternHandler->HighColor().GetColor32());
_RebuildClipping();
}
}
void
Painter::DetachFromBuffer()
{
_MakeEmpty();
}
void
Painter::SetDrawData(const DrawData* data)
{
SetHighColor(data->highcolor.GetColor32());
SetLowColor(data->lowcolor.GetColor32());
SetScale(data->scale);
SetPenSize(data->pensize);
SetDrawingMode(data->draw_mode);
SetBlendingMode(data->alphaSrcMode, data->alphaFncMode);
SetPenLocation(data->penlocation);
SetFont(data->font);
fPatternHandler->SetPattern(data->patt);
}
void
Painter::ConstrainClipping(const BRegion& region)
{
if (!fClippingRegion)
fClippingRegion = new BRegion(region);
else
*fClippingRegion = region;
_RebuildClipping();
}
void
Painter::SetHighColor(const rgb_color& color)
{
fPatternHandler->SetHighColor(color);
}
void
Painter::SetLowColor(const rgb_color& color)
{
fPatternHandler->SetLowColor(color);;
}
void
Painter::SetScale(float scale)
{
if (fScale != scale) {
fScale = scale;
_RebuildClipping();
_UpdateLineWidth();
}
}
void
Painter::SetPenSize(float size)
{
if (fPenSize != size) {
fPenSize = size;
_UpdateLineWidth();
}
}
void
Painter::SetOrigin(const BPoint& origin)
{
fOrigin = origin;
_RebuildClipping();
}
void
Painter::SetDrawingMode(drawing_mode mode)
{
if (fDrawingMode != mode) {
fDrawingMode = mode;
if (fPixelFormat) {
fPixelFormat->set_drawing_mode(DrawingModeFactory::DrawingModeFor(fDrawingMode,
fAlphaSrcMode,
fAlphaFncMode));
}
}
}
void
Painter::SetBlendingMode(source_alpha alphaSrcMode, alpha_function alphaFncMode)
{
if (fAlphaSrcMode != alphaSrcMode || fAlphaFncMode != alphaFncMode) {
fAlphaSrcMode = alphaSrcMode;
fAlphaFncMode = alphaFncMode;
if (fDrawingMode == B_OP_ALPHA && fPixelFormat) {
fPixelFormat->set_drawing_mode(DrawingModeFactory::DrawingModeFor(fDrawingMode,
fAlphaSrcMode,
fAlphaFncMode));
}
}
}
void
Painter::SetPenLocation(const BPoint& location)
{
fPenLocation = location;
}
void
Painter::SetFont(const BFont& font)
{
fFont.SetSpacing(font.Spacing());
fFont.SetShear(font.Shear());
fFont.SetRotation(font.Rotation());
fFont.SetSize(font.Size());
_UpdateFont();
}
void
Painter::SetFont(const ServerFont& font)
{
fFont = font;
_UpdateFont();
}
BRect
Painter::StrokeLine(BPoint a, BPoint b, const pattern& p)
{
_Transform(&a);
_Transform(&b);
BRect touched(a, b);
float penSize = _Transform(fPenSize);
if (penSize == 1.0 &&
(fDrawingMode == B_OP_COPY || fDrawingMode == B_OP_OVER)) {
pattern pat = *fPatternHandler->GetR5Pattern();
if (pat == B_SOLID_HIGH &&
StraightLine(a, b, fPatternHandler->HighColor().GetColor32())) {
SetPenLocation(b);
return _Clipped(touched);
} else if (pat == B_SOLID_LOW &&
StraightLine(a, b, fPatternHandler->LowColor().GetColor32())) {
SetPenLocation(b);
return _Clipped(touched);
}
}
agg::path_storage path;
path.move_to(a.x, a.y);
path.line_to(b.x, b.y);
touched = _StrokePath(path, p);
SetPenLocation(b);
return _Clipped(touched);
}
BRect
Painter::StrokeLine(BPoint b, const pattern& p)
{
return StrokeLine(fPenLocation, b);
}
bool
Painter::StraightLine(BPoint a, BPoint b, const rgb_color& c) const
{
if (fBuffer) {
if (a.x == b.x) {
uint8* dst = fBuffer->row(0);
uint32 bpr = fBuffer->stride();
int32 x = (int32)a.x;
dst += x * 4;
int32 y1 = (int32)min_c(a.y, b.y);
int32 y2 = (int32)max_c(a.y, b.y);
fBaseRenderer->first_clip_box();
do {
if (fBaseRenderer->xmin() <= x &&
fBaseRenderer->xmax() >= x) {
int32 i = max_c(fBaseRenderer->ymin(), y1);
int32 end = min_c(fBaseRenderer->ymax(), y2);
uint8* handle = dst + i * bpr;
for (; i <= end; i++) {
handle[0] = c.blue;
handle[1] = c.green;
handle[2] = c.red;
handle += bpr;
}
}
} while (fBaseRenderer->next_clip_box());
return true;
} else if (a.y == b.y) {
uint8* dst = fBuffer->row(0);
uint32 bpr = fBuffer->stride();
int32 y = (int32)a.y;
dst += y * bpr;
int32 x1 = (int32)min_c(a.x, b.x);
int32 x2 = (int32)max_c(a.x, b.x);
fBaseRenderer->first_clip_box();
do {
if (fBaseRenderer->ymin() <= y &&
fBaseRenderer->ymax() >= y) {
int32 i = max_c(fBaseRenderer->xmin(), x1);
int32 end = min_c(fBaseRenderer->xmax(), x2);
uint8* handle = dst + i * 4;
for (; i <= end; i++) {
handle[0] = c.blue;
handle[1] = c.green;
handle[2] = c.red;
handle += 4;
}
}
} while (fBaseRenderer->next_clip_box());
return true;
}
}
return false;
}
void
Painter::StrokeTriangle(BPoint pt1, BPoint pt2, BPoint pt3, const pattern& p) const
{
_DrawTriangle(pt1, pt2, pt3, p, false);
}
void
Painter::FillTriangle(BPoint pt1, BPoint pt2, BPoint pt3, const pattern& p) const
{
_DrawTriangle(pt1, pt2, pt3, p, true);
}
void
Painter::StrokePolygon(const BPoint* ptArray, int32 numPts,
bool closed, const pattern& p) const
{
_DrawPolygon(ptArray, numPts, closed, p, false);
}
void
Painter::FillPolygon(const BPoint* ptArray, int32 numPts,
bool closed, const pattern& p) const
{
_DrawPolygon(ptArray, numPts, closed, p, true);
}
void
Painter::StrokeBezier(const BPoint* controlPoints, const pattern& p) const
{
agg::path_storage curve;
BPoint p1(controlPoints[0]);
BPoint p2(controlPoints[1]);
BPoint p3(controlPoints[2]);
BPoint p4(controlPoints[3]);
_Transform(&p1);
_Transform(&p2);
_Transform(&p3);
_Transform(&p4);
curve.move_to(p1.x, p1.y);
curve.curve4(p1.x, p1.y,
p2.x, p2.y,
p3.x, p3.y);
agg::conv_curve<agg::path_storage> path(curve);
_StrokePath(path, p);
}
void
Painter::FillBezier(const BPoint* controlPoints, const pattern& p) const
{
agg::path_storage curve;
BPoint p1(controlPoints[0]);
BPoint p2(controlPoints[1]);
BPoint p3(controlPoints[2]);
BPoint p4(controlPoints[3]);
_Transform(&p1);
_Transform(&p2);
_Transform(&p3);
_Transform(&p4);
curve.move_to(p1.x, p1.y);
curve.curve4(p1.x, p1.y,
p2.x, p2.y,
p3.x, p3.y);
curve.close_polygon();
agg::conv_curve<agg::path_storage> path(curve);
_FillPath(path, p);
}
void
Painter::StrokeShape(BShape* shape, const pattern& p) const
{
_DrawShape(shape, p, false);
}
void
Painter::FillShape(BShape* shape, const pattern& p) const
{
_DrawShape(shape, p, true);
}
BRect
Painter::StrokeRect(const BRect& r, const pattern& p) const
{
BPoint a(r.left, r.top);
BPoint b(r.right, r.bottom);
_Transform(&a);
_Transform(&b);
float penSize = _Transform(fPenSize);
if (penSize == 1.0 &&
(fDrawingMode == B_OP_COPY || fDrawingMode == B_OP_OVER)) {
if (p == B_SOLID_HIGH) {
BRect rect(a, b);
StrokeRect(rect,
fPatternHandler->HighColor().GetColor32());
return _Clipped(rect);
} else if (p == B_SOLID_LOW) {
BRect rect(a, b);
StrokeRect(rect,
fPatternHandler->LowColor().GetColor32());
return _Clipped(rect);
}
}
agg::path_storage path;
path.move_to(a.x, a.y);
path.line_to(b.x, a.y);
path.line_to(b.x, b.y);
path.line_to(a.x, b.y);
path.close_polygon();
return _StrokePath(path, p);
}
void
Painter::StrokeRect(const BRect& r, const rgb_color& c) const
{
StraightLine(BPoint(r.left, r.top),
BPoint(r.right - 1, r.top), c);
StraightLine(BPoint(r.right, r.top),
BPoint(r.right, r.bottom - 1), c);
StraightLine(BPoint(r.right, r.bottom),
BPoint(r.left + 1, r.bottom), c);
StraightLine(BPoint(r.left, r.bottom),
BPoint(r.left, r.top + 1), c);
}
BRect
Painter::FillRect(const BRect& r, const pattern& p) const
{
BPoint a(r.left, r.top);
BPoint b(r.right, r.bottom);
_Transform(&a, false);
_Transform(&b, false);
if (fDrawingMode == B_OP_COPY || fDrawingMode == B_OP_OVER) {
pattern pat = *fPatternHandler->GetR5Pattern();
if (pat == B_SOLID_HIGH) {
BRect rect(a, b);
FillRect(rect, fPatternHandler->HighColor().GetColor32());
return _Clipped(rect);
} else if (pat == B_SOLID_LOW) {
BRect rect(a, b);
FillRect(rect, fPatternHandler->LowColor().GetColor32());
return _Clipped(rect);
}
}
b.x += 1.0;
b.y += 1.0;
agg::path_storage path;
path.move_to(a.x, a.y);
path.line_to(b.x, a.y);
path.line_to(b.x, b.y);
path.line_to(a.x, b.y);
path.close_polygon();
return _FillPath(path, p);
}
void
Painter::FillRect(const BRect& r, const rgb_color& c) const
{
if (fBuffer) {
uint8* dst = fBuffer->row(0);
uint32 bpr = fBuffer->stride();
int32 left = (int32)r.left;
int32 top = (int32)r.top;
int32 right = (int32)r.right;
int32 bottom = (int32)r.bottom;
fBaseRenderer->first_clip_box();
do {
int32 x1 = max_c(fBaseRenderer->xmin(), left);
int32 x2 = min_c(fBaseRenderer->xmax(), right);
if (x1 <= x2) {
int32 y1 = max_c(fBaseRenderer->ymin(), top);
int32 y2 = min_c(fBaseRenderer->ymax(), bottom);
uint8* offset = dst + x1 * 4;
for (; y1 <= y2; y1++) {
uint8* handle = offset + y1 * bpr;
for (int32 x = x1; x <= x2; x++) {
handle[0] = c.blue;
handle[1] = c.green;
handle[2] = c.red;
handle += 4;
}
}
}
} while (fBaseRenderer->next_clip_box());
}
}
void
Painter::StrokeRoundRect(const BRect& r, float xRadius, float yRadius,
const pattern& p) const
{
BPoint lt(r.left, r.top);
BPoint rb(r.right, r.bottom);
_Transform(<);
_Transform(&rb);
_Transform(&xRadius);
_Transform(&yRadius);
agg::rounded_rect rect;
rect.rect(lt.x, lt.y, rb.x, rb.y);
rect.radius(xRadius, yRadius);
_StrokePath(rect, p);
}
void
Painter::FillRoundRect(const BRect& r, float xRadius, float yRadius,
const pattern& p) const
{
BPoint lt(r.left, r.top);
BPoint rb(r.right, r.bottom);
_Transform(<, false);
_Transform(&rb, false);
rb.x += 1.0;
rb.y += 1.0;
_Transform(&xRadius);
_Transform(&yRadius);
agg::rounded_rect rect;
rect.rect(lt.x, lt.y, rb.x, rb.y);
rect.radius(xRadius, yRadius);
_FillPath(rect, p);
}
void
Painter::StrokeEllipse(BPoint center, float xRadius, float yRadius,
const pattern& p) const
{
_DrawEllipse(center, xRadius, yRadius, p, false);
}
void
Painter::FillEllipse(BPoint center, float xRadius, float yRadius,
const pattern& p) const
{
_DrawEllipse(center, xRadius, yRadius, p, true);
}
void
Painter::StrokeArc(BPoint center, float xRadius, float yRadius,
float angle, float span, const pattern& p) const
{
_Transform(¢er);
_Transform(&xRadius);
_Transform(&yRadius);
double angleRad = (angle * PI) / 180.0;
double spanRad = (span * PI) / 180.0;
agg::bezier_arc arc(center.x, center.y, xRadius, yRadius,
-angleRad, -spanRad);
agg::conv_curve<agg::bezier_arc> path(arc);
_StrokePath(path, p);
}
void
Painter::FillArc(BPoint center, float xRadius, float yRadius,
float angle, float span, const pattern& p) const
{
_Transform(¢er);
_Transform(&xRadius);
_Transform(&yRadius);
double angleRad = (angle * PI) / 180.0;
double spanRad = (span * PI) / 180.0;
agg::bezier_arc arc(center.x, center.y, xRadius, yRadius,
-angleRad, -spanRad);
agg::conv_curve<agg::bezier_arc> segmentedArc(arc);
agg::path_storage path;
path.move_to(center.x, center.y);
segmentedArc.rewind(0);
double x;
double y;
unsigned cmd = segmentedArc.vertex(&x, &y);
while (!agg::is_stop(cmd)) {
path.line_to(x, y);
cmd = segmentedArc.vertex(&x, &y);
}
path.close_polygon();
_FillPath(path, p);
}
BRect
Painter::DrawChar(char aChar)
{
return DrawChar(aChar, fPenLocation);
}
BRect
Painter::DrawChar(char aChar, BPoint baseLine)
{
char wrapper[2];
wrapper[0] = aChar;
wrapper[1] = 0;
return DrawString(wrapper, 1, baseLine);
}
BRect
Painter::DrawString(const char* utf8String, uint32 length,
const escapement_delta* delta)
{
return DrawString(utf8String, length, fPenLocation, delta);
}
BRect
Painter::DrawString(const char* utf8String, uint32 length,
BPoint baseLine, const escapement_delta* delta)
{
BRect bounds(0.0, 0.0, -1.0, -1.0);
fPatternHandler->SetPattern(B_SOLID_HIGH);
if (fBuffer) {
Transformable transform;
transform.ShearBy(B_ORIGIN, (90.0 - fFont.Shear()) * PI / 180.0, 0.0);
transform.RotateBy(B_ORIGIN, -fFont.Rotation() * PI / 180.0);
transform.TranslateBy(baseLine);
transform.ScaleBy(B_ORIGIN, fScale, fScale);
transform.TranslateBy(fOrigin);
BRect clippingFrame;
if (fClippingRegion)
clippingFrame = _Transform(fClippingRegion->Frame());
bounds = fTextRenderer->RenderString(utf8String,
length,
fFontRendererSolid,
fFontRendererBin,
transform,
clippingFrame,
false,
&fPenLocation);
transform.Reset();
transform.RotateBy(B_ORIGIN, -fFont.Rotation());
transform.TranslateBy(baseLine);
transform.Transform(&fPenLocation);
}
return _Clipped(bounds);
}
BRect
Painter::DrawString(const char* utf8String, const escapement_delta* delta)
{
return DrawString(utf8String, strlen(utf8String), fPenLocation, delta);
}
BRect
Painter::DrawString(const char* utf8String, BPoint baseLine,
const escapement_delta* delta)
{
return DrawString(utf8String, strlen(utf8String), baseLine, delta);
}
void
Painter::DrawBitmap(const BBitmap* bitmap,
BRect bitmapRect, BRect viewRect) const
{
if (bitmap && bitmap->IsValid()) {
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);
}
}
void
Painter::DrawBitmap(const ServerBitmap* bitmap,
BRect bitmapRect, BRect viewRect) const
{
if (bitmap && bitmap->InitCheck()) {
BRect actualBitmapRect(bitmap->Bounds());
agg::rendering_buffer srcBuffer;
srcBuffer.attach(bitmap->Bits(),
bitmap->Width(),
bitmap->Height(),
bitmap->BytesPerRow());
_DrawBitmap(srcBuffer, bitmap->ColorSpace(), actualBitmapRect, bitmapRect, viewRect);
}
}
void
Painter::FillRegion(const BRegion* region, const pattern& p = B_SOLID_HIGH) const
{
BRegion copy(*region);
int32 count = copy.CountRects();
for (int32 i = 0; i < count; i++) {
FillRect(copy.RectAt(i), p);
}
}
void
Painter::InvertRect(const BRect& r) const
{
BRegion region(r);
if (fClippingRegion) {
region.IntersectWith(fClippingRegion);
}
int32 count = region.CountRects();
for (int32 i = 0; i < count; i++) {
BRect r = region.RectAt(i);
_Transform(&r);
_InvertRect32(r);
}
}
BRect
Painter::BoundingBox(const char* utf8String, uint32 length,
const BPoint& baseLine) const
{
Transformable transform;
transform.TranslateBy(baseLine);
BRect dummy;
return fTextRenderer->RenderString(utf8String,
length,
fFontRendererSolid,
fFontRendererBin,
transform, dummy, true);
}
void
Painter::_MakeEmpty()
{
delete fBuffer;
fBuffer = NULL;
delete fPixelFormat;
fPixelFormat = NULL;
delete fBaseRenderer;
fBaseRenderer = NULL;
delete fOutlineRenderer;
fOutlineRenderer = NULL;
delete fOutlineRasterizer;
fOutlineRasterizer = NULL;
delete fScanline;
fScanline = NULL;
delete fRasterizer;
fRasterizer = NULL;
delete fRenderer;
fRenderer = NULL;
delete fFontRendererSolid;
fFontRendererSolid = NULL;
delete fFontRendererBin;
fFontRendererBin = NULL;
}
void
Painter::_Transform(BPoint* point, bool centerOffset) const
{
*point += fOrigin;
if (!fSubpixelPrecise) {
point->x = floorf(point->x);
point->y = floorf(point->y);
}
point->x *= fScale;
point->y *= fScale;
if (centerOffset) {
point->x += 0.5;
point->y += 0.5;
}
}
BPoint
Painter::_Transform(const BPoint& point, bool centerOffset) const
{
BPoint ret = point;
_Transform(&ret, centerOffset);
return ret;
}
void
Painter::_Transform(float* width) const
{
*width *= fScale;
if (*width < 1)
*width = 1;
}
float
Painter::_Transform(const float& width) const
{
float w = width * fScale;
if (w < 1)
w = 1;
return w;
}
void
Painter::_Transform(BRect* rect) const
{
rect->right++;
rect->bottom++;
rect->left += fOrigin.x;
rect->top += fOrigin.y;
rect->right += fOrigin.x;
rect->bottom += fOrigin.y;
rect->left *= fScale;
rect->top *= fScale;
rect->right *= fScale;
rect->bottom *= fScale;
rect->right--;
rect->bottom--;
}
BRect
Painter::_Transform(const BRect& rect) const
{
BRect ret = rect;
_Transform(&ret);
return ret;
}
BRect
Painter::_Clipped(const BRect& rect) const
{
if (rect.IsValid() && fClippingRegion)
return rect & _Transform(fClippingRegion->Frame());
return rect;
}
void
Painter::_RebuildClipping()
{
if (fBaseRenderer) {
fBaseRenderer->reset_clipping(!fClippingRegion);
if (fClippingRegion) {
int32 count = fClippingRegion->CountRects();
for (int32 i = 0; i < count; i++) {
BRect r = fClippingRegion->RectAt(i);
BPoint lt(r.LeftTop());
BPoint rb(r.RightBottom());
rb += BPoint(1.0, 1.0);
lt += fOrigin;
lt.x *= fScale;
lt.y *= fScale;
rb += fOrigin;
rb.x *= fScale;
rb.y *= fScale;
rb -= BPoint(1.0, 1.0);
fBaseRenderer->add_clip_box(roundf(lt.x),
roundf(lt.y),
roundf(rb.x),
roundf(rb.y));
}
}
}
}
void
Painter::_UpdateFont()
{
if (fLastFamilyAndStyle != fFont.GetFamilyAndStyle()) {
fLastFamilyAndStyle = fFont.GetFamilyAndStyle();
bool success = false;
success = fTextRenderer->SetFont(fFont);
if (!success)
fprintf(stderr, "unable to set font\n");
}
fTextRenderer->SetPointSize(fFont.Size());
}
void
Painter::_UpdateLineWidth()
{
float width = fPenSize;
_Transform(&width);
fLineProfile.width(width);
}
inline void
Painter::_DrawTriangle(BPoint pt1, BPoint pt2, BPoint pt3,
const pattern& p, bool fill) const
{
_Transform(&pt1);
_Transform(&pt2);
_Transform(&pt3);
agg::path_storage path;
path.move_to(pt1.x, pt1.y);
path.line_to(pt2.x, pt2.y);
path.line_to(pt3.x, pt3.y);
path.close_polygon();
if (fill)
_FillPath(path, p);
else
_StrokePath(path, p);
}
inline void
Painter::_DrawEllipse(BPoint center, float xRadius, float yRadius,
const pattern& p, bool fill) const
{
_Transform(¢er);
_Transform(&xRadius);
_Transform(&yRadius);
float width = fPenSize;
_Transform(&width);
int32 divisions = (int32)max_c(12, ((xRadius + yRadius) * PI) / 2 * (int32)width);
agg::ellipse path(center.x, center.y, xRadius, yRadius, divisions);
if (fill)
_FillPath(path, p);
else
_StrokePath(path, p);
}
inline void
Painter::_DrawShape(BShape* shape, const pattern& p, bool fill) const
{
agg::path_storage path;
ShapeConverter converter(&path);
converter.ScaleBy(B_ORIGIN, fScale, fScale);
converter.TranslateBy(fOrigin);
converter.TranslateBy(BPoint(0.5, 0.5));
converter.Iterate(shape);
if (fill)
_FillPath(path, p);
else
_StrokePath(path, p);
}
inline void
Painter::_DrawPolygon(const BPoint* ptArray, int32 numPts,
bool closed, const pattern& p, bool fill) const
{
if (numPts > 0) {
agg::path_storage path;
BPoint point = _Transform(*ptArray);
path.move_to(point.x, point.y);
for (int32 i = 1; i < numPts; i++) {
ptArray++;
point = _Transform(*ptArray);
path.line_to(point.x, point.y);
}
if (closed)
path.close_polygon();
if (fill)
_FillPath(path, p);
else
_StrokePath(path, p);
}
}
void
Painter::_DrawBitmap(const agg::rendering_buffer& srcBuffer, color_space format,
BRect actualBitmapRect, BRect bitmapRect, BRect viewRect) const
{
switch (format) {
case B_RGB32:
case B_RGBA32:
_DrawBitmap32(srcBuffer, actualBitmapRect, bitmapRect, viewRect);
break;
default:
fprintf(stderr, "Painter::_DrawBitmap() - non-native colorspace: %d\n", format);
#ifdef __HAIKU__
BBitmap temp(actualBitmapRect, 0, B_RGB32);
status_t err = temp.ImportBits(srcBuffer.buf(),
srcBuffer.height() * srcBuffer.stride(),
srcBuffer.stride(),
0, format);
if (err >= B_OK) {
agg::rendering_buffer convertedBuffer;
convertedBuffer.attach((uint8*)temp.Bits(),
(uint32)actualBitmapRect.IntegerWidth() + 1,
(uint32)actualBitmapRect.IntegerHeight() + 1,
temp.BytesPerRow());
_DrawBitmap32(convertedBuffer, actualBitmapRect, bitmapRect, viewRect);
} else {
fprintf(stderr, "Painter::_DrawBitmap() - colorspace conversion failed: %s\n", strerror(err));
}
#endif
break;
}
}
void
Painter::_DrawBitmap32(const agg::rendering_buffer& srcBuffer,
BRect actualBitmapRect, BRect bitmapRect, BRect viewRect) const
{
typedef agg::span_allocator<agg::rgba8> span_alloc_type;
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;
if (bitmapRect.IsValid() && bitmapRect.Intersects(actualBitmapRect)
&& viewRect.IsValid()) {
actualBitmapRect.OffsetBy(-actualBitmapRect.left, -actualBitmapRect.top);
double xScale = (viewRect.Width() + 1) / (bitmapRect.Width() + 1);
double yScale = (viewRect.Height() + 1) / (bitmapRect.Height() + 1);
if (bitmapRect.left < actualBitmapRect.left) {
float diff = actualBitmapRect.left - bitmapRect.left;
viewRect.left += diff * xScale;
bitmapRect.left = actualBitmapRect.left;
}
if (bitmapRect.top < actualBitmapRect.top) {
float diff = actualBitmapRect.top - bitmapRect.top;
viewRect.top += diff;
bitmapRect.top = actualBitmapRect.top;
}
if (bitmapRect.right > actualBitmapRect.right) {
float diff = bitmapRect.right - actualBitmapRect.right;
viewRect.right -= diff;
bitmapRect.right = actualBitmapRect.right;
}
if (bitmapRect.bottom > actualBitmapRect.bottom) {
float diff = bitmapRect.right - actualBitmapRect.bottom;
viewRect.bottom -= diff;
bitmapRect.bottom = actualBitmapRect.bottom;
}
float xOffset = viewRect.left - (bitmapRect.left * xScale);
float yOffset = viewRect.top - (bitmapRect.top * yScale);
agg::trans_affine srcMatrix;
srcMatrix *= agg::trans_affine_scaling(fScale, fScale);
srcMatrix *= agg::trans_affine_translation(fOrigin.x, fOrigin.y);
agg::trans_affine imgMatrix;
imgMatrix *= agg::trans_affine_scaling(xScale, yScale);
imgMatrix *= agg::trans_affine_translation(xOffset, yOffset);
imgMatrix *= agg::trans_affine_scaling(fScale, fScale);
imgMatrix *= agg::trans_affine_translation(fOrigin.x, fOrigin.y);
imgMatrix.invert();
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;
agg::path_storage path;
path.move_to(viewRect.left, viewRect.top);
path.line_to(viewRect.right + 1, viewRect.top);
path.line_to(viewRect.right + 1, viewRect.bottom + 1);
path.line_to(viewRect.left, viewRect.bottom + 1);
path.close_polygon();
agg::conv_transform<agg::path_storage> tr(path, srcMatrix);
pf.add_path(tr);
agg::render_scanlines(pf, sl, ri);
}
}
void
Painter::_InvertRect32(BRect r) const
{
if (fBuffer) {
int32 width = r.IntegerWidth() + 1;
for (int32 y = (int32)r.top; y <= (int32)r.bottom; y++) {
uint8* dst = fBuffer->row(y);
dst += (int32)r.left * 4;
for (int32 i = 0; i < width; i++) {
dst[0] = 255 - dst[0];
dst[1] = 255 - dst[1];
dst[2] = 255 - dst[2];
dst += 4;
}
}
}
}
template<class VertexSource>
BRect
Painter::_BoundingBox(VertexSource& path) const
{
double left = 0.0;
double top = 0.0;
double right = -1.0;
double bottom = -1.0;
uint32 pathID[1];
pathID[0] = 0;
agg::bounding_rect(path, pathID, 0, 1, &left, &top, &right, &bottom);
return BRect(left, top, right, bottom);
}
template<class VertexSource>
BRect
Painter::_StrokePath(VertexSource& path, const pattern& p) const
{
#if ALIASED_DRAWING
float width = fPenSize;
_Transform(&width);
if (width > 1.0) {
agg::conv_stroke<VertexSource> stroke(path);
stroke.width(width);
fRasterizer->add_path(stroke);
agg::render_scanlines(*fRasterizer, *fScanline, *fRenderer);
} else {
fOutlineRasterizer->add_path(path);
}
#else
fOutlineRasterizer->add_path(path);
#endif
return _Clipped(_BoundingBox(path));
}
template<class VertexSource>
BRect
Painter::_FillPath(VertexSource& path, const pattern& p) const
{
fRasterizer->add_path(path);
agg::render_scanlines(*fRasterizer, *fScanline, *fRenderer);
return _Clipped(_BoundingBox(path));
}
void
Painter::_SetPattern(const pattern& p) const
{
if (!(p == *fPatternHandler->GetR5Pattern())) {
printf("Painter::_SetPattern()\n");
fPatternHandler->SetPattern(p);
DrawingMode* mode = NULL;
if (p == B_SOLID_HIGH) {
_SetRendererColor(fPatternHandler->HighColor().GetColor32());
mode = DrawingModeFactory::DrawingModeFor(fDrawingMode,
fAlphaSrcMode,
fAlphaFncMode,
true);
} else if (p == B_SOLID_LOW) {
_SetRendererColor(fPatternHandler->LowColor().GetColor32());
mode = DrawingModeFactory::DrawingModeFor(fDrawingMode,
fAlphaSrcMode,
fAlphaFncMode,
true);
} else {
mode = DrawingModeFactory::DrawingModeFor(fDrawingMode,
fAlphaSrcMode,
fAlphaFncMode,
false);
}
fPixelFormat->set_drawing_mode(mode);
}
}
void
Painter::_SetRendererColor(const rgb_color& color) const
{
if (fOutlineRenderer)
#if ALIASED_DRAWING
fOutlineRenderer->line_color(agg::rgba(color.red / 255.0,
color.green / 255.0,
color.blue / 255.0));
#else
fOutlineRenderer->color(agg::rgba(color.red / 255.0,
color.green / 255.0,
color.blue / 255.0));
#endif
if (fRenderer)
fRenderer->color(agg::rgba(color.red / 255.0,
color.green / 255.0,
color.blue / 255.0));
if (fFontRendererSolid)
fFontRendererSolid->color(agg::rgba(color.red / 255.0,
color.green / 255.0,
color.blue / 255.0));
if (fFontRendererBin)
fFontRendererBin->color(agg::rgba(color.red / 255.0,
color.green / 255.0,
color.blue / 255.0));
}