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