130f5afc8SStephan Aßmus// Painter.cpp
230f5afc8SStephan Aßmus
330f5afc8SStephan Aßmus#include <stdio.h>
430f5afc8SStephan Aßmus#include <string.h>
530f5afc8SStephan Aßmus
630f5afc8SStephan Aßmus#include <Bitmap.h>
730f5afc8SStephan Aßmus#include <GraphicsDefs.h>
830f5afc8SStephan Aßmus#include <Region.h>
930f5afc8SStephan Aßmus
1030f5afc8SStephan Aßmus#include <agg_bezier_arc.h>
1130f5afc8SStephan Aßmus#include <agg_bounding_rect.h>
1230f5afc8SStephan Aßmus#include <agg_conv_curve.h>
1330f5afc8SStephan Aßmus#include <agg_conv_stroke.h>
1430f5afc8SStephan Aßmus#include <agg_ellipse.h>
1530f5afc8SStephan Aßmus#include <agg_path_storage.h>
1630f5afc8SStephan Aßmus#include <agg_rounded_rect.h>
1730f5afc8SStephan Aßmus#include <agg_span_image_filter_rgba32.h>
1830f5afc8SStephan Aßmus#include <agg_span_interpolator_linear.h>
1930f5afc8SStephan Aßmus
2030f5afc8SStephan Aßmus#include "LayerData.h"
2130f5afc8SStephan Aßmus
2230f5afc8SStephan Aßmus#include "AGGTextRenderer.h"
2330f5afc8SStephan Aßmus#include "DrawingMode.h"
2430f5afc8SStephan Aßmus#include "DrawingModeFactory.h"
2530f5afc8SStephan Aßmus#include "FontManager.h"
2630f5afc8SStephan Aßmus#include "PatternHandler.h"
2730f5afc8SStephan Aßmus#include "RenderingBuffer.h"
2830f5afc8SStephan Aßmus#include "ShapeConverter.h"
2930f5afc8SStephan Aßmus#include "ServerBitmap.h"
3030f5afc8SStephan Aßmus#include "ServerFont.h"
3130f5afc8SStephan Aßmus
3230f5afc8SStephan Aßmus#include "Painter.h"
3330f5afc8SStephan Aßmus
3430f5afc8SStephan Aßmusint
3530f5afc8SStephan Aßmusroundf(float v)
3630f5afc8SStephan Aßmus{
3730f5afc8SStephan Aßmus	if (v >= 0.0)
3830f5afc8SStephan Aßmus		return (int)floorf(v + 0.5);
3930f5afc8SStephan Aßmus	else
4030f5afc8SStephan Aßmus		return (int)floorf(v - 0.5);
4130f5afc8SStephan Aßmus}
4230f5afc8SStephan Aßmus
4330f5afc8SStephan Aßmus// constructor
4430f5afc8SStephan AßmusPainter::Painter()
4530f5afc8SStephan Aßmus	: fBuffer(NULL),
4630f5afc8SStephan Aßmus	  fPixelFormat(NULL),
4730f5afc8SStephan Aßmus	  fBaseRenderer(NULL),
4830f5afc8SStephan Aßmus	  fOutlineRenderer(NULL),
4930f5afc8SStephan Aßmus	  fOutlineRasterizer(NULL),
5030f5afc8SStephan Aßmus	  fScanline(NULL),
5130f5afc8SStephan Aßmus	  fRasterizer(NULL),
5230f5afc8SStephan Aßmus	  fRenderer(NULL),
5330f5afc8SStephan Aßmus	  fFontRendererSolid(NULL),
5430f5afc8SStephan Aßmus	  fFontRendererBin(NULL),
5530f5afc8SStephan Aßmus	  fLineProfile(),
5630f5afc8SStephan Aßmus	  fSubpixelPrecise(false),
5730f5afc8SStephan Aßmus	  fScale(1.0),
5830f5afc8SStephan Aßmus	  fPenSize(1.0),
5930f5afc8SStephan Aßmus	  fOrigin(0.0, 0.0),
6030f5afc8SStephan Aßmus	  fClippingRegion(NULL),
6130f5afc8SStephan Aßmus	  fDrawingMode(B_OP_COPY),
6230f5afc8SStephan Aßmus	  fAlphaSrcMode(B_PIXEL_ALPHA),
6330f5afc8SStephan Aßmus//	  fAlphaSrcMode(B_CONSTANT_ALPHA),
6430f5afc8SStephan Aßmus	  fAlphaFncMode(B_ALPHA_OVERLAY),
6530f5afc8SStephan Aßmus	  fPenLocation(0.0, 0.0),
6630f5afc8SStephan Aßmus	  fPatternHandler(new PatternHandler()),
6730f5afc8SStephan Aßmus	  fTextRenderer(new AGGTextRenderer()),
6830f5afc8SStephan Aßmus	  fLastFamilyAndStyle(0)
6930f5afc8SStephan Aßmus{
7030f5afc8SStephan Aßmus	if (fontserver)
7130f5afc8SStephan Aßmus		fFont = *fontserver->GetSystemPlain();
7230f5afc8SStephan Aßmus
7330f5afc8SStephan Aßmus	_UpdateFont();
7430f5afc8SStephan Aßmus	_UpdateLineWidth();
7530f5afc8SStephan Aßmus}
7630f5afc8SStephan Aßmus
7730f5afc8SStephan Aßmus// destructor
7830f5afc8SStephan AßmusPainter::~Painter()
7930f5afc8SStephan Aßmus{
8030f5afc8SStephan Aßmus	_MakeEmpty();
8130f5afc8SStephan Aßmus
8230f5afc8SStephan Aßmus	delete fClippingRegion;
8330f5afc8SStephan Aßmus	delete fPatternHandler;
8430f5afc8SStephan Aßmus	delete fTextRenderer;
8530f5afc8SStephan Aßmus}
8630f5afc8SStephan Aßmus
8730f5afc8SStephan Aßmus// #pragma mark -
8830f5afc8SStephan Aßmus
8930f5afc8SStephan Aßmus// AttachToBuffer
9030f5afc8SStephan Aßmusvoid
9130f5afc8SStephan AßmusPainter::AttachToBuffer(RenderingBuffer* buffer)
9230f5afc8SStephan Aßmus{
9330f5afc8SStephan Aßmus	if (buffer && buffer->InitCheck() >= B_OK) {
9430f5afc8SStephan Aßmus		// clean up previous stuff
9530f5afc8SStephan Aßmus		_MakeEmpty();
9630f5afc8SStephan Aßmus
9730f5afc8SStephan Aßmus		fBuffer = new agg::rendering_buffer();
9830f5afc8SStephan Aßmus		fBuffer->attach((uint8*)buffer->Bits(),
9930f5afc8SStephan Aßmus						buffer->Width(),
10030f5afc8SStephan Aßmus						buffer->Height(),
10130f5afc8SStephan Aßmus						buffer->BytesPerRow());
10230f5afc8SStephan Aßmus
10330f5afc8SStephan Aßmus		fPixelFormat = new pixfmt(*fBuffer, fPatternHandler);
10430f5afc8SStephan Aßmus		fPixelFormat->set_drawing_mode(DrawingModeFactory::DrawingModeFor(fDrawingMode,
10530f5afc8SStephan Aßmus																		  fAlphaSrcMode,
10630f5afc8SStephan Aßmus																		  fAlphaFncMode,
10730f5afc8SStephan Aßmus																		  false));
10830f5afc8SStephan Aßmus
10930f5afc8SStephan Aßmus		fBaseRenderer = new renderer_base(*fPixelFormat);
11030f5afc8SStephan Aßmus
11130f5afc8SStephan Aßmus		// These are the AGG renderes and rasterizes which
11230f5afc8SStephan Aßmus		// will be used for stroking paths
11330f5afc8SStephan Aßmusrgb_color color = fPatternHandler->HighColor().GetColor32();
11430f5afc8SStephan Aßmus#if ALIASED_DRAWING
11530f5afc8SStephan Aßmus		fOutlineRenderer = new outline_renderer_type(*fBaseRenderer);
11630f5afc8SStephan Aßmus		fOutlineRasterizer = new outline_rasterizer_type(*fOutlineRenderer);
11730f5afc8SStephan Aßmus#else
11830f5afc8SStephan Aßmus		fOutlineRenderer = new outline_renderer_type(*fBaseRenderer, fLineProfile);
11930f5afc8SStephan Aßmus		fOutlineRasterizer = new outline_rasterizer_type(*fOutlineRenderer);
12030f5afc8SStephan Aßmus
12130f5afc8SStephan Aßmus		// attach our line profile to the renderer, it keeps a pointer
12230f5afc8SStephan Aßmus		fOutlineRenderer->profile(fLineProfile);
12330f5afc8SStephan Aßmus#endif
12430f5afc8SStephan Aßmus		// the renderer used for filling paths
12530f5afc8SStephan Aßmus		fRenderer = new renderer_type(*fBaseRenderer);
12630f5afc8SStephan Aßmus		fRasterizer = new rasterizer_type();
12730f5afc8SStephan Aßmus		fScanline = new scanline_type();
12830f5afc8SStephan Aßmus
12930f5afc8SStephan Aßmus#if ALIASED_DRAWING
13030f5afc8SStephan Aßmus		fRasterizer->gamma(agg::gamma_threshold(0.5));
13130f5afc8SStephan Aßmus#endif
13230f5afc8SStephan Aßmus
13330f5afc8SStephan Aßmus		// These are renderers needed for drawing text
13430f5afc8SStephan Aßmus		fFontRendererSolid = new font_renderer_solid_type(*fBaseRenderer);
13530f5afc8SStephan Aßmus		fFontRendererBin = new font_renderer_bin_type(*fBaseRenderer);
13630f5afc8SStephan Aßmus
13730f5afc8SStephan Aßmus		_SetRendererColor(fPatternHandler->HighColor().GetColor32());
13830f5afc8SStephan Aßmus		_RebuildClipping();
13930f5afc8SStephan Aßmus	}
14030f5afc8SStephan Aßmus}
14130f5afc8SStephan Aßmus
14230f5afc8SStephan Aßmus// DetachFromBuffer
14330f5afc8SStephan Aßmusvoid
14430f5afc8SStephan AßmusPainter::DetachFromBuffer()
14530f5afc8SStephan Aßmus{
14630f5afc8SStephan Aßmus	_MakeEmpty();
14730f5afc8SStephan Aßmus}
14830f5afc8SStephan Aßmus
14930f5afc8SStephan Aßmus// SetDrawData
15030f5afc8SStephan Aßmusvoid
15130f5afc8SStephan AßmusPainter::SetDrawData(const DrawData* data)
15230f5afc8SStephan Aßmus{
15330f5afc8SStephan Aßmus	// for now...
15430f5afc8SStephan Aßmus	SetHighColor(data->highcolor.GetColor32());
15530f5afc8SStephan Aßmus	SetLowColor(data->lowcolor.GetColor32());
15630f5afc8SStephan Aßmus	SetScale(data->scale);
15730f5afc8SStephan Aßmus	SetPenSize(data->pensize);
15830f5afc8SStephan Aßmus//	fOrigin = data->coordOrigin;
15930f5afc8SStephan Aßmus	SetDrawingMode(data->draw_mode);
16030f5afc8SStephan Aßmus	SetBlendingMode(data->alphaSrcMode, data->alphaFncMode);
16130f5afc8SStephan Aßmus	SetPenLocation(data->penlocation);
16230f5afc8SStephan Aßmus	SetFont(data->font);
16330f5afc8SStephan Aßmus//	if (data->clipReg) {
16430f5afc8SStephan Aßmus//		ConstrainClipping(*data->clipReg);
16530f5afc8SStephan Aßmus//	}
16630f5afc8SStephan Aßmus	fPatternHandler->SetPattern(data->patt);
16730f5afc8SStephan Aßmus}
16830f5afc8SStephan Aßmus
16930f5afc8SStephan Aßmus// #pragma mark -
17030f5afc8SStephan Aßmus
17130f5afc8SStephan Aßmus// ConstrainClipping
17230f5afc8SStephan Aßmusvoid
17330f5afc8SStephan AßmusPainter::ConstrainClipping(const BRegion& region)
17430f5afc8SStephan Aßmus{
17530f5afc8SStephan Aßmus	// The idea is that if the clipping region was
17630f5afc8SStephan Aßmus	// never constrained, there is *no* clipping.
17730f5afc8SStephan Aßmus	// This is of course different from having
17830f5afc8SStephan Aßmus	// an *empty* clipping region.
17930f5afc8SStephan Aßmus	if (!fClippingRegion)
18030f5afc8SStephan Aßmus		fClippingRegion = new BRegion(region);
18130f5afc8SStephan Aßmus	else
18230f5afc8SStephan Aßmus		*fClippingRegion = region;
18330f5afc8SStephan Aßmus	_RebuildClipping();
18430f5afc8SStephan Aßmus}
18530f5afc8SStephan Aßmus
18630f5afc8SStephan Aßmus// SetHighColor
18730f5afc8SStephan Aßmusvoid
18830f5afc8SStephan AßmusPainter::SetHighColor(const rgb_color& color)
18930f5afc8SStephan Aßmus{
19030f5afc8SStephan Aßmus	fPatternHandler->SetHighColor(color);
19130f5afc8SStephan Aßmus}
19230f5afc8SStephan Aßmus
19330f5afc8SStephan Aßmus// SetLowColor
19430f5afc8SStephan Aßmusvoid
19530f5afc8SStephan AßmusPainter::SetLowColor(const rgb_color& color)
19630f5afc8SStephan Aßmus{
19730f5afc8SStephan Aßmus	fPatternHandler->SetLowColor(color);;
19830f5afc8SStephan Aßmus}
19930f5afc8SStephan Aßmus
20030f5afc8SStephan Aßmus// SetScale
20130f5afc8SStephan Aßmusvoid
20230f5afc8SStephan AßmusPainter::SetScale(float scale)
20330f5afc8SStephan Aßmus{
20430f5afc8SStephan Aßmus	if (fScale != scale) {
20530f5afc8SStephan Aßmus		fScale = scale;
20630f5afc8SStephan Aßmus		_RebuildClipping();
20730f5afc8SStephan Aßmus		_UpdateLineWidth();
20830f5afc8SStephan Aßmus	}
20930f5afc8SStephan Aßmus}
21030f5afc8SStephan Aßmus
21130f5afc8SStephan Aßmus// SetPenSize
21230f5afc8SStephan Aßmusvoid
21330f5afc8SStephan AßmusPainter::SetPenSize(float size)
21430f5afc8SStephan Aßmus{
21530f5afc8SStephan Aßmus	if (fPenSize != size) {
21630f5afc8SStephan Aßmus		fPenSize = size;
21730f5afc8SStephan Aßmus		_UpdateLineWidth();
21830f5afc8SStephan Aßmus	}
21930f5afc8SStephan Aßmus}
22030f5afc8SStephan Aßmus
22130f5afc8SStephan Aßmus// SetOrigin
22230f5afc8SStephan Aßmusvoid
22330f5afc8SStephan AßmusPainter::SetOrigin(const BPoint& origin)
22430f5afc8SStephan Aßmus{
22530f5afc8SStephan Aßmus	// NOTE: The BeBook says that the coordinate system
22630f5afc8SStephan Aßmus	// of a view cannot be changed during an update, because
22730f5afc8SStephan Aßmus	// it would mess up the clipping, and this is indeed
22830f5afc8SStephan Aßmus	// what would happen in this implementation as well.
22930f5afc8SStephan Aßmus	// I don't know yet what actually happens if you still
23030f5afc8SStephan Aßmus	// try to call SetOrigin() from within BView::Draw()
23130f5afc8SStephan Aßmus	fOrigin = origin;
23230f5afc8SStephan Aßmus	_RebuildClipping();
23330f5afc8SStephan Aßmus}
23430f5afc8SStephan Aßmus
23530f5afc8SStephan Aßmus// SetDrawingMode
23630f5afc8SStephan Aßmusvoid
23730f5afc8SStephan AßmusPainter::SetDrawingMode(drawing_mode mode)
23830f5afc8SStephan Aßmus{
23930f5afc8SStephan Aßmus	if (fDrawingMode != mode) {
24030f5afc8SStephan Aßmus		fDrawingMode = mode;
24130f5afc8SStephan Aßmus		if (fPixelFormat) {
24230f5afc8SStephan Aßmus			fPixelFormat->set_drawing_mode(DrawingModeFactory::DrawingModeFor(fDrawingMode,
24330f5afc8SStephan Aßmus																			  fAlphaSrcMode,
24430f5afc8SStephan Aßmus																			  fAlphaFncMode));
24530f5afc8SStephan Aßmus		}
24630f5afc8SStephan Aßmus	}
24730f5afc8SStephan Aßmus}
24830f5afc8SStephan Aßmus
24930f5afc8SStephan Aßmus// SetBlendingMode
25030f5afc8SStephan Aßmusvoid
25130f5afc8SStephan AßmusPainter::SetBlendingMode(source_alpha alphaSrcMode, alpha_function alphaFncMode)
25230f5afc8SStephan Aßmus{
25330f5afc8SStephan Aßmus	if (fAlphaSrcMode != alphaSrcMode || fAlphaFncMode != alphaFncMode) {
25430f5afc8SStephan Aßmus		fAlphaSrcMode = alphaSrcMode;
25530f5afc8SStephan Aßmus		fAlphaFncMode = alphaFncMode;
25630f5afc8SStephan Aßmus		if (fDrawingMode == B_OP_ALPHA && fPixelFormat) {
25730f5afc8SStephan Aßmus			fPixelFormat->set_drawing_mode(DrawingModeFactory::DrawingModeFor(fDrawingMode,
25830f5afc8SStephan Aßmus																			  fAlphaSrcMode,
25930f5afc8SStephan Aßmus																			  fAlphaFncMode));
26030f5afc8SStephan Aßmus		}
26130f5afc8SStephan Aßmus	}
26230f5afc8SStephan Aßmus}
26330f5afc8SStephan Aßmus
26430f5afc8SStephan Aßmus// SetPenLocation
26530f5afc8SStephan Aßmusvoid
26630f5afc8SStephan AßmusPainter::SetPenLocation(const BPoint& location)
26730f5afc8SStephan Aßmus{
26830f5afc8SStephan Aßmus	fPenLocation = location;
26930f5afc8SStephan Aßmus}
27030f5afc8SStephan Aßmus
27130f5afc8SStephan Aßmus// SetFont
27230f5afc8SStephan Aßmusvoid
27330f5afc8SStephan AßmusPainter::SetFont(const BFont& font)
27430f5afc8SStephan Aßmus{
27530f5afc8SStephan Aßmus	//fFont.SetFamilyAndStyle(font.GetFamily(), font.GetStyle());
27630f5afc8SStephan Aßmus	fFont.SetSpacing(font.Spacing());
27730f5afc8SStephan Aßmus	fFont.SetShear(font.Shear());
27830f5afc8SStephan Aßmus	fFont.SetRotation(font.Rotation());
27930f5afc8SStephan Aßmus	fFont.SetSize(font.Size());
28030f5afc8SStephan Aßmus
28130f5afc8SStephan Aßmus	_UpdateFont();
28230f5afc8SStephan Aßmus}
28330f5afc8SStephan Aßmus
28430f5afc8SStephan Aßmus// SetFont
28530f5afc8SStephan Aßmusvoid
28630f5afc8SStephan AßmusPainter::SetFont(const ServerFont& font)
28730f5afc8SStephan Aßmus{
28830f5afc8SStephan Aßmus	fFont = font;
28930f5afc8SStephan Aßmus	_UpdateFont();
29030f5afc8SStephan Aßmus}
29130f5afc8SStephan Aßmus
29230f5afc8SStephan Aßmus// #pragma mark -
29330f5afc8SStephan Aßmus
29430f5afc8SStephan Aßmus// StrokeLine
29530f5afc8SStephan AßmusBRect
29630f5afc8SStephan AßmusPainter::StrokeLine(BPoint a, BPoint b, const pattern& p)
29730f5afc8SStephan Aßmus{
29830f5afc8SStephan Aßmus	_Transform(&a);
29930f5afc8SStephan Aßmus	_Transform(&b);
30030f5afc8SStephan Aßmus
30130f5afc8SStephan Aßmus	BRect touched(a, b);
30230f5afc8SStephan Aßmus
30330f5afc8SStephan Aßmus	// first, try an optimized version
30430f5afc8SStephan Aßmus	float penSize = _Transform(fPenSize);
30530f5afc8SStephan Aßmus	if (penSize == 1.0 &&
30630f5afc8SStephan Aßmus		(fDrawingMode == B_OP_COPY || fDrawingMode == B_OP_OVER)) {
30730f5afc8SStephan Aßmus		pattern pat = *fPatternHandler->GetR5Pattern();
30830f5afc8SStephan Aßmus		if (pat == B_SOLID_HIGH &&
30930f5afc8SStephan Aßmus			StraightLine(a, b, fPatternHandler->HighColor().GetColor32())) {
31030f5afc8SStephan Aßmus			SetPenLocation(b);
31130f5afc8SStephan Aßmus			return _Clipped(touched);
31230f5afc8SStephan Aßmus		} else if (pat == B_SOLID_LOW &&
31330f5afc8SStephan Aßmus			StraightLine(a, b, fPatternHandler->LowColor().GetColor32())) {
31430f5afc8SStephan Aßmus			SetPenLocation(b);
31530f5afc8SStephan Aßmus			return _Clipped(touched);
31630f5afc8SStephan Aßmus		}
31730f5afc8SStephan Aßmus	}
31830f5afc8SStephan Aßmus
31930f5afc8SStephan Aßmus	agg::path_storage path;
32030f5afc8SStephan Aßmus	path.move_to(a.x, a.y);
32130f5afc8SStephan Aßmus	path.line_to(b.x, b.y);
32230f5afc8SStephan Aßmus
32330f5afc8SStephan Aßmus	touched = _StrokePath(path, p);
32430f5afc8SStephan Aßmus
32530f5afc8SStephan Aßmus	SetPenLocation(b);
32630f5afc8SStephan Aßmus
32730f5afc8SStephan Aßmus	return _Clipped(touched);
32830f5afc8SStephan Aßmus}
32930f5afc8SStephan Aßmus
33030f5afc8SStephan Aßmus// StrokeLine
33130f5afc8SStephan AßmusBRect
33230f5afc8SStephan AßmusPainter::StrokeLine(BPoint b, const pattern& p)
33330f5afc8SStephan Aßmus{
33430f5afc8SStephan Aßmus	// TODO: move this function elsewhere
33530f5afc8SStephan Aßmus	return StrokeLine(fPenLocation, b);
33630f5afc8SStephan Aßmus}
33730f5afc8SStephan Aßmus
33830f5afc8SStephan Aßmus// StraightLine
33930f5afc8SStephan Aßmusbool
34030f5afc8SStephan AßmusPainter::StraightLine(BPoint a, BPoint b, const rgb_color& c) const
34130f5afc8SStephan Aßmus{
34230f5afc8SStephan Aßmus	if (fBuffer) {
34330f5afc8SStephan Aßmus		if (a.x == b.x) {
34430f5afc8SStephan Aßmus			// vertical
34530f5afc8SStephan Aßmus			uint8* dst = fBuffer->row(0);
34630f5afc8SStephan Aßmus			uint32 bpr = fBuffer->stride();
34730f5afc8SStephan Aßmus			int32 x = (int32)a.x;
34830f5afc8SStephan Aßmus			dst += x * 4;
34930f5afc8SStephan Aßmus			int32 y1 = (int32)min_c(a.y, b.y);
35030f5afc8SStephan Aßmus			int32 y2 = (int32)max_c(a.y, b.y);
35130f5afc8SStephan Aßmus			// draw a line, iterate over clipping boxes
35230f5afc8SStephan Aßmus			fBaseRenderer->first_clip_box();
35330f5afc8SStephan Aßmus			do {
35430f5afc8SStephan Aßmus				if (fBaseRenderer->xmin() <= x &&
35530f5afc8SStephan Aßmus					fBaseRenderer->xmax() >= x) {
35630f5afc8SStephan Aßmus					int32 i = max_c(fBaseRenderer->ymin(), y1);
35730f5afc8SStephan Aßmus					int32 end = min_c(fBaseRenderer->ymax(), y2);
35830f5afc8SStephan Aßmus					uint8* handle = dst + i * bpr;
35930f5afc8SStephan Aßmus					for (; i <= end; i++) {
36030f5afc8SStephan Aßmus						handle[0] = c.blue;
36130f5afc8SStephan Aßmus						handle[1] = c.green;
36230f5afc8SStephan Aßmus						handle[2] = c.red;
36330f5afc8SStephan Aßmus						handle += bpr;
36430f5afc8SStephan Aßmus					}
36530f5afc8SStephan Aßmus				}
36630f5afc8SStephan Aßmus			} while (fBaseRenderer->next_clip_box());
36730f5afc8SStephan Aßmus
36830f5afc8SStephan Aßmus			return true;
36930f5afc8SStephan Aßmus
37030f5afc8SStephan Aßmus		} else if (a.y == b.y) {
37130f5afc8SStephan Aßmus			// horizontal
37230f5afc8SStephan Aßmus			uint8* dst = fBuffer->row(0);
37330f5afc8SStephan Aßmus			uint32 bpr = fBuffer->stride();
37430f5afc8SStephan Aßmus			int32 y = (int32)a.y;
37530f5afc8SStephan Aßmus			dst += y * bpr;
37630f5afc8SStephan Aßmus			int32 x1 = (int32)min_c(a.x, b.x);
37730f5afc8SStephan Aßmus			int32 x2 = (int32)max_c(a.x, b.x);
37830f5afc8SStephan Aßmus			// draw a line, iterate over clipping boxes
37930f5afc8SStephan Aßmus			fBaseRenderer->first_clip_box();
38030f5afc8SStephan Aßmus			do {
38130f5afc8SStephan Aßmus				if (fBaseRenderer->ymin() <= y &&
38230f5afc8SStephan Aßmus					fBaseRenderer->ymax() >= y) {
38330f5afc8SStephan Aßmus					int32 i = max_c(fBaseRenderer->xmin(), x1);
38430f5afc8SStephan Aßmus					int32 end = min_c(fBaseRenderer->xmax(), x2);
38530f5afc8SStephan Aßmus					uint8* handle = dst + i * 4;
38630f5afc8SStephan Aßmus					for (; i <= end; i++) {
38730f5afc8SStephan Aßmus						handle[0] = c.blue;
38830f5afc8SStephan Aßmus						handle[1] = c.green;
38930f5afc8SStephan Aßmus						handle[2] = c.red;
39030f5afc8SStephan Aßmus						handle += 4;
39130f5afc8SStephan Aßmus					}
39230f5afc8SStephan Aßmus				}
39330f5afc8SStephan Aßmus			} while (fBaseRenderer->next_clip_box());
39430f5afc8SStephan Aßmus
39530f5afc8SStephan Aßmus			return true;
39630f5afc8SStephan Aßmus		}
39730f5afc8SStephan Aßmus	}
39830f5afc8SStephan Aßmus	return false;
39930f5afc8SStephan Aßmus}
40030f5afc8SStephan Aßmus
40130f5afc8SStephan Aßmus// #pragma mark -
40230f5afc8SStephan Aßmus
40330f5afc8SStephan Aßmus// StrokeTriangle
40430f5afc8SStephan Aßmusvoid
40530f5afc8SStephan AßmusPainter::StrokeTriangle(BPoint pt1, BPoint pt2, BPoint pt3, const pattern& p) const
40630f5afc8SStephan Aßmus{
40730f5afc8SStephan Aßmus	_DrawTriangle(pt1, pt2, pt3, p, false);
40830f5afc8SStephan Aßmus}
40930f5afc8SStephan Aßmus
41030f5afc8SStephan Aßmus// FillTriangle
41130f5afc8SStephan Aßmusvoid
41230f5afc8SStephan AßmusPainter::FillTriangle(BPoint pt1, BPoint pt2, BPoint pt3, const pattern& p) const
41330f5afc8SStephan Aßmus{
41430f5afc8SStephan Aßmus	_DrawTriangle(pt1, pt2, pt3, p, true);
41530f5afc8SStephan Aßmus}
41630f5afc8SStephan Aßmus
41730f5afc8SStephan Aßmus// StrokePolygon
41830f5afc8SStephan Aßmusvoid
41930f5afc8SStephan AßmusPainter::StrokePolygon(const BPoint* ptArray, int32 numPts,
42030f5afc8SStephan Aßmus					   bool closed, const pattern& p) const
42130f5afc8SStephan Aßmus{
42230f5afc8SStephan Aßmus	_DrawPolygon(ptArray, numPts, closed, p, false);
42330f5afc8SStephan Aßmus}
42430f5afc8SStephan Aßmus
42530f5afc8SStephan Aßmus// FillPolygon
42630f5afc8SStephan Aßmusvoid
42730f5afc8SStephan AßmusPainter::FillPolygon(const BPoint* ptArray, int32 numPts,
42830f5afc8SStephan Aßmus					   bool closed, const pattern& p) const
42930f5afc8SStephan Aßmus{
43030f5afc8SStephan Aßmus	_DrawPolygon(ptArray, numPts, closed, p, true);
43130f5afc8SStephan Aßmus}
43230f5afc8SStephan Aßmus
43330f5afc8SStephan Aßmus// StrokeBezier
43430f5afc8SStephan Aßmusvoid
43530f5afc8SStephan AßmusPainter::StrokeBezier(const BPoint* controlPoints, const pattern& p) const
43630f5afc8SStephan Aßmus{
43730f5afc8SStephan Aßmus	agg::path_storage curve;
43830f5afc8SStephan Aßmus
43930f5afc8SStephan Aßmus	BPoint p1(controlPoints[0]);
44030f5afc8SStephan Aßmus	BPoint p2(controlPoints[1]);
44130f5afc8SStephan Aßmus	BPoint p3(controlPoints[2]);
44230f5afc8SStephan Aßmus	BPoint p4(controlPoints[3]);
44330f5afc8SStephan Aßmus	_Transform(&p1);
44430f5afc8SStephan Aßmus	_Transform(&p2);
44530f5afc8SStephan Aßmus	_Transform(&p3);
44630f5afc8SStephan Aßmus	_Transform(&p4);
44730f5afc8SStephan Aßmus
44830f5afc8SStephan Aßmus	curve.move_to(p1.x, p1.y);
44930f5afc8SStephan Aßmus	curve.curve4(p1.x, p1.y,
45030f5afc8SStephan Aßmus				 p2.x, p2.y,
45130f5afc8SStephan Aßmus				 p3.x, p3.y);
45230f5afc8SStephan Aßmus
45330f5afc8SStephan Aßmus
45430f5afc8SStephan Aßmus	agg::conv_curve<agg::path_storage> path(curve);
45530f5afc8SStephan Aßmus
45630f5afc8SStephan Aßmus	_StrokePath(path, p);
45730f5afc8SStephan Aßmus}
45830f5afc8SStephan Aßmus
45930f5afc8SStephan Aßmus// FillBezier
46030f5afc8SStephan Aßmusvoid
46130f5afc8SStephan AßmusPainter::FillBezier(const BPoint* controlPoints, const pattern& p) const
46230f5afc8SStephan Aßmus{
46330f5afc8SStephan Aßmus	agg::path_storage curve;
46430f5afc8SStephan Aßmus
46530f5afc8SStephan Aßmus	BPoint p1(controlPoints[0]);
46630f5afc8SStephan Aßmus	BPoint p2(controlPoints[1]);
46730f5afc8SStephan Aßmus	BPoint p3(controlPoints[2]);
46830f5afc8SStephan Aßmus	BPoint p4(controlPoints[3]);
46930f5afc8SStephan Aßmus	_Transform(&p1);
47030f5afc8SStephan Aßmus	_Transform(&p2);
47130f5afc8SStephan Aßmus	_Transform(&p3);
47230f5afc8SStephan Aßmus	_Transform(&p4);
47330f5afc8SStephan Aßmus
47430f5afc8SStephan Aßmus	curve.move_to(p1.x, p1.y);
47530f5afc8SStephan Aßmus	curve.curve4(p1.x, p1.y,
47630f5afc8SStephan Aßmus				 p2.x, p2.y,
47730f5afc8SStephan Aßmus				 p3.x, p3.y);
47830f5afc8SStephan Aßmus	curve.close_polygon();
47930f5afc8SStephan Aßmus
48030f5afc8SStephan Aßmus	agg::conv_curve<agg::path_storage> path(curve);
48130f5afc8SStephan Aßmus
48230f5afc8SStephan Aßmus	_FillPath(path, p);
48330f5afc8SStephan Aßmus}
48430f5afc8SStephan Aßmus
48530f5afc8SStephan Aßmus// StrokeShape
48630f5afc8SStephan Aßmusvoid
48730f5afc8SStephan AßmusPainter::StrokeShape(/*const */BShape* shape, const pattern& p) const
48830f5afc8SStephan Aßmus{
48930f5afc8SStephan Aßmus	_DrawShape(shape, p, false);
49030f5afc8SStephan Aßmus}
49130f5afc8SStephan Aßmus
49230f5afc8SStephan Aßmus// FillShape
49330f5afc8SStephan Aßmusvoid
49430f5afc8SStephan AßmusPainter::FillShape(/*const */BShape* shape, const pattern& p) const
49530f5afc8SStephan Aßmus{
49630f5afc8SStephan Aßmus	_DrawShape(shape, p, true);
49730f5afc8SStephan Aßmus}
49830f5afc8SStephan Aßmus
49930f5afc8SStephan Aßmus// StrokeRect
50030f5afc8SStephan AßmusBRect
50130f5afc8SStephan AßmusPainter::StrokeRect(const BRect& r, const pattern& p) const
50230f5afc8SStephan Aßmus{
50330f5afc8SStephan Aßmus	BPoint a(r.left, r.top);
50430f5afc8SStephan Aßmus	BPoint b(r.right, r.bottom);
50530f5afc8SStephan Aßmus	_Transform(&a);
50630f5afc8SStephan Aßmus	_Transform(&b);
50730f5afc8SStephan Aßmus
50830f5afc8SStephan Aßmus	// first, try an optimized version
50930f5afc8SStephan Aßmus	float penSize = _Transform(fPenSize);
51030f5afc8SStephan Aßmus	if (penSize == 1.0 &&
51130f5afc8SStephan Aßmus		(fDrawingMode == B_OP_COPY || fDrawingMode == B_OP_OVER)) {
51230f5afc8SStephan Aßmus// TODO: fix me
51330f5afc8SStephan Aßmus//		pattern p = *fPatternHandler->GetR5Pattern();
51430f5afc8SStephan Aßmus		if (p == B_SOLID_HIGH) {
51530f5afc8SStephan Aßmus			BRect rect(a, b);
51630f5afc8SStephan Aßmus			StrokeRect(rect,
51730f5afc8SStephan Aßmus					   fPatternHandler->HighColor().GetColor32());
51830f5afc8SStephan Aßmus			return _Clipped(rect);
51930f5afc8SStephan Aßmus		} else if (p == B_SOLID_LOW) {
52030f5afc8SStephan Aßmus			BRect rect(a, b);
52130f5afc8SStephan Aßmus			StrokeRect(rect,
52230f5afc8SStephan Aßmus					   fPatternHandler->LowColor().GetColor32());
52330f5afc8SStephan Aßmus			return _Clipped(rect);
52430f5afc8SStephan Aßmus		}
52530f5afc8SStephan Aßmus	}
52630f5afc8SStephan Aßmus
52730f5afc8SStephan Aßmus	agg::path_storage path;
52830f5afc8SStephan Aßmus	path.move_to(a.x, a.y);
52930f5afc8SStephan Aßmus	path.line_to(b.x, a.y);
53030f5afc8SStephan Aßmus	path.line_to(b.x, b.y);
53130f5afc8SStephan Aßmus	path.line_to(a.x, b.y);
53230f5afc8SStephan Aßmus	path.close_polygon();
53330f5afc8SStephan Aßmus
53430f5afc8SStephan Aßmus	return _StrokePath(path, p);
53530f5afc8SStephan Aßmus}
53630f5afc8SStephan Aßmus
53730f5afc8SStephan Aßmus// StrokeRect
53830f5afc8SStephan Aßmusvoid
53930f5afc8SStephan AßmusPainter::StrokeRect(const BRect& r, const rgb_color& c) const
54030f5afc8SStephan Aßmus{
54130f5afc8SStephan Aßmus	StraightLine(BPoint(r.left, r.top),
54230f5afc8SStephan Aßmus				 BPoint(r.right - 1, r.top), c);
54330f5afc8SStephan Aßmus	StraightLine(BPoint(r.right, r.top),
54430f5afc8SStephan Aßmus				 BPoint(r.right, r.bottom - 1), c);
54530f5afc8SStephan Aßmus	StraightLine(BPoint(r.right, r.bottom),
54630f5afc8SStephan Aßmus				 BPoint(r.left + 1, r.bottom), c);
54730f5afc8SStephan Aßmus	StraightLine(BPoint(r.left, r.bottom),
54830f5afc8SStephan Aßmus				 BPoint(r.left, r.top + 1), c);
54930f5afc8SStephan Aßmus}
55030f5afc8SStephan Aßmus
55130f5afc8SStephan Aßmus// FillRect
55230f5afc8SStephan AßmusBRect
55330f5afc8SStephan AßmusPainter::FillRect(const BRect& r, const pattern& p) const
55430f5afc8SStephan Aßmus{
55530f5afc8SStephan Aßmus	BPoint a(r.left, r.top);
55630f5afc8SStephan Aßmus	BPoint b(r.right, r.bottom);
55730f5afc8SStephan Aßmus	_Transform(&a, false);
55830f5afc8SStephan Aßmus	_Transform(&b, false);
55930f5afc8SStephan Aßmus
56030f5afc8SStephan Aßmus	// first, try an optimized version
56130f5afc8SStephan Aßmus	if (fDrawingMode == B_OP_COPY || fDrawingMode == B_OP_OVER) {
56230f5afc8SStephan Aßmus		pattern pat = *fPatternHandler->GetR5Pattern();
56330f5afc8SStephan Aßmus		if (pat == B_SOLID_HIGH) {
56430f5afc8SStephan Aßmus			BRect rect(a, b);
56530f5afc8SStephan Aßmus			FillRect(rect, fPatternHandler->HighColor().GetColor32());
56630f5afc8SStephan Aßmus			return _Clipped(rect);
56730f5afc8SStephan Aßmus		} else if (pat == B_SOLID_LOW) {
56830f5afc8SStephan Aßmus			BRect rect(a, b);
56930f5afc8SStephan Aßmus			FillRect(rect, fPatternHandler->LowColor().GetColor32());
57030f5afc8SStephan Aßmus			return _Clipped(rect);
57130f5afc8SStephan Aßmus		}
57230f5afc8SStephan Aßmus	}
57330f5afc8SStephan Aßmus
57430f5afc8SStephan Aßmus	// account for stricter interpretation of coordinates in AGG
57530f5afc8SStephan Aßmus	// the rectangle ranges from the top-left (.0, .0)
57630f5afc8SStephan Aßmus	// to the bottom-right (.9999, .9999) corner of pixels
57730f5afc8SStephan Aßmus	b.x += 1.0;
57830f5afc8SStephan Aßmus	b.y += 1.0;
57930f5afc8SStephan Aßmus
58030f5afc8SStephan Aßmus	agg::path_storage path;
58130f5afc8SStephan Aßmus	path.move_to(a.x, a.y);
58230f5afc8SStephan Aßmus	path.line_to(b.x, a.y);
58330f5afc8SStephan Aßmus	path.line_to(b.x, b.y);
58430f5afc8SStephan Aßmus	path.line_to(a.x, b.y);
58530f5afc8SStephan Aßmus	path.close_polygon();
58630f5afc8SStephan Aßmus
58730f5afc8SStephan Aßmus	return _FillPath(path, p);
58830f5afc8SStephan Aßmus}
58930f5afc8SStephan Aßmus
59030f5afc8SStephan Aßmus// FillRect
59130f5afc8SStephan Aßmusvoid
59230f5afc8SStephan AßmusPainter::FillRect(const BRect& r, const rgb_color& c) const
59330f5afc8SStephan Aßmus{
59430f5afc8SStephan Aßmus	if (fBuffer) {
59530f5afc8SStephan Aßmus		uint8* dst = fBuffer->row(0);
59630f5afc8SStephan Aßmus		uint32 bpr = fBuffer->stride();
59730f5afc8SStephan Aßmus		int32 left = (int32)r.left;
59830f5afc8SStephan Aßmus		int32 top = (int32)r.top;
59930f5afc8SStephan Aßmus		int32 right = (int32)r.right;
60030f5afc8SStephan Aßmus		int32 bottom = (int32)r.bottom;
60130f5afc8SStephan Aßmus		// fill rects, iterate over clipping boxes
60230f5afc8SStephan Aßmus		fBaseRenderer->first_clip_box();
60330f5afc8SStephan Aßmus		do {
60430f5afc8SStephan Aßmus			int32 x1 = max_c(fBaseRenderer->xmin(), left);
60530f5afc8SStephan Aßmus			int32 x2 = min_c(fBaseRenderer->xmax(), right);
60630f5afc8SStephan Aßmus			if (x1 <= x2) {
60730f5afc8SStephan Aßmus				int32 y1 = max_c(fBaseRenderer->ymin(), top);
60830f5afc8SStephan Aßmus				int32 y2 = min_c(fBaseRenderer->ymax(), bottom);
60930f5afc8SStephan Aßmus				uint8* offset = dst + x1 * 4;
61030f5afc8SStephan Aßmus				for (; y1 <= y2; y1++) {
61130f5afc8SStephan Aßmus					uint8* handle = offset + y1 * bpr;
61230f5afc8SStephan Aßmus					for (int32 x = x1; x <= x2; x++) {
61330f5afc8SStephan Aßmus						handle[0] = c.blue;
61430f5afc8SStephan Aßmus						handle[1] = c.green;
61530f5afc8SStephan Aßmus						handle[2] = c.red;
61630f5afc8SStephan Aßmus						handle += 4;
61730f5afc8SStephan Aßmus					}
61830f5afc8SStephan Aßmus				}
61930f5afc8SStephan Aßmus			}
62030f5afc8SStephan Aßmus		} while (fBaseRenderer->next_clip_box());
62130f5afc8SStephan Aßmus	}
62230f5afc8SStephan Aßmus}
62330f5afc8SStephan Aßmus
62430f5afc8SStephan Aßmus// StrokeRoundRect
62530f5afc8SStephan Aßmusvoid
62630f5afc8SStephan AßmusPainter::StrokeRoundRect(const BRect& r, float xRadius, float yRadius,
62730f5afc8SStephan Aßmus						 const pattern& p) const
62830f5afc8SStephan Aßmus{
62930f5afc8SStephan Aßmus	BPoint lt(r.left, r.top);
63030f5afc8SStephan Aßmus	BPoint rb(r.right, r.bottom);
63130f5afc8SStephan Aßmus	_Transform(&lt);
63230f5afc8SStephan Aßmus	_Transform(&rb);
63330f5afc8SStephan Aßmus
63430f5afc8SStephan Aßmus	_Transform(&xRadius);
63530f5afc8SStephan Aßmus	_Transform(&yRadius);
63630f5afc8SStephan Aßmus
63730f5afc8SStephan Aßmus	agg::rounded_rect rect;
63830f5afc8SStephan Aßmus	rect.rect(lt.x, lt.y, rb.x, rb.y);
63930f5afc8SStephan Aßmus	rect.radius(xRadius, yRadius);
64030f5afc8SStephan Aßmus
64130f5afc8SStephan Aßmus	_StrokePath(rect, p);
64230f5afc8SStephan Aßmus}
64330f5afc8SStephan Aßmus
64430f5afc8SStephan Aßmus// FillRoundRect
64530f5afc8SStephan Aßmusvoid
64630f5afc8SStephan AßmusPainter::FillRoundRect(const BRect& r, float xRadius, float yRadius,
64730f5afc8SStephan Aßmus					   const pattern& p) const
64830f5afc8SStephan Aßmus{
64930f5afc8SStephan Aßmus	BPoint lt(r.left, r.top);
65030f5afc8SStephan Aßmus	BPoint rb(r.right, r.bottom);
65130f5afc8SStephan Aßmus	_Transform(&lt, false);
65230f5afc8SStephan Aßmus	_Transform(&rb, false);
65330f5afc8SStephan Aßmus
65430f5afc8SStephan Aßmus	// account for stricter interpretation of coordinates in AGG
65530f5afc8SStephan Aßmus	// the rectangle ranges from the top-left (.0, .0)
65630f5afc8SStephan Aßmus	// to the bottom-right (.9999, .9999) corner of pixels
65730f5afc8SStephan Aßmus	rb.x += 1.0;
65830f5afc8SStephan Aßmus	rb.y += 1.0;
65930f5afc8SStephan Aßmus
66030f5afc8SStephan Aßmus	_Transform(&xRadius);
66130f5afc8SStephan Aßmus	_Transform(&yRadius);
66230f5afc8SStephan Aßmus
66330f5afc8SStephan Aßmus	agg::rounded_rect rect;
66430f5afc8SStephan Aßmus	rect.rect(lt.x, lt.y, rb.x, rb.y);
66530f5afc8SStephan Aßmus	rect.radius(xRadius, yRadius);
66630f5afc8SStephan Aßmus
66730f5afc8SStephan Aßmus	_FillPath(rect, p);
66830f5afc8SStephan Aßmus}
66930f5afc8SStephan Aßmus
67030f5afc8SStephan Aßmus// StrokeEllipse
67130f5afc8SStephan Aßmusvoid
67230f5afc8SStephan AßmusPainter::StrokeEllipse(BPoint center, float xRadius, float yRadius,
67330f5afc8SStephan Aßmus					   const pattern& p) const
67430f5afc8SStephan Aßmus{
67530f5afc8SStephan Aßmus	_DrawEllipse(center, xRadius, yRadius, p, false);
67630f5afc8SStephan Aßmus}
67730f5afc8SStephan Aßmus
67830f5afc8SStephan Aßmus// FillEllipse
67930f5afc8SStephan Aßmusvoid
68030f5afc8SStephan AßmusPainter::FillEllipse(BPoint center, float xRadius, float yRadius,
68130f5afc8SStephan Aßmus					 const pattern& p) const
68230f5afc8SStephan Aßmus{
68330f5afc8SStephan Aßmus	_DrawEllipse(center, xRadius, yRadius, p, true);
68430f5afc8SStephan Aßmus}
68530f5afc8SStephan Aßmus
68630f5afc8SStephan Aßmus// StrokeArc
68730f5afc8SStephan Aßmusvoid
68830f5afc8SStephan AßmusPainter::StrokeArc(BPoint center, float xRadius, float yRadius,
68930f5afc8SStephan Aßmus				   float angle, float span, const pattern& p) const
69030f5afc8SStephan Aßmus{
69130f5afc8SStephan Aßmus	_Transform(&center);
69230f5afc8SStephan Aßmus	_Transform(&xRadius);
69330f5afc8SStephan Aßmus	_Transform(&yRadius);
69430f5afc8SStephan Aßmus
69530f5afc8SStephan Aßmus	double angleRad = (angle * PI) / 180.0;
69630f5afc8SStephan Aßmus	double spanRad = (span * PI) / 180.0;
69730f5afc8SStephan Aßmus	agg::bezier_arc arc(center.x, center.y, xRadius, yRadius,
69830f5afc8SStephan Aßmus						-angleRad, -spanRad);
69930f5afc8SStephan Aßmus
70030f5afc8SStephan Aßmus	agg::conv_curve<agg::bezier_arc> path(arc);
70130f5afc8SStephan Aßmus
70230f5afc8SStephan Aßmus	_StrokePath(path, p);
70330f5afc8SStephan Aßmus}
70430f5afc8SStephan Aßmus
70530f5afc8SStephan Aßmus// FillArc
70630f5afc8SStephan Aßmusvoid
70730f5afc8SStephan AßmusPainter::FillArc(BPoint center, float xRadius, float yRadius,
70830f5afc8SStephan Aßmus				 float angle, float span, const pattern& p) const
70930f5afc8SStephan Aßmus{
71030f5afc8SStephan Aßmus	_Transform(&center);
71130f5afc8SStephan Aßmus	_Transform(&xRadius);
71230f5afc8SStephan Aßmus	_Transform(&yRadius);
71330f5afc8SStephan Aßmus
71430f5afc8SStephan Aßmus	double angleRad = (angle * PI) / 180.0;
71530f5afc8SStephan Aßmus	double spanRad = (span * PI) / 180.0;
71630f5afc8SStephan Aßmus	agg::bezier_arc arc(center.x, center.y, xRadius, yRadius,
71730f5afc8SStephan Aßmus						-angleRad, -spanRad);
71830f5afc8SStephan Aßmus
71930f5afc8SStephan Aßmus	agg::conv_curve<agg::bezier_arc> segmentedArc(arc);
72030f5afc8SStephan Aßmus
72130f5afc8SStephan Aßmus	agg::path_storage path;
72230f5afc8SStephan Aßmus
72330f5afc8SStephan Aßmus	// build a new path by starting at the center point,
72430f5afc8SStephan Aßmus	// then traversing the arc, then going back to the center
72530f5afc8SStephan Aßmus	path.move_to(center.x, center.y);
72630f5afc8SStephan Aßmus
72730f5afc8SStephan Aßmus	segmentedArc.rewind(0);
72830f5afc8SStephan Aßmus	double x;
72930f5afc8SStephan Aßmus	double y;
73030f5afc8SStephan Aßmus	unsigned cmd = segmentedArc.vertex(&x, &y);
73130f5afc8SStephan Aßmus	while (!agg::is_stop(cmd)) {
73230f5afc8SStephan Aßmus		path.line_to(x, y);
73330f5afc8SStephan Aßmus		cmd = segmentedArc.vertex(&x, &y);
73430f5afc8SStephan Aßmus	}
73530f5afc8SStephan Aßmus
73630f5afc8SStephan Aßmus	path.close_polygon();
73730f5afc8SStephan Aßmus
73830f5afc8SStephan Aßmus	_FillPath(path, p);
73930f5afc8SStephan Aßmus}
74030f5afc8SStephan Aßmus
74130f5afc8SStephan Aßmus// #pragma mark -
74230f5afc8SStephan Aßmus
74330f5afc8SStephan Aßmus// DrawChar
74430f5afc8SStephan AßmusBRect
74530f5afc8SStephan AßmusPainter::DrawChar(char aChar)
74630f5afc8SStephan Aßmus{
74730f5afc8SStephan Aßmus	// TODO: to be moved elsewhere
74830f5afc8SStephan Aßmus	return DrawChar(aChar, fPenLocation);
74930f5afc8SStephan Aßmus}
75030f5afc8SStephan Aßmus
75130f5afc8SStephan Aßmus// DrawChar
75230f5afc8SStephan AßmusBRect
75330f5afc8SStephan AßmusPainter::DrawChar(char aChar, BPoint baseLine)
75430f5afc8SStephan Aßmus{
75530f5afc8SStephan Aßmus	// TODO: to be moved elsewhere
75630f5afc8SStephan Aßmus	char wrapper[2];
75730f5afc8SStephan Aßmus	wrapper[0] = aChar;
75830f5afc8SStephan Aßmus	wrapper[1] = 0;
75930f5afc8SStephan Aßmus	return DrawString(wrapper, 1, baseLine);
76030f5afc8SStephan Aßmus}
76130f5afc8SStephan Aßmus
76230f5afc8SStephan Aßmus// DrawString
76330f5afc8SStephan AßmusBRect
76430f5afc8SStephan AßmusPainter::DrawString(const char* utf8String, uint32 length,
76530f5afc8SStephan Aßmus					const escapement_delta* delta)
76630f5afc8SStephan Aßmus{
76730f5afc8SStephan Aßmus	// TODO: to be moved elsewhere
76830f5afc8SStephan Aßmus	return DrawString(utf8String, length, fPenLocation, delta);
76930f5afc8SStephan Aßmus}
77030f5afc8SStephan Aßmus
77130f5afc8SStephan Aßmus// DrawString
77230f5afc8SStephan AßmusBRect
77330f5afc8SStephan AßmusPainter::DrawString(const char* utf8String, uint32 length,
77430f5afc8SStephan Aßmus					BPoint baseLine, const escapement_delta* delta)
77530f5afc8SStephan Aßmus{
77630f5afc8SStephan Aßmus	BRect bounds(0.0, 0.0, -1.0, -1.0);
77730f5afc8SStephan Aßmus	fPatternHandler->SetPattern(B_SOLID_HIGH);
77830f5afc8SStephan Aßmus
77930f5afc8SStephan Aßmus	if (fBuffer) {
78030f5afc8SStephan Aßmus
78130f5afc8SStephan Aßmus		Transformable transform;
78294c484bbSJérôme Duval		transform.ShearBy(B_ORIGIN, (90.0 - fFont.Shear()) * PI / 180.0, 0.0);
78394c484bbSJérôme Duval		transform.RotateBy(B_ORIGIN, -fFont.Rotation() * PI / 180.0);
78430f5afc8SStephan Aßmus		transform.TranslateBy(baseLine);
78530f5afc8SStephan Aßmus		transform.ScaleBy(B_ORIGIN, fScale, fScale);
78630f5afc8SStephan Aßmus		transform.TranslateBy(fOrigin);
78730f5afc8SStephan Aßmus
78830f5afc8SStephan Aßmus		BRect clippingFrame;
78930f5afc8SStephan Aßmus		if (fClippingRegion)
79030f5afc8SStephan Aßmus			clippingFrame = _Transform(fClippingRegion->Frame());
79130f5afc8SStephan Aßmus
79230f5afc8SStephan Aßmus		bounds = fTextRenderer->RenderString(utf8String,
79330f5afc8SStephan Aßmus											 length,
79430f5afc8SStephan Aßmus											 fFontRendererSolid,
79530f5afc8SStephan Aßmus											 fFontRendererBin,
79630f5afc8SStephan Aßmus											 transform,
79730f5afc8SStephan Aßmus											 clippingFrame,
79830f5afc8SStephan Aßmus											 false,
79930f5afc8SStephan Aßmus											 &fPenLocation);
80030f5afc8SStephan Aßmus		// pen location is not transformed in quite the same way,
80130f5afc8SStephan Aßmus		// or transformations would add up
80230f5afc8SStephan Aßmus		transform.Reset();
80330f5afc8SStephan Aßmus		transform.RotateBy(B_ORIGIN, -fFont.Rotation());
80430f5afc8SStephan Aßmus		transform.TranslateBy(baseLine);
80530f5afc8SStephan Aßmus		transform.Transform(&fPenLocation);
80630f5afc8SStephan Aßmus	}
80730f5afc8SStephan Aßmus	return _Clipped(bounds);
80830f5afc8SStephan Aßmus}
80930f5afc8SStephan Aßmus
81030f5afc8SStephan Aßmus// DrawString
81130f5afc8SStephan AßmusBRect
81230f5afc8SStephan AßmusPainter::DrawString(const char* utf8String, const escapement_delta* delta)
81330f5afc8SStephan Aßmus{
81430f5afc8SStephan Aßmus	// TODO: to be moved elsewhere
81530f5afc8SStephan Aßmus	return DrawString(utf8String, strlen(utf8String), fPenLocation, delta);
81630f5afc8SStephan Aßmus}
81730f5afc8SStephan Aßmus
81830f5afc8SStephan Aßmus// DrawString
81930f5afc8SStephan AßmusBRect
82030f5afc8SStephan AßmusPainter::DrawString(const char* utf8String, BPoint baseLine,
82130f5afc8SStephan Aßmus					const escapement_delta* delta)
82230f5afc8SStephan Aßmus{
82330f5afc8SStephan Aßmus	// TODO: to be moved elsewhere
82430f5afc8SStephan Aßmus	return DrawString(utf8String, strlen(utf8String), baseLine, delta);
82530f5afc8SStephan Aßmus}
82630f5afc8SStephan Aßmus
82730f5afc8SStephan Aßmus// #pragma mark -
82830f5afc8SStephan Aßmus
82930f5afc8SStephan Aßmus// DrawBitmap
83030f5afc8SStephan Aßmusvoid
83130f5afc8SStephan AßmusPainter::DrawBitmap(const BBitmap* bitmap,
83230f5afc8SStephan Aßmus					BRect bitmapRect, BRect viewRect) const
83330f5afc8SStephan Aßmus{
83430f5afc8SStephan Aßmus	if (bitmap && bitmap->IsValid()) {
83530f5afc8SStephan Aßmus		// the native bitmap coordinate system
83630f5afc8SStephan Aßmus		// (can have left top corner offset)
83730f5afc8SStephan Aßmus		BRect actualBitmapRect(bitmap->Bounds());
83830f5afc8SStephan Aßmus
83930f5afc8SStephan Aßmus		agg::rendering_buffer srcBuffer;
84030f5afc8SStephan Aßmus		srcBuffer.attach((uint8*)bitmap->Bits(),
84130f5afc8SStephan Aßmus						 (uint32)actualBitmapRect.IntegerWidth() + 1,
84230f5afc8SStephan Aßmus						 (uint32)actualBitmapRect.IntegerHeight() + 1,
84330f5afc8SStephan Aßmus						 bitmap->BytesPerRow());
84430f5afc8SStephan Aßmus
84530f5afc8SStephan Aßmus		_DrawBitmap(srcBuffer, bitmap->ColorSpace(), actualBitmapRect, bitmapRect, viewRect);
84630f5afc8SStephan Aßmus	}
84730f5afc8SStephan Aßmus}
84830f5afc8SStephan Aßmus
84930f5afc8SStephan Aßmus// DrawBitmap
85030f5afc8SStephan Aßmusvoid
85130f5afc8SStephan AßmusPainter::DrawBitmap(const ServerBitmap* bitmap,
85230f5afc8SStephan Aßmus					BRect bitmapRect, BRect viewRect) const
85330f5afc8SStephan Aßmus{
85430f5afc8SStephan Aßmus	if (bitmap && bitmap->InitCheck()) {
85530f5afc8SStephan Aßmus		// the native bitmap coordinate system
85630f5afc8SStephan Aßmus		BRect actualBitmapRect(bitmap->Bounds());
85730f5afc8SStephan Aßmus
85830f5afc8SStephan Aßmus		agg::rendering_buffer srcBuffer;
85930f5afc8SStephan Aßmus		srcBuffer.attach(bitmap->Bits(),
86030f5afc8SStephan Aßmus						 bitmap->Width(),
86130f5afc8SStephan Aßmus						 bitmap->Height(),
86230f5afc8SStephan Aßmus						 bitmap->BytesPerRow());
86330f5afc8SStephan Aßmus
86430f5afc8SStephan Aßmus		_DrawBitmap(srcBuffer, bitmap->ColorSpace(), actualBitmapRect, bitmapRect, viewRect);
86530f5afc8SStephan Aßmus	}
86630f5afc8SStephan Aßmus}
86730f5afc8SStephan Aßmus
86830f5afc8SStephan Aßmus// #pragma mark -
86930f5afc8SStephan Aßmus
87030f5afc8SStephan Aßmus// FillRegion
87130f5afc8SStephan Aßmusvoid
87230f5afc8SStephan AßmusPainter::FillRegion(const BRegion* region, const pattern& p = B_SOLID_HIGH) const
87330f5afc8SStephan Aßmus{
87430f5afc8SStephan Aßmus	BRegion copy(*region);
87530f5afc8SStephan Aßmus	int32 count = copy.CountRects();
87630f5afc8SStephan Aßmus	for (int32 i = 0; i < count; i++) {
87730f5afc8SStephan Aßmus		FillRect(copy.RectAt(i), p);
87830f5afc8SStephan Aßmus	}
87930f5afc8SStephan Aßmus}
88030f5afc8SStephan Aßmus
88130f5afc8SStephan Aßmus// InvertRect
88230f5afc8SStephan Aßmusvoid
88330f5afc8SStephan AßmusPainter::InvertRect(const BRect& r) const
88430f5afc8SStephan Aßmus{
88530f5afc8SStephan Aßmus	BRegion region(r);
88630f5afc8SStephan Aßmus	if (fClippingRegion) {
88730f5afc8SStephan Aßmus		region.IntersectWith(fClippingRegion);
88830f5afc8SStephan Aßmus	}
88930f5afc8SStephan Aßmus	// implementation only for B_RGB32 at the m