1/*
2 * Copyright 2009, Christian Packmann.
3 * Copyright 2008, Andrej Spielmann <andrej.spielmann@seh.ox.ac.uk>.
4 * Copyright 2005-2014, Stephan A��mus <superstippi@gmx.de>.
5 * Copyright 2015, Julian Harnath <julian.harnath@rwth-aachen.de>
6 * All rights reserved. Distributed under the terms of the MIT License.
7 */
8
9
10/*!	API to the Anti-Grain Geometry based "Painter" drawing backend. Manages
11	rendering pipe-lines for stroke, fills, bitmap and text rendering.
12*/
13
14
15#include "Painter.h"
16
17#include <new>
18
19#include <stdio.h>
20#include <string.h>
21#include <syslog.h>
22
23#include <Bitmap.h>
24#include <GraphicsDefs.h>
25#include <Region.h>
26#include <String.h>
27#include <GradientLinear.h>
28#include <GradientRadial.h>
29#include <GradientRadialFocus.h>
30#include <GradientDiamond.h>
31#include <GradientConic.h>
32
33#include <ShapePrivate.h>
34
35#include <agg_bezier_arc.h>
36#include <agg_bounding_rect.h>
37#include <agg_conv_clip_polygon.h>
38#include <agg_conv_curve.h>
39#include <agg_conv_stroke.h>
40#include <agg_ellipse.h>
41#include <agg_image_accessors.h>
42#include <agg_path_storage.h>
43#include <agg_pixfmt_rgba.h>
44#include <agg_rounded_rect.h>
45#include <agg_span_allocator.h>
46#include <agg_span_image_filter_rgba.h>
47#include <agg_span_interpolator_linear.h>
48
49#include "drawing_support.h"
50
51#include "DrawState.h"
52
53#include <AutoDeleter.h>
54#include <View.h>
55
56#include "AlphaMask.h"
57#include "BitmapPainter.h"
58#include "DrawingMode.h"
59#include "GlobalSubpixelSettings.h"
60#include "PatternHandler.h"
61#include "RenderingBuffer.h"
62#include "ServerBitmap.h"
63#include "ServerFont.h"
64#include "SystemPalette.h"
65
66#include "AppServer.h"
67
68using std::nothrow;
69
70#undef TRACE
71// #define TRACE_PAINTER
72#ifdef TRACE_PAINTER
73#	define TRACE(x...)		printf(x)
74#else
75#	define TRACE(x...)
76#endif
77
78//#define TRACE_GRADIENTS
79#ifdef TRACE_GRADIENTS
80#	include <OS.h>
81#	define GTRACE(x...)		debug_printf(x)
82#else
83#	define GTRACE(x...)
84#endif
85
86
87#define CHECK_CLIPPING	if (!fValidClipping) return BRect(0, 0, -1, -1);
88#define CHECK_CLIPPING_NO_RETURN	if (!fValidClipping) return;
89
90
91// Shortcuts for accessing internal data
92#define fBuffer					fInternal.fBuffer
93#define fPixelFormat			fInternal.fPixelFormat
94#define fBaseRenderer			fInternal.fBaseRenderer
95#define fUnpackedScanline		fInternal.fUnpackedScanline
96#define fPackedScanline			fInternal.fPackedScanline
97#define fRasterizer				fInternal.fRasterizer
98#define fRenderer				fInternal.fRenderer
99#define fRendererBin			fInternal.fRendererBin
100#define fSubpixPackedScanline	fInternal.fSubpixPackedScanline
101#define fSubpixUnpackedScanline	fInternal.fSubpixUnpackedScanline
102#define fSubpixRasterizer		fInternal.fSubpixRasterizer
103#define fSubpixRenderer			fInternal.fSubpixRenderer
104#define fMaskedUnpackedScanline	fInternal.fMaskedUnpackedScanline
105#define fClippedAlphaMask		fInternal.fClippedAlphaMask
106#define fPath					fInternal.fPath
107#define fCurve					fInternal.fCurve
108
109
110static uint32 detect_simd();
111
112uint32 gSIMDFlags = detect_simd();
113
114
115/*!	Detect SIMD flags for use in AppServer. Checks all CPUs in the system
116	and chooses the minimum supported set of instructions.
117*/
118static uint32
119detect_simd()
120{
121#if __i386__
122	// Only scan CPUs for which we are certain the SIMD flags are properly
123	// defined.
124	const char* vendorNames[] = {
125		"GenuineIntel",
126		"AuthenticAMD",
127		"CentaurHauls", // Via CPUs, MMX and SSE support
128		"RiseRiseRise", // should be MMX-only
129		"CyrixInstead", // MMX-only, but custom MMX extensions
130		"GenuineTMx86", // MMX and SSE
131		0
132	};
133
134	system_info systemInfo;
135	if (get_system_info(&systemInfo) != B_OK)
136		return 0;
137
138	// We start out with all flags set and end up with only those flags
139	// supported across all CPUs found.
140	uint32 systemSIMD = 0xffffffff;
141
142	for (uint32 cpu = 0; cpu < systemInfo.cpu_count; cpu++) {
143		cpuid_info cpuInfo;
144		get_cpuid(&cpuInfo, 0, cpu);
145
146		// Get the vendor string and terminate it manually
147		char vendor[13];
148		memcpy(vendor, cpuInfo.eax_0.vendor_id, 12);
149		vendor[12] = 0;
150
151		bool vendorFound = false;
152		for (uint32 i = 0; vendorNames[i] != 0; i++) {
153			if (strcmp(vendor, vendorNames[i]) == 0)
154				vendorFound = true;
155		}
156
157		uint32 cpuSIMD = 0;
158		uint32 maxStdFunc = cpuInfo.regs.eax;
159		if (vendorFound && maxStdFunc >= 1) {
160			get_cpuid(&cpuInfo, 1, 0);
161			uint32 edx = cpuInfo.regs.edx;
162			if (edx & (1 << 23))
163				cpuSIMD |= APPSERVER_SIMD_MMX;
164			if (edx & (1 << 25))
165				cpuSIMD |= APPSERVER_SIMD_SSE;
166		} else {
167			// no flags can be identified
168			cpuSIMD = 0;
169		}
170		systemSIMD &= cpuSIMD;
171	}
172	return systemSIMD;
173#else	// !__i386__
174	return 0;
175#endif
176}
177
178
179// #pragma mark -
180
181
182Painter::Painter()
183	:
184	fInternal(fPatternHandler),
185	fSubpixelPrecise(false),
186	fValidClipping(false),
187	fDrawingText(false),
188	fAttached(false),
189
190	fPenSize(1.0),
191	fClippingRegion(NULL),
192	fDrawingMode(B_OP_COPY),
193	fAlphaSrcMode(B_PIXEL_ALPHA),
194	fAlphaFncMode(B_ALPHA_OVERLAY),
195	fLineCapMode(B_BUTT_CAP),
196	fLineJoinMode(B_MITER_JOIN),
197	fMiterLimit(B_DEFAULT_MITER_LIMIT),
198
199	fPatternHandler(),
200	fTextRenderer(fSubpixRenderer, fRenderer, fRendererBin, fUnpackedScanline,
201		fSubpixUnpackedScanline, fSubpixRasterizer, fMaskedUnpackedScanline,
202		fTransform)
203{
204	fPixelFormat.SetDrawingMode(fDrawingMode, fAlphaSrcMode, fAlphaFncMode,
205		false);
206
207#if ALIASED_DRAWING
208	fRasterizer.gamma(agg::gamma_threshold(0.5));
209	fSubpixRasterizer.gamma(agg:gamma_threshold(0.5));
210#endif
211}
212
213
214// destructor
215Painter::~Painter()
216{
217}
218
219
220// #pragma mark -
221
222
223// AttachToBuffer
224void
225Painter::AttachToBuffer(RenderingBuffer* buffer)
226{
227	if (buffer && buffer->InitCheck() >= B_OK
228		&& (buffer->ColorSpace() == B_RGBA32
229			|| buffer->ColorSpace() == B_RGB32)) {
230		// TODO: implement drawing on B_RGB24, B_RGB15, B_RGB16,
231		// B_CMAP8 and B_GRAY8 :-[
232		// (if ever we want to support some devices where this gives
233		// a great speed up, right now it seems fine, even in emulation)
234
235		fBuffer.attach((uint8*)buffer->Bits(),
236			buffer->Width(), buffer->Height(), buffer->BytesPerRow());
237
238		fAttached = true;
239		fValidClipping = fClippingRegion != NULL
240			&& fClippingRegion->Frame().IsValid();
241
242		// These are the AGG renderes and rasterizes which
243		// will be used for stroking paths
244
245		_SetRendererColor(fPatternHandler.HighColor());
246	}
247}
248
249
250// DetachFromBuffer
251void
252Painter::DetachFromBuffer()
253{
254	fBuffer.attach(NULL, 0, 0, 0);
255	fAttached = false;
256	fValidClipping = false;
257}
258
259
260// Bounds
261BRect
262Painter::Bounds() const
263{
264	return BRect(0, 0, fBuffer.width() - 1, fBuffer.height() - 1);
265}
266
267
268// #pragma mark -
269
270
271// SetDrawState
272void
273Painter::SetDrawState(const DrawState* state, int32 xOffset, int32 yOffset)
274{
275	// NOTE: The custom clipping in "state" is ignored, because it has already
276	// been taken into account elsewhere
277
278	// NOTE: Usually this function is only used when the "current view"
279	// is switched in the ServerWindow and after the decorator has drawn
280	// and messed up the state. For other graphics state changes, the
281	// Painter methods are used directly, so this function is much less
282	// speed critical than it used to be.
283
284	SetTransform(state->CombinedTransform(), xOffset, yOffset);
285
286	SetPenSize(state->PenSize());
287
288	SetFont(state);
289
290	fSubpixelPrecise = state->SubPixelPrecise();
291
292	if (state->GetAlphaMask() != NULL) {
293		fMaskedUnpackedScanline = state->GetAlphaMask()->Scanline();
294		fClippedAlphaMask = state->GetAlphaMask()->Mask();
295	} else {
296		fMaskedUnpackedScanline = NULL;
297		fClippedAlphaMask = NULL;
298	}
299
300	// any of these conditions means we need to use a different drawing
301	// mode instance
302	bool updateDrawingMode
303		= !(state->GetPattern() == fPatternHandler.GetPattern())
304			|| state->GetDrawingMode() != fDrawingMode
305			|| (state->GetDrawingMode() == B_OP_ALPHA
306				&& (state->AlphaSrcMode() != fAlphaSrcMode
307					|| state->AlphaFncMode() != fAlphaFncMode));
308
309	fDrawingMode = state->GetDrawingMode();
310	fAlphaSrcMode = state->AlphaSrcMode();
311	fAlphaFncMode = state->AlphaFncMode();
312	fPatternHandler.SetPattern(state->GetPattern());
313	fPatternHandler.SetOffsets(xOffset, yOffset);
314	fLineCapMode = state->LineCapMode();
315	fLineJoinMode = state->LineJoinMode();
316	fMiterLimit = state->MiterLimit();
317
318	SetFillRule(state->FillRule());
319
320	// adopt the color *after* the pattern is set
321	// to set the renderers to the correct color
322	SetHighColor(state->HighColor());
323	SetLowColor(state->LowColor());
324
325	if (updateDrawingMode)
326		_UpdateDrawingMode();
327}
328
329
330// #pragma mark - state
331
332
333// ConstrainClipping
334void
335Painter::ConstrainClipping(const BRegion* region)
336{
337	fClippingRegion = region;
338	fBaseRenderer.set_clipping_region(const_cast<BRegion*>(region));
339	fValidClipping = region->Frame().IsValid() && fAttached;
340
341	if (fValidClipping) {
342		clipping_rect cb = fClippingRegion->FrameInt();
343		fRasterizer.clip_box(cb.left, cb.top, cb.right + 1, cb.bottom + 1);
344		fSubpixRasterizer.clip_box(cb.left, cb.top, cb.right + 1, cb.bottom + 1);
345	}
346}
347
348
349void
350Painter::SetTransform(BAffineTransform transform, int32 xOffset, int32 yOffset)
351{
352	fIdentityTransform = transform.IsIdentity();
353	if (!fIdentityTransform) {
354		fTransform = agg::trans_affine_translation(-xOffset, -yOffset);
355		fTransform *= agg::trans_affine(transform.sx, transform.shy,
356			transform.shx, transform.sy, transform.tx, transform.ty);
357		fTransform *= agg::trans_affine_translation(xOffset, yOffset);
358	} else {
359		fTransform.reset();
360	}
361}
362
363
364// SetHighColor
365void
366Painter::SetHighColor(const rgb_color& color)
367{
368	if (fPatternHandler.HighColor() == color)
369		return;
370	fPatternHandler.SetHighColor(color);
371	if (*(fPatternHandler.GetR5Pattern()) == B_SOLID_HIGH)
372		_SetRendererColor(color);
373}
374
375
376// SetLowColor
377void
378Painter::SetLowColor(const rgb_color& color)
379{
380	fPatternHandler.SetLowColor(color);
381	if (*(fPatternHandler.GetR5Pattern()) == B_SOLID_LOW)
382		_SetRendererColor(color);
383}
384
385
386// SetDrawingMode
387void
388Painter::SetDrawingMode(drawing_mode mode)
389{
390	if (fDrawingMode != mode) {
391		fDrawingMode = mode;
392		_UpdateDrawingMode();
393	}
394}
395
396
397// SetBlendingMode
398void
399Painter::SetBlendingMode(source_alpha srcAlpha, alpha_function alphaFunc)
400{
401	if (fAlphaSrcMode != srcAlpha || fAlphaFncMode != alphaFunc) {
402		fAlphaSrcMode = srcAlpha;
403		fAlphaFncMode = alphaFunc;
404		if (fDrawingMode == B_OP_ALPHA)
405			_UpdateDrawingMode();
406	}
407}
408
409
410// SetPenSize
411void
412Painter::SetPenSize(float size)
413{
414	fPenSize = size;
415}
416
417
418// SetStrokeMode
419void
420Painter::SetStrokeMode(cap_mode lineCap, join_mode joinMode, float miterLimit)
421{
422	fLineCapMode = lineCap;
423	fLineJoinMode = joinMode;
424	fMiterLimit = miterLimit;
425}
426
427
428void
429Painter::SetFillRule(int32 fillRule)
430{
431	agg::filling_rule_e aggFillRule = fillRule == B_EVEN_ODD
432		? agg::fill_even_odd : agg::fill_non_zero;
433
434	fRasterizer.filling_rule(aggFillRule);
435	fSubpixRasterizer.filling_rule(aggFillRule);
436}
437
438
439// SetPattern
440void
441Painter::SetPattern(const pattern& p, bool drawingText)
442{
443	if (!(p == *fPatternHandler.GetR5Pattern()) || drawingText != fDrawingText) {
444		fPatternHandler.SetPattern(p);
445		fDrawingText = drawingText;
446		_UpdateDrawingMode(fDrawingText);
447
448		// update renderer color if necessary
449		if (fPatternHandler.IsSolidHigh()) {
450			// pattern was not solid high before
451			_SetRendererColor(fPatternHandler.HighColor());
452		} else if (fPatternHandler.IsSolidLow()) {
453			// pattern was not solid low before
454			_SetRendererColor(fPatternHandler.LowColor());
455		}
456	}
457}
458
459
460// SetFont
461void
462Painter::SetFont(const ServerFont& font)
463{
464	fTextRenderer.SetFont(font);
465	fTextRenderer.SetAntialiasing(!(font.Flags() & B_DISABLE_ANTIALIASING));
466}
467
468
469// SetFont
470void
471Painter::SetFont(const DrawState* state)
472{
473	fTextRenderer.SetFont(state->Font());
474	fTextRenderer.SetAntialiasing(!state->ForceFontAliasing()
475		&& (state->Font().Flags() & B_DISABLE_ANTIALIASING) == 0);
476}
477
478
479// #pragma mark - drawing
480
481
482// StrokeLine
483void
484Painter::StrokeLine(BPoint a, BPoint b)
485{
486	CHECK_CLIPPING_NO_RETURN
487
488	// "false" means not to do the pixel center offset,
489	// because it would mess up our optimized versions
490	_Align(&a, false);
491	_Align(&b, false);
492
493	// first, try an optimized version
494	if (fPenSize == 1.0 && fIdentityTransform
495		&& (fDrawingMode == B_OP_COPY || fDrawingMode == B_OP_OVER)
496		&& fMaskedUnpackedScanline == NULL) {
497		pattern pat = *fPatternHandler.GetR5Pattern();
498		if (pat == B_SOLID_HIGH
499			&& StraightLine(a, b, fPatternHandler.HighColor())) {
500			return;
501		} else if (pat == B_SOLID_LOW
502			&& StraightLine(a, b, fPatternHandler.LowColor())) {
503			return;
504		}
505	}
506
507	fPath.remove_all();
508
509	if (a == b) {
510		// special case dots
511		if (fPenSize == 1.0 && !fSubpixelPrecise && fIdentityTransform) {
512			if (fClippingRegion->Contains(a)) {
513				int dotX = (int)a.x;
514				int dotY = (int)a.y;
515				fBaseRenderer.translate_to_base_ren(dotX, dotY);
516				fPixelFormat.blend_pixel(dotX, dotY, fRenderer.color(),
517					255);
518			}
519		} else {
520			fPath.move_to(a.x, a.y);
521			fPath.line_to(a.x + 1, a.y);
522			fPath.line_to(a.x + 1, a.y + 1);
523			fPath.line_to(a.x, a.y + 1);
524
525			_FillPath(fPath);
526		}
527	} else {
528		// Do the pixel center offset here
529		if (!fSubpixelPrecise && fmodf(fPenSize, 2.0) != 0.0) {
530			_Align(&a, true);
531			_Align(&b, true);
532		}
533
534		fPath.move_to(a.x, a.y);
535		fPath.line_to(b.x, b.y);
536
537		if (!fSubpixelPrecise && fPenSize == 1.0f) {
538			// Tweak ends to "include" the pixel at the index,
539			// we need to do this in order to produce results like R5,
540			// where coordinates were inclusive
541			_StrokePath(fPath, B_SQUARE_CAP);
542		} else
543			_StrokePath(fPath);
544	}
545}
546
547
548// StraightLine
549bool
550Painter::StraightLine(BPoint a, BPoint b, const rgb_color& c) const
551{
552	if (!fValidClipping)
553		return false;
554
555	if (a.x == b.x) {
556		// vertical
557		uint8* dst = fBuffer.row_ptr(0);
558		uint32 bpr = fBuffer.stride();
559		int32 x = (int32)a.x;
560		dst += x * 4;
561		int32 y1 = (int32)min_c(a.y, b.y);
562		int32 y2 = (int32)max_c(a.y, b.y);
563		pixel32 color;
564		color.data8[0] = c.blue;
565		color.data8[1] = c.green;
566		color.data8[2] = c.red;
567		color.data8[3] = 255;
568		// draw a line, iterate over clipping boxes
569		fBaseRenderer.first_clip_box();
570		do {
571			if (fBaseRenderer.xmin() <= x &&
572				fBaseRenderer.xmax() >= x) {
573				int32 i = max_c(fBaseRenderer.ymin(), y1);
574				int32 end = min_c(fBaseRenderer.ymax(), y2);
575				uint8* handle = dst + i * bpr;
576				for (; i <= end; i++) {
577					*(uint32*)handle = color.data32;
578					handle += bpr;
579				}
580			}
581		} while (fBaseRenderer.next_clip_box());
582
583		return true;
584	}
585
586	if (a.y == b.y) {
587		// horizontal
588		int32 y = (int32)a.y;
589		if (y < 0 || y >= (int32)fBuffer.height())
590			return true;
591
592		uint8* dst = fBuffer.row_ptr(y);
593		int32 x1 = (int32)min_c(a.x, b.x);
594		int32 x2 = (int32)max_c(a.x, b.x);
595		pixel32 color;
596		color.data8[0] = c.blue;
597		color.data8[1] = c.green;
598		color.data8[2] = c.red;
599		color.data8[3] = 255;
600		// draw a line, iterate over clipping boxes
601		fBaseRenderer.first_clip_box();
602		do {
603			if (fBaseRenderer.ymin() <= y &&
604				fBaseRenderer.ymax() >= y) {
605				int32 i = max_c(fBaseRenderer.xmin(), x1);
606				int32 end = min_c(fBaseRenderer.xmax(), x2);
607				uint32* handle = (uint32*)(dst + i * 4);
608				for (; i <= end; i++) {
609					*handle++ = color.data32;
610				}
611			}
612		} while (fBaseRenderer.next_clip_box());
613
614		return true;
615	}
616	return false;
617}
618
619
620// #pragma mark -
621
622
623// StrokeTriangle
624BRect
625Painter::StrokeTriangle(BPoint pt1, BPoint pt2, BPoint pt3) const
626{
627	return _DrawTriangle(pt1, pt2, pt3, false);
628}
629
630
631// FillTriangle
632BRect
633Painter::FillTriangle(BPoint pt1, BPoint pt2, BPoint pt3) const
634{
635	return _DrawTriangle(pt1, pt2, pt3, true);
636}
637
638
639// FillTriangle
640BRect
641Painter::FillTriangle(BPoint pt1, BPoint pt2, BPoint pt3,
642	const BGradient& gradient) const
643{
644	CHECK_CLIPPING
645
646	_Align(&pt1);
647	_Align(&pt2);
648	_Align(&pt3);
649
650	fPath.remove_all();
651
652	fPath.move_to(pt1.x, pt1.y);
653	fPath.line_to(pt2.x, pt2.y);
654	fPath.line_to(pt3.x, pt3.y);
655
656	fPath.close_polygon();
657
658	return _FillPath(fPath, gradient);
659}
660
661
662// DrawPolygon
663BRect
664Painter::DrawPolygon(BPoint* p, int32 numPts, bool filled, bool closed) const
665{
666	CHECK_CLIPPING
667
668	if (numPts == 0)
669		return BRect(0.0, 0.0, -1.0, -1.0);
670
671	bool centerOffset = !filled && fIdentityTransform
672		&& fmodf(fPenSize, 2.0) != 0.0;
673
674	fPath.remove_all();
675
676	_Align(p, centerOffset);
677	fPath.move_to(p->x, p->y);
678
679	for (int32 i = 1; i < numPts; i++) {
680		p++;
681		_Align(p, centerOffset);
682		fPath.line_to(p->x, p->y);
683	}
684
685	if (closed)
686		fPath.close_polygon();
687
688	if (filled)
689		return _FillPath(fPath);
690
691	return _StrokePath(fPath);
692}
693
694
695// FillPolygon
696BRect
697Painter::FillPolygon(BPoint* p, int32 numPts, const BGradient& gradient,
698	bool closed) const
699{
700	CHECK_CLIPPING
701
702	if (numPts > 0) {
703		fPath.remove_all();
704
705		_Align(p);
706		fPath.move_to(p->x, p->y);
707
708		for (int32 i = 1; i < numPts; i++) {
709			p++;
710			_Align(p);
711			fPath.line_to(p->x, p->y);
712		}
713
714		if (closed)
715			fPath.close_polygon();
716
717		return _FillPath(fPath, gradient);
718	}
719	return BRect(0.0, 0.0, -1.0, -1.0);
720}
721
722
723// DrawBezier
724BRect
725Painter::DrawBezier(BPoint* p, bool filled) const
726{
727	CHECK_CLIPPING
728
729	fPath.remove_all();
730
731	_Align(&(p[0]));
732	_Align(&(p[1]));
733	_Align(&(p[2]));
734	_Align(&(p[3]));
735
736	fPath.move_to(p[0].x, p[0].y);
737	fPath.curve4(p[1].x, p[1].y, p[2].x, p[2].y, p[3].x, p[3].y);
738
739	if (filled) {
740		fPath.close_polygon();
741		return _FillPath(fCurve);
742	}
743
744	return _StrokePath(fCurve);
745}
746
747
748// FillBezier
749BRect
750Painter::FillBezier(BPoint* p, const BGradient& gradient) const
751{
752	CHECK_CLIPPING
753
754	fPath.remove_all();
755
756	_Align(&(p[0]));
757	_Align(&(p[1]));
758	_Align(&(p[2]));
759	_Align(&(p[3]));
760
761	fPath.move_to(p[0].x, p[0].y);
762	fPath.curve4(p[1].x, p[1].y, p[2].x, p[2].y, p[3].x, p[3].y);
763
764	fPath.close_polygon();
765	return _FillPath(fCurve, gradient);
766}
767
768
769// DrawShape
770BRect
771Painter::DrawShape(const int32& opCount, const uint32* opList,
772	const int32& ptCount, const BPoint* points, bool filled,
773	const BPoint& viewToScreenOffset, float viewScale) const
774{
775	CHECK_CLIPPING
776
777	_IterateShapeData(opCount, opList, ptCount, points, viewToScreenOffset,
778		viewScale);
779
780	if (filled)
781		return _FillPath(fCurve);
782
783	return _StrokePath(fCurve);
784}
785
786
787// FillShape
788BRect
789Painter::FillShape(const int32& opCount, const uint32* opList,
790	const int32& ptCount, const BPoint* points, const BGradient& gradient,
791	const BPoint& viewToScreenOffset, float viewScale) const
792{
793	CHECK_CLIPPING
794
795	_IterateShapeData(opCount, opList, ptCount, points, viewToScreenOffset,
796		viewScale);
797
798	return _FillPath(fCurve, gradient);
799}
800
801
802// StrokeRect
803BRect
804Painter::StrokeRect(const BRect& r) const
805{
806	CHECK_CLIPPING
807
808	BPoint a(r.left, r.top);
809	BPoint b(r.right, r.bottom);
810	_Align(&a, false);
811	_Align(&b, false);
812
813	// first, try an optimized version
814	if (fPenSize == 1.0 && fIdentityTransform
815			&& (fDrawingMode == B_OP_COPY || fDrawingMode == B_OP_OVER)
816			&& fMaskedUnpackedScanline == NULL) {
817		pattern p = *fPatternHandler.GetR5Pattern();
818		if (p == B_SOLID_HIGH) {
819			BRect rect(a, b);
820			StrokeRect(rect, fPatternHandler.HighColor());
821			return _Clipped(rect);
822		} else if (p == B_SOLID_LOW) {
823			BRect rect(a, b);
824			StrokeRect(rect, fPatternHandler.LowColor());
825			return _Clipped(rect);
826		}
827	}
828
829	if (fIdentityTransform && fmodf(fPenSize, 2.0) != 0.0) {
830		// shift coords to center of pixels
831		a.x += 0.5;
832		a.y += 0.5;
833		b.x += 0.5;
834		b.y += 0.5;
835	}
836
837	fPath.remove_all();
838	fPath.move_to(a.x, a.y);
839	if (a.x == b.x || a.y == b.y) {
840		// special case rects with one pixel height or width
841		fPath.line_to(b.x, b.y);
842	} else {
843		fPath.line_to(b.x, a.y);
844		fPath.line_to(b.x, b.y);
845		fPath.line_to(a.x, b.y);
846	}
847	fPath.close_polygon();
848
849	return _StrokePath(fPath);
850}
851
852
853// StrokeRect
854void
855Painter::StrokeRect(const BRect& r, const rgb_color& c) const
856{
857	StraightLine(BPoint(r.left, r.top), BPoint(r.right - 1, r.top), c);
858	StraightLine(BPoint(r.right, r.top), BPoint(r.right, r.bottom - 1), c);
859	StraightLine(BPoint(r.right, r.bottom), BPoint(r.left + 1, r.bottom), c);
860	StraightLine(BPoint(r.left, r.bottom), BPoint(r.left, r.top + 1), c);
861}
862
863
864// FillRect
865BRect
866Painter::FillRect(const BRect& r) const
867{
868	CHECK_CLIPPING
869
870	// support invalid rects
871	BPoint a(min_c(r.left, r.right), min_c(r.top, r.bottom));
872	BPoint b(max_c(r.left, r.right), max_c(r.top, r.bottom));
873	_Align(&a, true, false);
874	_Align(&b, true, false);
875
876	// first, try an optimized version
877	if ((fDrawingMode == B_OP_COPY || fDrawingMode == B_OP_OVER)
878		&& fMaskedUnpackedScanline == NULL && fIdentityTransform) {
879		pattern p = *fPatternHandler.GetR5Pattern();
880		if (p == B_SOLID_HIGH) {
881			BRect rect(a, b);
882			FillRect(rect, fPatternHandler.HighColor());
883			return _Clipped(rect);
884		} else if (p == B_SOLID_LOW) {
885			BRect rect(a, b);
886			FillRect(rect, fPatternHandler.LowColor());
887			return _Clipped(rect);
888		}
889	}
890	if (fDrawingMode == B_OP_ALPHA && fAlphaFncMode == B_ALPHA_OVERLAY
891		&& fMaskedUnpackedScanline == NULL && fIdentityTransform) {
892		pattern p = *fPatternHandler.GetR5Pattern();
893		if (p == B_SOLID_HIGH) {
894			BRect rect(a, b);
895			_BlendRect32(rect, fPatternHandler.HighColor());
896			return _Clipped(rect);
897		} else if (p == B_SOLID_LOW) {
898			rgb_color c = fPatternHandler.LowColor();
899			if (fAlphaSrcMode == B_CONSTANT_ALPHA)
900				c.alpha = fPatternHandler.HighColor().alpha;
901			BRect rect(a, b);
902			_BlendRect32(rect, c);
903			return _Clipped(rect);
904		}
905	}
906
907	// account for stricter interpretation of coordinates in AGG
908	// the rectangle ranges from the top-left (.0, .0)
909	// to the bottom-right (.9999, .9999) corner of pixels
910	b.x += 1.0;
911	b.y += 1.0;
912
913	fPath.remove_all();
914	fPath.move_to(a.x, a.y);
915	fPath.line_to(b.x, a.y);
916	fPath.line_to(b.x, b.y);
917	fPath.line_to(a.x, b.y);
918	fPath.close_polygon();
919
920	return _FillPath(fPath);
921}
922
923
924// FillRect
925BRect
926Painter::FillRect(const BRect& r, const BGradient& gradient) const
927{
928	CHECK_CLIPPING
929
930	// support invalid rects
931	BPoint a(min_c(r.left, r.right), min_c(r.top, r.bottom));
932	BPoint b(max_c(r.left, r.right), max_c(r.top, r.bottom));
933	_Align(&a, true, false);
934	_Align(&b, true, false);
935
936	// first, try an optimized version
937	if (gradient.GetType() == BGradient::TYPE_LINEAR
938		&& (fDrawingMode == B_OP_COPY || fDrawingMode == B_OP_OVER)
939		&& fMaskedUnpackedScanline == NULL && fIdentityTransform) {
940		const BGradientLinear* linearGradient
941			= dynamic_cast<const BGradientLinear*>(&gradient);
942		if (linearGradient->Start().x == linearGradient->End().x
943			// TODO: Remove this second check once the optimized method
944			// handled "upside down" gradients as well...
945			&& linearGradient->Start().y <= linearGradient->End().y) {
946			// a vertical gradient
947			BRect rect(a, b);
948			FillRectVerticalGradient(rect, *linearGradient);
949			return _Clipped(rect);
950		}
951	}
952
953	// account for stricter interpretation of coordinates in AGG
954	// the rectangle ranges from the top-left (.0, .0)
955	// to the bottom-right (.9999, .9999) corner of pixels
956	b.x += 1.0;
957	b.y += 1.0;
958
959	fPath.remove_all();
960	fPath.move_to(a.x, a.y);
961	fPath.line_to(b.x, a.y);
962	fPath.line_to(b.x, b.y);
963	fPath.line_to(a.x, b.y);
964	fPath.close_polygon();
965
966	return _FillPath(fPath, gradient);
967}
968
969
970// FillRect
971void
972Painter::FillRect(const BRect& r, const rgb_color& c) const
973{
974	if (!fValidClipping)
975		return;
976
977	uint8* dst = fBuffer.row_ptr(0);
978	uint32 bpr = fBuffer.stride();
979	int32 left = (int32)r.left;
980	int32 top = (int32)r.top;
981	int32 right = (int32)r.right;
982	int32 bottom = (int32)r.bottom;
983	// get a 32 bit pixel ready with the color
984	pixel32 color;
985	color.data8[0] = c.blue;
986	color.data8[1] = c.green;
987	color.data8[2] = c.red;
988	color.data8[3] = c.alpha;
989	// fill rects, iterate over clipping boxes
990	fBaseRenderer.first_clip_box();
991	do {
992		int32 x1 = max_c(fBaseRenderer.xmin(), left);
993		int32 x2 = min_c(fBaseRenderer.xmax(), right);
994		if (x1 <= x2) {
995			int32 y1 = max_c(fBaseRenderer.ymin(), top);
996			int32 y2 = min_c(fBaseRenderer.ymax(), bottom);
997			uint8* offset = dst + x1 * 4;
998			for (; y1 <= y2; y1++) {
999//					uint32* handle = (uint32*)(offset + y1 * bpr);
1000//					for (int32 x = x1; x <= x2; x++) {
1001//						*handle++ = color.data32;
1002//					}
1003				gfxset32(offset + y1 * bpr, color.data32, (x2 - x1 + 1) * 4);
1004			}
1005		}
1006	} while (fBaseRenderer.next_clip_box());
1007}
1008
1009
1010// FillRectVerticalGradient
1011void
1012Painter::FillRectVerticalGradient(BRect r,
1013	const BGradientLinear& gradient) const
1014{
1015	if (!fValidClipping)
1016		return;
1017
1018	// Make sure the color array is no larger than the screen height.
1019	r = r & fClippingRegion->Frame();
1020
1021	int32 gradientArraySize = r.IntegerHeight() + 1;
1022	uint32 gradientArray[gradientArraySize];
1023	int32 gradientTop = (int32)gradient.Start().y;
1024	int32 gradientBottom = (int32)gradient.End().y;
1025	int32 colorCount = gradientBottom - gradientTop + 1;
1026	if (colorCount < 0) {
1027		// Gradient is upside down. That's currently not supported by this
1028		// method.
1029		return;
1030	}
1031
1032	_MakeGradient(gradient, colorCount, gradientArray,
1033		gradientTop - (int32)r.top, gradientArraySize);
1034
1035	uint8* dst = fBuffer.row_ptr(0);
1036	uint32 bpr = fBuffer.stride();
1037	int32 left = (int32)r.left;
1038	int32 top = (int32)r.top;
1039	int32 right = (int32)r.right;
1040	int32 bottom = (int32)r.bottom;
1041	// fill rects, iterate over clipping boxes
1042	fBaseRenderer.first_clip_box();
1043	do {
1044		int32 x1 = max_c(fBaseRenderer.xmin(), left);
1045		int32 x2 = min_c(fBaseRenderer.xmax(), right);
1046		if (x1 <= x2) {
1047			int32 y1 = max_c(fBaseRenderer.ymin(), top);
1048			int32 y2 = min_c(fBaseRenderer.ymax(), bottom);
1049			uint8* offset = dst + x1 * 4;
1050			for (; y1 <= y2; y1++) {
1051//					uint32* handle = (uint32*)(offset + y1 * bpr);
1052//					for (int32 x = x1; x <= x2; x++) {
1053//						*handle++ = gradientArray[y1 - top];
1054//					}
1055				gfxset32(offset + y1 * bpr, gradientArray[y1 - top],
1056					(x2 - x1 + 1) * 4);
1057			}
1058		}
1059	} while (fBaseRenderer.next_clip_box());
1060}
1061
1062
1063// FillRectNoClipping
1064void
1065Painter::FillRectNoClipping(const clipping_rect& r, const rgb_color& c) const
1066{
1067	int32 y = (int32)r.top;
1068
1069	uint8* dst = fBuffer.row_ptr(y) + r.left * 4;
1070	uint32 bpr = fBuffer.stride();
1071	int32 bytes = (r.right - r.left + 1) * 4;
1072
1073	// get a 32 bit pixel ready with the color
1074	pixel32 color;
1075	color.data8[0] = c.blue;
1076	color.data8[1] = c.green;
1077	color.data8[2] = c.red;
1078	color.data8[3] = c.alpha;
1079
1080	for (; y <= r.bottom; y++) {
1081//			uint32* handle = (uint32*)dst;
1082//			for (int32 x = left; x <= right; x++) {
1083//				*handle++ = color.data32;
1084//			}
1085		gfxset32(dst, color.data32, bytes);
1086		dst += bpr;
1087	}
1088}
1089
1090
1091// StrokeRoundRect
1092BRect
1093Painter::StrokeRoundRect(const BRect& r, float xRadius, float yRadius) const
1094{
1095	CHECK_CLIPPING
1096
1097	BPoint lt(r.left, r.top);
1098	BPoint rb(r.right, r.bottom);
1099	bool centerOffset = fmodf(fPenSize, 2.0) != 0.0;
1100	_Align(&lt, centerOffset);
1101	_Align(&rb, centerOffset);
1102
1103	agg::rounded_rect rect;
1104	rect.rect(lt.x, lt.y, rb.x, rb.y);
1105	rect.radius(xRadius, yRadius);
1106
1107	return _StrokePath(rect);
1108}
1109
1110
1111// FillRoundRect
1112BRect
1113Painter::FillRoundRect(const BRect& r, float xRadius, float yRadius) const
1114{
1115	CHECK_CLIPPING
1116
1117	BPoint lt(r.left, r.top);
1118	BPoint rb(r.right, r.bottom);
1119	_Align(&lt, false);
1120	_Align(&rb, false);
1121
1122	// account for stricter interpretation of coordinates in AGG
1123	// the rectangle ranges from the top-left (.0, .0)
1124	// to the bottom-right (.9999, .9999) corner of pixels
1125	rb.x += 1.0;
1126	rb.y += 1.0;
1127
1128	agg::rounded_rect rect;
1129	rect.rect(lt.x, lt.y, rb.x, rb.y);
1130	rect.radius(xRadius, yRadius);
1131
1132	return _FillPath(rect);
1133}
1134
1135
1136// FillRoundRect
1137BRect
1138Painter::FillRoundRect(const BRect& r, float xRadius, float yRadius,
1139	const BGradient& gradient) const
1140{
1141	CHECK_CLIPPING
1142
1143	BPoint lt(r.left, r.top);
1144	BPoint rb(r.right, r.bottom);
1145	_Align(&lt, false);
1146	_Align(&rb, false);
1147
1148	// account for stricter interpretation of coordinates in AGG
1149	// the rectangle ranges from the top-left (.0, .0)
1150	// to the bottom-right (.9999, .9999) corner of pixels
1151	rb.x += 1.0;
1152	rb.y += 1.0;
1153
1154	agg::rounded_rect rect;
1155	rect.rect(lt.x, lt.y, rb.x, rb.y);
1156	rect.radius(xRadius, yRadius);
1157
1158	return _FillPath(rect, gradient);
1159}
1160
1161
1162// AlignEllipseRect
1163void
1164Painter::AlignEllipseRect(BRect* rect, bool filled) const
1165{
1166	if (!fSubpixelPrecise) {
1167		// align rect to pixels
1168		align_rect_to_pixels(rect);
1169		// account for "pixel index" versus "pixel area"
1170		rect->right++;
1171		rect->bottom++;
1172		if (!filled && fmodf(fPenSize, 2.0) != 0.0) {
1173			// align the stroke
1174			rect->InsetBy(0.5, 0.5);
1175		}
1176	}
1177}
1178
1179
1180// DrawEllipse
1181BRect
1182Painter::DrawEllipse(BRect r, bool fill) const
1183{
1184	CHECK_CLIPPING
1185
1186	AlignEllipseRect(&r, fill);
1187
1188	float xRadius = r.Width() / 2.0;
1189	float yRadius = r.Height() / 2.0;
1190	BPoint center(r.left + xRadius, r.top + yRadius);
1191
1192	int32 divisions = (int32)((xRadius + yRadius + 2 * fPenSize) * M_PI / 2);
1193	if (divisions < 12)
1194		divisions = 12;
1195	if (divisions > 4096)
1196		divisions = 4096;
1197
1198	agg::ellipse path(center.x, center.y, xRadius, yRadius, divisions);
1199
1200	if (fill)
1201		return _FillPath(path);
1202	else
1203		return _StrokePath(path);
1204}
1205
1206
1207// FillEllipse
1208BRect
1209Painter::FillEllipse(BRect r, const BGradient& gradient) const
1210{
1211	CHECK_CLIPPING
1212
1213	AlignEllipseRect(&r, true);
1214
1215	float xRadius = r.Width() / 2.0;
1216	float yRadius = r.Height() / 2.0;
1217	BPoint center(r.left + xRadius, r.top + yRadius);
1218
1219	int32 divisions = (int32)((xRadius + yRadius + 2 * fPenSize) * M_PI / 2);
1220	if (divisions < 12)
1221		divisions = 12;
1222	if (divisions > 4096)
1223		divisions = 4096;
1224
1225	agg::ellipse path(center.x, center.y, xRadius, yRadius, divisions);
1226
1227	return _FillPath(path, gradient);
1228}
1229
1230
1231// StrokeArc
1232BRect
1233Painter::StrokeArc(BPoint center, float xRadius, float yRadius, float angle,
1234	float span) const
1235{
1236	CHECK_CLIPPING
1237
1238	_Align(&center);
1239
1240	double angleRad = (angle * M_PI) / 180.0;
1241	double spanRad = (span * M_PI) / 180.0;
1242	agg::bezier_arc arc(center.x, center.y, xRadius, yRadius, -angleRad,
1243		-spanRad);
1244
1245	agg::conv_curve<agg::bezier_arc> path(arc);
1246	path.approximation_scale(2.0);
1247
1248	return _StrokePath(path);
1249}
1250
1251
1252// FillArc
1253BRect
1254Painter::FillArc(BPoint center, float xRadius, float yRadius, float angle,
1255	float span) const
1256{
1257	CHECK_CLIPPING
1258
1259	_Align(&center);
1260
1261	double angleRad = (angle * M_PI) / 180.0;
1262	double spanRad = (span * M_PI) / 180.0;
1263	agg::bezier_arc arc(center.x, center.y, xRadius, yRadius, -angleRad,
1264		-spanRad);
1265
1266	agg::conv_curve<agg::bezier_arc> segmentedArc(arc);
1267
1268	fPath.remove_all();
1269
1270	// build a new path by starting at the center point,
1271	// then traversing the arc, then going back to the center
1272	fPath.move_to(center.x, center.y);
1273
1274	segmentedArc.rewind(0);
1275	double x;
1276	double y;
1277	unsigned cmd = segmentedArc.vertex(&x, &y);
1278	while (!agg::is_stop(cmd)) {
1279		fPath.line_to(x, y);
1280		cmd = segmentedArc.vertex(&x, &y);
1281	}
1282
1283	fPath.close_polygon();
1284
1285	return _FillPath(fPath);
1286}
1287
1288
1289// FillArc
1290BRect
1291Painter::FillArc(BPoint center, float xRadius, float yRadius, float angle,
1292	float span, const BGradient& gradient) const
1293{
1294	CHECK_CLIPPING
1295
1296	_Align(&center);
1297
1298	double angleRad = (angle * M_PI) / 180.0;
1299	double spanRad = (span * M_PI) / 180.0;
1300	agg::bezier_arc arc(center.x, center.y, xRadius, yRadius, -angleRad,
1301		-spanRad);
1302
1303	agg::conv_curve<agg::bezier_arc> segmentedArc(arc);
1304
1305	fPath.remove_all();
1306
1307	// build a new path by starting at the center point,
1308	// then traversing the arc, then going back to the center
1309	fPath.move_to(center.x, center.y);
1310
1311	segmentedArc.rewind(0);
1312	double x;
1313	double y;
1314	unsigned cmd = segmentedArc.vertex(&x, &y);
1315	while (!agg::is_stop(cmd)) {
1316		fPath.line_to(x, y);
1317		cmd = segmentedArc.vertex(&x, &y);
1318	}
1319
1320	fPath.close_polygon();
1321
1322	return _FillPath(fPath, gradient);
1323}
1324
1325
1326// #pragma mark -
1327
1328
1329// DrawString
1330BRect
1331Painter::DrawString(const char* utf8String, uint32 length, BPoint baseLine,
1332	const escapement_delta* delta, FontCacheReference* cacheReference)
1333{
1334	CHECK_CLIPPING
1335
1336	if (!fSubpixelPrecise) {
1337		baseLine.x = roundf(baseLine.x);
1338		baseLine.y = roundf(baseLine.y);
1339	}
1340
1341	BRect bounds;
1342
1343	// text is not rendered with patterns, but we need to
1344	// make sure that the previous pattern is restored
1345	pattern oldPattern = *fPatternHandler.GetR5Pattern();
1346	SetPattern(B_SOLID_HIGH, true);
1347
1348	bounds = fTextRenderer.RenderString(utf8String, length,
1349		baseLine, fClippingRegion->Frame(), false, NULL, delta,
1350		cacheReference);
1351
1352	SetPattern(oldPattern);
1353
1354	return _Clipped(bounds);
1355}
1356
1357
1358// DrawString
1359BRect
1360Painter::DrawString(const char* utf8String, uint32 length,
1361	const BPoint* offsets, FontCacheReference* cacheReference)
1362{
1363	CHECK_CLIPPING
1364
1365	// TODO: Round offsets to device pixel grid if !fSubpixelPrecise?
1366
1367	BRect bounds;
1368
1369	// text is not rendered with patterns, but we need to
1370	// make sure that the previous pattern is restored
1371	pattern oldPattern = *fPatternHandler.GetR5Pattern();
1372	SetPattern(B_SOLID_HIGH, true);
1373
1374	bounds = fTextRenderer.RenderString(utf8String, length,
1375		offsets, fClippingRegion->Frame(), false, NULL,
1376		cacheReference);
1377
1378	SetPattern(oldPattern);
1379
1380	return _Clipped(bounds);
1381}
1382
1383
1384// BoundingBox
1385BRect
1386Painter::BoundingBox(const char* utf8String, uint32 length, BPoint baseLine,
1387	BPoint* penLocation, const escapement_delta* delta,
1388	FontCacheReference* cacheReference) const
1389{
1390	if (!fSubpixelPrecise) {
1391		baseLine.x = roundf(baseLine.x);
1392		baseLine.y = roundf(baseLine.y);
1393	}
1394
1395	static BRect dummy;
1396	return fTextRenderer.RenderString(utf8String, length,
1397		baseLine, dummy, true, penLocation, delta, cacheReference);
1398}
1399
1400
1401// BoundingBox
1402BRect
1403Painter::BoundingBox(const char* utf8String, uint32 length,
1404	const BPoint* offsets, BPoint* penLocation,
1405	FontCacheReference* cacheReference) const
1406{
1407	// TODO: Round offsets to device pixel grid if !fSubpixelPrecise?
1408
1409	static BRect dummy;
1410	return fTextRenderer.RenderString(utf8String, length,
1411		offsets, dummy, true, penLocation, cacheReference);
1412}
1413
1414
1415// StringWidth
1416float
1417Painter::StringWidth(const char* utf8String, uint32 length,
1418	const escapement_delta* delta)
1419{
1420	return Font().StringWidth(utf8String, length, delta);
1421}
1422
1423
1424// #pragma mark -
1425
1426
1427// DrawBitmap
1428BRect
1429Painter::DrawBitmap(const ServerBitmap* bitmap, BRect bitmapRect,
1430	BRect viewRect, uint32 options) const
1431{
1432	CHECK_CLIPPING
1433
1434	BRect touched = TransformAlignAndClipRect(viewRect);
1435
1436	if (touched.IsValid()) {
1437		BitmapPainter bitmapPainter(this, bitmap, options);
1438		bitmapPainter.Draw(bitmapRect, viewRect);
1439	}
1440
1441	return touched;
1442}
1443
1444
1445// #pragma mark -
1446
1447
1448// FillRegion
1449BRect
1450Painter::FillRegion(const BRegion* region) const
1451{
1452	CHECK_CLIPPING
1453
1454	BRegion copy(*region);
1455	int32 count = copy.CountRects();
1456	BRect touched = FillRect(copy.RectAt(0));
1457	for (int32 i = 1; i < count; i++) {
1458		touched = touched | FillRect(copy.RectAt(i));
1459	}
1460	return touched;
1461}
1462
1463
1464// FillRegion
1465BRect
1466Painter::FillRegion(const BRegion* region, const BGradient& gradient) const
1467{
1468	CHECK_CLIPPING
1469
1470	BRegion copy(*region);
1471	int32 count = copy.CountRects();
1472	BRect touched = FillRect(copy.RectAt(0), gradient);
1473	for (int32 i = 1; i < count; i++) {
1474		touched = touched | FillRect(copy.RectAt(i), gradient);
1475	}
1476	return touched;
1477}
1478
1479
1480// InvertRect
1481BRect
1482Painter::InvertRect(const BRect& r) const
1483{
1484	CHECK_CLIPPING
1485
1486	BRegion region(r);
1487	region.IntersectWith(fClippingRegion);
1488
1489	// implementation only for B_RGB32 at the moment
1490	int32 count = region.CountRects();
1491	for (int32 i = 0; i < count; i++)
1492		_InvertRect32(region.RectAt(i));
1493
1494	return _Clipped(r);
1495}
1496
1497
1498void
1499Painter::SetRendererOffset(int32 offsetX, int32 offsetY)
1500{
1501	fBaseRenderer.set_offset(offsetX, offsetY);
1502}
1503
1504
1505// #pragma mark - private
1506
1507
1508inline float
1509Painter::_Align(float coord, bool round, bool centerOffset) const
1510{
1511	// rounding
1512	if (round)
1513		coord = (int32)coord;
1514
1515	// This code is supposed to move coordinates to the center of pixels,
1516	// as AGG considers (0,0) to be the "upper left corner" of a pixel,
1517	// but BViews are less strict on those details
1518	if (centerOffset)
1519		coord += 0.5;
1520
1521	return coord;
1522}
1523
1524
1525inline void
1526Painter::_Align(BPoint* point, bool centerOffset) const
1527{
1528	_Align(point, !fSubpixelPrecise, centerOffset);
1529}
1530
1531
1532inline void
1533Painter::_Align(BPoint* point, bool round, bool centerOffset) const
1534{
1535	point->x = _Align(point->x, round, centerOffset);
1536	point->y = _Align(point->y, round, centerOffset);
1537}
1538
1539
1540inline BPoint
1541Painter::_Align(const BPoint& point, bool centerOffset) const
1542{
1543	BPoint ret(point);
1544	_Align(&ret, centerOffset);
1545	return ret;
1546}
1547
1548
1549// _Clipped
1550BRect
1551Painter::_Clipped(const BRect& rect) const
1552{
1553	if (rect.IsValid())
1554		return BRect(rect & fClippingRegion->Frame());
1555
1556	return BRect(rect);
1557}
1558
1559
1560// _UpdateDrawingMode
1561void
1562Painter::_UpdateDrawingMode(bool drawingText)
1563{
1564	// The AGG renderers have their own color setting, however
1565	// almost all drawing mode classes ignore the color given
1566	// by the AGG renderer and use the colors from the PatternHandler
1567	// instead. If we have a B_SOLID_* pattern, we can actually use
1568	// the color in the renderer and special versions of drawing modes
1569	// that don't use PatternHandler and are more efficient. This
1570	// has been implemented for B_OP_COPY and a couple others (the
1571	// DrawingMode*Solid ones) as of now. The PixelFormat knows the
1572	// PatternHandler and makes its decision based on the pattern.
1573	// The last parameter to SetDrawingMode() is a special flag
1574	// for when Painter is used to draw text. In this case, another
1575	// special version of B_OP_COPY is used that acts like R5 in that
1576	// anti-aliased pixel are not rendered against the actual background
1577	// but the current low color instead. This way, the frame buffer
1578	// doesn't need to be read.
1579	// When a solid pattern is used, _SetRendererColor()
1580	// has to be called so that all internal colors in the renderes
1581	// are up to date for use by the solid drawing mode version.
1582	fPixelFormat.SetDrawingMode(fDrawingMode, fAlphaSrcMode, fAlphaFncMode,
1583		drawingText);
1584	if (drawingText)
1585		fPatternHandler.MakeOpCopyColorCache();
1586}
1587
1588
1589// _SetRendererColor
1590void
1591Painter::_SetRendererColor(const rgb_color& color) const
1592{
1593	fRenderer.color(agg::rgba(color.red / 255.0, color.green / 255.0,
1594		color.blue / 255.0, color.alpha / 255.0));
1595	fSubpixRenderer.color(agg::rgba(color.red / 255.0, color.green / 255.0,
1596		color.blue / 255.0, color.alpha / 255.0));
1597// TODO: bitmap fonts not yet correctly setup in AGGTextRenderer
1598//	fRendererBin.color(agg::rgba(color.red / 255.0, color.green / 255.0,
1599//		color.blue / 255.0, color.alpha / 255.0));
1600}
1601
1602
1603// #pragma mark -
1604
1605
1606// _DrawTriangle
1607inline BRect
1608Painter::_DrawTriangle(BPoint pt1, BPoint pt2, BPoint pt3, bool fill) const
1609{
1610	CHECK_CLIPPING
1611
1612	_Align(&pt1);
1613	_Align(&pt2);
1614	_Align(&pt3);
1615
1616	fPath.remove_all();
1617
1618	fPath.move_to(pt1.x, pt1.y);
1619	fPath.line_to(pt2.x, pt2.y);
1620	fPath.line_to(pt3.x, pt3.y);
1621
1622	fPath.close_polygon();
1623
1624	if (fill)
1625		return _FillPath(fPath);
1626
1627	return _StrokePath(fPath);
1628}
1629
1630
1631void
1632Painter::_IterateShapeData(const int32& opCount, const uint32* opList,
1633	const int32& ptCount, const BPoint* points,
1634	const BPoint& viewToScreenOffset, float viewScale) const
1635{
1636	// TODO: if shapes are ever used more heavily in Haiku,
1637	// it would be nice to use BShape data directly (write
1638	// an AGG "VertexSource" adaptor)
1639	fPath.remove_all();
1640	for (int32 i = 0; i < opCount; i++) {
1641		uint32 op = opList[i] & 0xFF000000;
1642		if ((op & OP_MOVETO) != 0) {
1643			fPath.move_to(
1644				points->x * viewScale + viewToScreenOffset.x,
1645				points->y * viewScale + viewToScreenOffset.y);
1646			points++;
1647		}
1648
1649		if ((op & OP_LINETO) != 0) {
1650			int32 count = opList[i] & 0x00FFFFFF;
1651			while (count--) {
1652				fPath.line_to(
1653					points->x * viewScale + viewToScreenOffset.x,
1654					points->y * viewScale + viewToScreenOffset.y);
1655				points++;
1656			}
1657		}
1658
1659		if ((op & OP_BEZIERTO) != 0) {
1660			int32 count = opList[i] & 0x00FFFFFF;
1661			while (count) {
1662				fPath.curve4(
1663					points[0].x * viewScale + viewToScreenOffset.x,
1664					points[0].y * viewScale + viewToScreenOffset.y,
1665					points[1].x * viewScale + viewToScreenOffset.x,
1666					points[1].y * viewScale + viewToScreenOffset.y,
1667					points[2].x * viewScale + viewToScreenOffset.x,
1668					points[2].y * viewScale + viewToScreenOffset.y);
1669				points += 3;
1670				count -= 3;
1671			}
1672		}
1673
1674		if ((op & OP_LARGE_ARC_TO_CW) != 0 || (op & OP_LARGE_ARC_TO_CCW) != 0
1675			|| (op & OP_SMALL_ARC_TO_CW) != 0
1676			|| (op & OP_SMALL_ARC_TO_CCW) != 0) {
1677			int32 count = opList[i] & 0x00FFFFFF;
1678			while (count > 0) {
1679				fPath.arc_to(
1680					points[0].x * viewScale,
1681					points[0].y * viewScale,
1682					points[1].x,
1683					op & (OP_LARGE_ARC_TO_CW | OP_LARGE_ARC_TO_CCW),
1684					op & (OP_SMALL_ARC_TO_CW | OP_LARGE_ARC_TO_CW),
1685					points[2].x * viewScale + viewToScreenOffset.x,
1686					points[2].y * viewScale + viewToScreenOffset.y);
1687				points += 3;
1688				count -= 3;
1689			}
1690		}
1691
1692		if ((op & OP_CLOSE) != 0)
1693			fPath.close_polygon();
1694	}
1695}
1696
1697
1698// _InvertRect32
1699void
1700Painter::_InvertRect32(BRect r) const
1701{
1702	int32 width = r.IntegerWidth() + 1;
1703	for (int32 y = (int32)r.top; y <= (int32)r.bottom; y++) {
1704		uint8* dst = fBuffer.row_ptr(y);
1705		dst += (int32)r.left * 4;
1706		for (int32 i = 0; i < width; i++) {
1707			dst[0] = 255 - dst[0];
1708			dst[1] = 255 - dst[1];
1709			dst[2] = 255 - dst[2];
1710			dst += 4;
1711		}
1712	}
1713}
1714
1715
1716// _BlendRect32
1717void
1718Painter::_BlendRect32(const BRect& r, const rgb_color& c) const
1719{
1720	if (!fValidClipping)
1721		return;
1722
1723	uint8* dst = fBuffer.row_ptr(0);
1724	uint32 bpr = fBuffer.stride();
1725
1726	int32 left = (int32)r.left;
1727	int32 top = (int32)r.top;
1728	int32 right = (int32)r.right;
1729	int32 bottom = (int32)r.bottom;
1730
1731	// fill rects, iterate over clipping boxes
1732	fBaseRenderer.first_clip_box();
1733	do {
1734		int32 x1 = max_c(fBaseRenderer.xmin(), left);
1735		int32 x2 = min_c(fBaseRenderer.xmax(), right);
1736		if (x1 <= x2) {
1737			int32 y1 = max_c(fBaseRenderer.ymin(), top);
1738			int32 y2 = min_c(fBaseRenderer.ymax(), bottom);
1739
1740			uint8* offset = dst + x1 * 4 + y1 * bpr;
1741			for (; y1 <= y2; y1++) {
1742				blend_line32(offset, x2 - x1 + 1, c.red, c.green, c.blue,
1743					c.alpha);
1744				offset += bpr;
1745			}
1746		}
1747	} while (fBaseRenderer.next_clip_box());
1748}
1749
1750
1751// #pragma mark -
1752
1753
1754template<class VertexSource>
1755BRect
1756Painter::_BoundingBox(VertexSource& path) const
1757{
1758	double left = 0.0;
1759	double top = 0.0;
1760	double right = -1.0;
1761	double bottom = -1.0;
1762	uint32 pathID[1];
1763	pathID[0] = 0;
1764	agg::bounding_rect(path, pathID, 0, 1, &left, &top, &right, &bottom);
1765	return BRect(left, top, right, bottom);
1766}
1767
1768
1769// agg_line_cap_mode_for
1770inline agg::line_cap_e
1771agg_line_cap_mode_for(cap_mode mode)
1772{
1773	switch (mode) {
1774		case B_BUTT_CAP:
1775			return agg::butt_cap;
1776		case B_SQUARE_CAP:
1777			return agg::square_cap;
1778		case B_ROUND_CAP:
1779			return agg::round_cap;
1780	}
1781	return agg::butt_cap;
1782}
1783
1784
1785// agg_line_join_mode_for
1786inline agg::line_join_e
1787agg_line_join_mode_for(join_mode mode)
1788{
1789	switch (mode) {
1790		case B_MITER_JOIN:
1791			return agg::miter_join;
1792		case B_ROUND_JOIN:
1793			return agg::round_join;
1794		case B_BEVEL_JOIN:
1795		case B_BUTT_JOIN: // ??
1796		case B_SQUARE_JOIN: // ??
1797			return agg::bevel_join;
1798	}
1799	return agg::miter_join;
1800}
1801
1802
1803template<class VertexSource>
1804BRect
1805Painter::_StrokePath(VertexSource& path) const
1806{
1807	return _StrokePath(path, fLineCapMode);
1808}
1809
1810
1811template<class VertexSource>
1812BRect
1813Painter::_StrokePath(VertexSource& path, cap_mode capMode) const
1814{
1815	agg::conv_stroke<VertexSource> stroke(path);
1816	stroke.width(fPenSize);
1817
1818	stroke.line_cap(agg_line_cap_mode_for(capMode));
1819	stroke.line_join(agg_line_join_mode_for(fLineJoinMode));
1820	stroke.miter_limit(fMiterLimit);
1821
1822	if (fIdentityTransform)
1823		return _RasterizePath(stroke);
1824
1825	stroke.approximation_scale(fTransform.scale());
1826
1827	agg::conv_transform<agg::conv_stroke<VertexSource> > transformedStroke(
1828		stroke, fTransform);
1829	return _RasterizePath(transformedStroke);
1830}
1831
1832
1833// _FillPath
1834template<class VertexSource>
1835BRect
1836Painter::_FillPath(VertexSource& path) const
1837{
1838	if (fIdentityTransform)
1839		return _RasterizePath(path);
1840
1841	agg::conv_transform<VertexSource> transformedPath(path, fTransform);
1842	return _RasterizePath(transformedPath);
1843}
1844
1845
1846// _RasterizePath
1847template<class VertexSource>
1848BRect
1849Painter::_RasterizePath(VertexSource& path) const
1850{
1851	if (fMaskedUnpackedScanline != NULL) {
1852		// TODO: we can't do both alpha-masking and subpixel AA.
1853		fRasterizer.reset();
1854		fRasterizer.add_path(path);
1855		agg::render_scanlines(fRasterizer, *fMaskedUnpackedScanline,
1856			fRenderer);
1857	} else if (gSubpixelAntialiasing) {
1858		fSubpixRasterizer.reset();
1859		fSubpixRasterizer.add_path(path);
1860		agg::render_scanlines(fSubpixRasterizer,
1861			fSubpixPackedScanline, fSubpixRenderer);
1862	} else {
1863		fRasterizer.reset();
1864		fRasterizer.add_path(path);
1865		agg::render_scanlines(fRasterizer, fPackedScanline, fRenderer);
1866	}
1867
1868	return _Clipped(_BoundingBox(path));
1869}
1870
1871
1872// _FillPath
1873template<class VertexSource>
1874BRect
1875Painter::_FillPath(VertexSource& path, const BGradient& gradient) const
1876{
1877	if (fIdentityTransform)
1878		return _RasterizePath(path, gradient);
1879
1880	agg::conv_transform<VertexSource> transformedPath(path, fTransform);
1881	return _RasterizePath(transformedPath, gradient);
1882}
1883
1884
1885// _FillPath
1886template<class VertexSource>
1887BRect
1888Painter::_RasterizePath(VertexSource& path, const BGradient& gradient) const
1889{
1890	GTRACE("Painter::_RasterizePath\n");
1891
1892	agg::trans_affine gradientTransform;
1893
1894	switch (gradient.GetType()) {
1895		case BGradient::TYPE_LINEAR:
1896		{
1897			GTRACE(("Painter::_FillPath> type == TYPE_LINEAR\n"));
1898			const BGradientLinear& linearGradient
1899				= (const BGradientLinear&) gradient;
1900			agg::gradient_x gradientFunction;
1901			_CalcLinearGradientTransform(linearGradient.Start(),
1902				linearGradient.End(), gradientTransform);
1903			_RasterizePath(path, gradient, gradientFunction, gradientTransform);
1904			break;
1905		}
1906		case BGradient::TYPE_RADIAL:
1907		{
1908			GTRACE(("Painter::_FillPathGradient> type == TYPE_RADIAL\n"));
1909			const BGradientRadial& radialGradient
1910				= (const BGradientRadial&) gradient;
1911			agg::gradient_radial gradientFunction;
1912			_CalcRadialGradientTransform(radialGradient.Center(),
1913				gradientTransform);
1914			_RasterizePath(path, gradient, gradientFunction, gradientTransform,
1915				radialGradient.Radius());
1916			break;
1917		}
1918		case BGradient::TYPE_RADIAL_FOCUS:
1919		{
1920			GTRACE(("Painter::_FillPathGradient> type == TYPE_RADIAL_FOCUS\n"));
1921			const BGradientRadialFocus& radialGradient
1922				= (const BGradientRadialFocus&) gradient;
1923			agg::gradient_radial_focus gradientFunction;
1924			_CalcRadialGradientTransform(radialGradient.Center(),
1925				gradientTransform);
1926			_RasterizePath(path, gradient, gradientFunction, gradientTransform,
1927				radialGradient.Radius());
1928			break;
1929		}
1930		case BGradient::TYPE_DIAMOND:
1931		{
1932			GTRACE(("Painter::_FillPathGradient> type == TYPE_DIAMOND\n"));
1933			const BGradientDiamond& diamontGradient
1934				= (const BGradientDiamond&) gradient;
1935			agg::gradient_diamond gradientFunction;
1936			_CalcRadialGradientTransform(diamontGradient.Center(),
1937				gradientTransform);
1938			_RasterizePath(path, gradient, gradientFunction, gradientTransform);
1939			break;
1940		}
1941		case BGradient::TYPE_CONIC:
1942		{
1943			GTRACE(("Painter::_FillPathGradient> type == TYPE_CONIC\n"));
1944			const BGradientConic& conicGradient
1945				= (const BGradientConic&) gradient;
1946			agg::gradient_conic gradientFunction;
1947			_CalcRadialGradientTransform(conicGradient.Center(),
1948				gradientTransform);
1949			_RasterizePath(path, gradient, gradientFunction, gradientTransform);
1950			break;
1951		}
1952
1953		default:
1954		case BGradient::TYPE_NONE:
1955			GTRACE(("Painter::_FillPathGradient> type == TYPE_NONE/unkown\n"));
1956			break;
1957	}
1958
1959	return _Clipped(_BoundingBox(path));
1960}
1961
1962
1963void
1964Painter::_CalcLinearGradientTransform(BPoint startPoint, BPoint endPoint,
1965	agg::trans_affine& matrix, float gradient_d2) const
1966{
1967	float dx = endPoint.x - startPoint.x;
1968	float dy = endPoint.y - startPoint.y;
1969
1970	matrix.reset();
1971	matrix *= agg::trans_affine_scaling(sqrt(dx * dx + dy * dy) / gradient_d2);
1972	matrix *= agg::trans_affine_rotation(atan2(dy, dx));
1973	matrix *= agg::trans_affine_translation(startPoint.x, startPoint.y);
1974	matrix *= fTransform;
1975	matrix.invert();
1976}
1977
1978
1979void
1980Painter::_CalcRadialGradientTransform(BPoint center,
1981	agg::trans_affine& matrix, float gradient_d2) const
1982{
1983	matrix.reset();
1984	matrix *= agg::trans_affine_translation(center.x, center.y);
1985	matrix *= fTransform;
1986	matrix.invert();
1987}
1988
1989
1990void
1991Painter::_MakeGradient(const BGradient& gradient, int32 colorCount,
1992	uint32* colors, int32 arrayOffset, int32 arraySize) const
1993{
1994	BGradient::ColorStop* from = gradient.ColorStopAt(0);
1995
1996	if (!from)
1997		return;
1998
1999	// current index into "colors" array
2000//	int32 index = (int32)floorf(colorCount * from->offset + 0.5)
2001//		+ arrayOffset;
2002	int32 index = (int32)floorf(colorCount * from->offset / 255 + 0.5)
2003		+ arrayOffset;
2004	if (index > arraySize)
2005		index = arraySize;
2006	// Make sure we fill the entire array in case the gradient is outside.
2007	if (index > 0) {
2008		uint8* c = (uint8*)&colors[0];
2009		for (int32 i = 0; i < index; i++) {
2010			c[0] = from->color.blue;
2011			c[1] = from->color.green;
2012			c[2] = from->color.red;
2013			c[3] = from->color.alpha;
2014			c += 4;
2015		}
2016	}
2017
2018	// interpolate "from" to "to"
2019	int32 stopCount = gradient.CountColorStops();
2020	for (int32 i = 1; i < stopCount; i++) {
2021		// find the step with the next offset
2022		BGradient::ColorStop* to = gradient.ColorStopAtFast(i);
2023
2024		// interpolate
2025//		int32 offset = (int32)floorf((colorCount - 1) * to->offset + 0.5);
2026		int32 offset = (int32)floorf((colorCount - 1)
2027			* to->offset / 255 + 0.5);
2028		if (offset > colorCount - 1)
2029			offset = colorCount - 1;
2030		offset += arrayOffset;
2031		int32 dist = offset - index;
2032		if (dist >= 0) {
2033			int32 startIndex = max_c(index, 0);
2034			int32 stopIndex = min_c(offset, arraySize - 1);
2035			uint8* c = (uint8*)&colors[startIndex];
2036			for (int32 i = startIndex; i <= stopIndex; i++) {
2037				float f = (float)(offset - i) / (float)(dist + 1);
2038				float t = 1.0 - f;
2039				c[0] = (uint8)floorf(from->color.blue * f
2040					+ to->color.blue * t + 0.5);
2041				c[1] = (uint8)floorf(from->color.green * f
2042					+ to->color.green * t + 0.5);
2043				c[2] = (uint8)floorf(from->color.red * f
2044					+ to->color.red * t + 0.5);
2045				c[3] = (uint8)floorf(from->color.alpha * f
2046					+ to->color.alpha * t + 0.5);
2047				c += 4;
2048			}
2049		}
2050		index = offset + 1;
2051		// the current "to" will be the "from" in the next interpolation
2052		from = to;
2053	}
2054	//  make sure we fill the entire array
2055	if (index < arraySize) {
2056		int32 startIndex = max_c(index, 0);
2057		uint8* c = (uint8*)&colors[startIndex];
2058		for (int32 i = startIndex; i < arraySize; i++) {
2059			c[0] = from->color.blue;
2060			c[1] = from->color.green;
2061			c[2] = from->color.red;
2062			c[3] = from->color.alpha;
2063			c += 4;
2064		}
2065	}
2066}
2067
2068
2069template<class Array>
2070void
2071Painter::_MakeGradient(Array& array, const BGradient& gradient) const
2072{
2073	for (int i = 0; i < gradient.CountColorStops() - 1; i++) {
2074		BGradient::ColorStop* from = gradient.ColorStopAtFast(i);
2075		BGradient::ColorStop* to = gradient.ColorStopAtFast(i + 1);
2076		agg::rgba8 fromColor(from->color.red, from->color.green,
2077							 from->color.blue, from->color.alpha);
2078		agg::rgba8 toColor(to->color.red, to->color.green,
2079						   to->color.blue, to->color.alpha);
2080		GTRACE("Painter::_MakeGradient> fromColor(%d, %d, %d, %d) offset = %f\n",
2081			   fromColor.r, fromColor.g, fromColor.b, fromColor.a,
2082			   from->offset);
2083		GTRACE("Painter::_MakeGradient> toColor(%d, %d, %d %d) offset = %f\n",
2084			   toColor.r, toColor.g, toColor.b, toColor.a, to->offset);
2085		float dist = to->offset - from->offset;
2086		GTRACE("Painter::_MakeGradient> dist = %f\n", dist);
2087		// TODO: Review this... offset should better be on [0..1]
2088		if (dist > 0) {
2089			for (int j = (int)from->offset; j <= (int)to->offset; j++) {
2090				float f = (float)(to->offset - j) / (float)(dist + 1);
2091				array[j] = toColor.gradient(fromColor, f);
2092				GTRACE("Painter::_MakeGradient> array[%d](%d, %d, %d, %d)\n",
2093					   j, array[j].r, array[j].g, array[j].b, array[j].a);
2094			}
2095		}
2096	}
2097}
2098
2099
2100template<class VertexSource, typename GradientFunction>
2101void
2102Painter::_RasterizePath(VertexSource& path, const BGradient& gradient,
2103	GradientFunction function, agg::trans_affine& gradientTransform,
2104	int gradientStop) const
2105{
2106	GTRACE("Painter::_RasterizePath\n");
2107
2108	typedef agg::span_interpolator_linear<> interpolator_type;
2109	typedef agg::pod_auto_array<agg::rgba8, 256> color_array_type;
2110	typedef agg::span_allocator<agg::rgba8> span_allocator_type;
2111	typedef agg::span_gradient<agg::rgba8, interpolator_type,
2112				GradientFunction, color_array_type> span_gradient_type;
2113	typedef agg::renderer_scanline_aa<renderer_base, span_allocator_type,
2114				span_gradient_type> renderer_gradient_type;
2115
2116	interpolator_type spanInterpolator(gradientTransform);
2117	span_allocator_type spanAllocator;
2118	color_array_type colorArray;
2119
2120	_MakeGradient(colorArray, gradient);
2121
2122	span_gradient_type spanGradient(spanInterpolator, function, colorArray,
2123		0, gradientStop);
2124
2125	renderer_gradient_type gradientRenderer(fBaseRenderer, spanAllocator,
2126		spanGradient);
2127
2128	fRasterizer.reset();
2129	fRasterizer.add_path(path);
2130	if (fMaskedUnpackedScanline == NULL)
2131		agg::render_scanlines(fRasterizer, fUnpackedScanline, gradientRenderer);
2132	else {
2133		agg::render_scanlines(fRasterizer, *fMaskedUnpackedScanline,
2134			gradientRenderer);
2135	}
2136}
2137