xref: /haiku/src/servers/app/drawing/Painter/Painter.cpp (revision c2f0a314a012bea8e4ebb35b8ce9e1a85c798727)
1 /*
2  * Copyright 2009, Christian Packmann.
3  * Copyright 2008, Andrej Spielmann <andrej.spielmann@seh.ox.ac.uk>.
4  * Copyright 2005-2009, Stephan Aßmus <superstippi@gmx.de>.
5  * All rights reserved. Distributed under the terms of the MIT License.
6  */
7 
8 /*!	API to the Anti-Grain Geometry based "Painter" drawing backend. Manages
9 	rendering pipe-lines for stroke, fills, bitmap and text rendering.
10 */
11 
12 #include "Painter.h"
13 
14 #include <new>
15 
16 #include <stdio.h>
17 #include <string.h>
18 
19 #include <Bitmap.h>
20 #include <GraphicsDefs.h>
21 #include <Region.h>
22 #include <String.h>
23 #include <GradientLinear.h>
24 #include <GradientRadial.h>
25 #include <GradientRadialFocus.h>
26 #include <GradientDiamond.h>
27 #include <GradientConic.h>
28 
29 #include <ShapePrivate.h>
30 
31 #include <agg_bezier_arc.h>
32 #include <agg_bounding_rect.h>
33 #include <agg_conv_clip_polygon.h>
34 #include <agg_conv_curve.h>
35 #include <agg_conv_stroke.h>
36 #include <agg_ellipse.h>
37 #include <agg_image_accessors.h>
38 #include <agg_path_storage.h>
39 #include <agg_pixfmt_rgba.h>
40 #include <agg_rounded_rect.h>
41 #include <agg_span_allocator.h>
42 #include <agg_span_image_filter_rgba.h>
43 #include <agg_span_interpolator_linear.h>
44 
45 #include "drawing_support.h"
46 
47 #include "DrawState.h"
48 
49 #include <AutoDeleter.h>
50 #include <View.h>
51 
52 #include "DrawingMode.h"
53 #include "GlobalSubpixelSettings.h"
54 #include "PatternHandler.h"
55 #include "RenderingBuffer.h"
56 #include "ServerBitmap.h"
57 #include "ServerFont.h"
58 #include "SystemPalette.h"
59 
60 #include "AppServer.h"
61 
62 using std::nothrow;
63 
64 #undef TRACE
65 // #define TRACE_PAINTER
66 #ifdef TRACE_PAINTER
67 #	define TRACE(x...)		printf(x)
68 #else
69 #	define TRACE(x...)
70 #endif
71 
72 //#define TRACE_GRADIENTS
73 #ifdef TRACE_GRADIENTS
74 #	include <OS.h>
75 #	define GTRACE(x...)		debug_printf(x)
76 #else
77 #	define GTRACE(x...)
78 #endif
79 
80 
81 #define CHECK_CLIPPING	if (!fValidClipping) return BRect(0, 0, -1, -1);
82 #define CHECK_CLIPPING_NO_RETURN	if (!fValidClipping) return;
83 
84 
85 // constructor
86 Painter::Painter()
87 	:
88 	fBuffer(),
89 	fPixelFormat(fBuffer, &fPatternHandler),
90 	fBaseRenderer(fPixelFormat),
91 	fUnpackedScanline(),
92 	fPackedScanline(),
93 	fSubpixPackedScanline(),
94 	fSubpixUnpackedScanline(),
95 	fSubpixRasterizer(),
96 	fRasterizer(),
97 	fSubpixRenderer(fBaseRenderer),
98 	fRenderer(fBaseRenderer),
99 	fRendererBin(fBaseRenderer),
100 
101 	fPath(),
102 	fCurve(fPath),
103 
104 	fSubpixelPrecise(false),
105 	fValidClipping(false),
106 	fDrawingText(false),
107 	fAttached(false),
108 
109 	fPenSize(1.0),
110 	fClippingRegion(NULL),
111 	fDrawingMode(B_OP_COPY),
112 	fAlphaSrcMode(B_PIXEL_ALPHA),
113 	fAlphaFncMode(B_ALPHA_OVERLAY),
114 	fLineCapMode(B_BUTT_CAP),
115 	fLineJoinMode(B_MITER_JOIN),
116 	fMiterLimit(B_DEFAULT_MITER_LIMIT),
117 
118 	fPatternHandler(),
119 	fTextRenderer(fSubpixRenderer, fRenderer, fRendererBin, fUnpackedScanline,
120 		fSubpixUnpackedScanline, fSubpixRasterizer)
121 {
122 	fPixelFormat.SetDrawingMode(fDrawingMode, fAlphaSrcMode, fAlphaFncMode,
123 		false);
124 
125 #if ALIASED_DRAWING
126 	fRasterizer.gamma(agg::gamma_threshold(0.5));
127 	fSubpixRasterizer.gamma(agg:gamma_threshold(0.5));
128 #endif
129 }
130 
131 
132 // destructor
133 Painter::~Painter()
134 {
135 }
136 
137 
138 // #pragma mark -
139 
140 
141 // AttachToBuffer
142 void
143 Painter::AttachToBuffer(RenderingBuffer* buffer)
144 {
145 	if (buffer && buffer->InitCheck() >= B_OK
146 		&& (buffer->ColorSpace() == B_RGBA32
147 			|| buffer->ColorSpace() == B_RGB32)) {
148 		// TODO: implement drawing on B_RGB24, B_RGB15, B_RGB16,
149 		// B_CMAP8 and B_GRAY8 :-[
150 		// (if ever we want to support some devices where this gives
151 		// a great speed up, right now it seems fine, even in emulation)
152 
153 		fBuffer.attach((uint8*)buffer->Bits(),
154 			buffer->Width(), buffer->Height(), buffer->BytesPerRow());
155 
156 		fAttached = true;
157 		fValidClipping = fClippingRegion
158 			&& fClippingRegion->Frame().IsValid();
159 
160 		// These are the AGG renderes and rasterizes which
161 		// will be used for stroking paths
162 
163 		_SetRendererColor(fPatternHandler.HighColor());
164 	}
165 }
166 
167 
168 // DetachFromBuffer
169 void
170 Painter::DetachFromBuffer()
171 {
172 	fBuffer.attach(NULL, 0, 0, 0);
173 	fAttached = false;
174 	fValidClipping = false;
175 }
176 
177 
178 // Bounds
179 BRect
180 Painter::Bounds() const
181 {
182 	return BRect(0, 0, fBuffer.width() - 1, fBuffer.height() - 1);
183 }
184 
185 
186 // #pragma mark -
187 
188 
189 // SetDrawState
190 void
191 Painter::SetDrawState(const DrawState* data, int32 xOffset, int32 yOffset)
192 {
193 	// NOTE: The custom clipping in "data" is ignored, because it has already
194 	// been taken into account elsewhere
195 
196 	// NOTE: Usually this function is only used when the "current view"
197 	// is switched in the ServerWindow and after the decorator has drawn
198 	// and messed up the state. For other graphics state changes, the
199 	// Painter methods are used directly, so this function is much less
200 	// speed critical than it used to be.
201 
202 	SetPenSize(data->PenSize());
203 
204 	SetFont(data);
205 
206 	fSubpixelPrecise = data->SubPixelPrecise();
207 
208 	// any of these conditions means we need to use a different drawing
209 	// mode instance
210 	bool updateDrawingMode
211 		= !(data->GetPattern() == fPatternHandler.GetPattern())
212 			|| data->GetDrawingMode() != fDrawingMode
213 			|| (data->GetDrawingMode() == B_OP_ALPHA
214 				&& (data->AlphaSrcMode() != fAlphaSrcMode
215 					|| data->AlphaFncMode() != fAlphaFncMode));
216 
217 	fDrawingMode = data->GetDrawingMode();
218 	fAlphaSrcMode = data->AlphaSrcMode();
219 	fAlphaFncMode = data->AlphaFncMode();
220 	fPatternHandler.SetPattern(data->GetPattern());
221 	fPatternHandler.SetOffsets(xOffset, yOffset);
222 	fLineCapMode = data->LineCapMode();
223 	fLineJoinMode = data->LineJoinMode();
224 	fMiterLimit = data->MiterLimit();
225 
226 	// adopt the color *after* the pattern is set
227 	// to set the renderers to the correct color
228 	SetHighColor(data->HighColor());
229 	SetLowColor(data->LowColor());
230 
231 	if (updateDrawingMode || fPixelFormat.UsesOpCopyForText())
232 		_UpdateDrawingMode();
233 }
234 
235 
236 // #pragma mark - state
237 
238 
239 // ConstrainClipping
240 void
241 Painter::ConstrainClipping(const BRegion* region)
242 {
243 	fClippingRegion = region;
244 	fBaseRenderer.set_clipping_region(const_cast<BRegion*>(region));
245 	fValidClipping = region->Frame().IsValid() && fAttached;
246 
247 	if (fValidClipping) {
248 		clipping_rect cb = fClippingRegion->FrameInt();
249 		fRasterizer.clip_box(cb.left, cb.top, cb.right + 1, cb.bottom + 1);
250 		fSubpixRasterizer.clip_box(cb.left, cb.top, cb.right + 1, cb.bottom + 1);
251 	}
252 }
253 
254 
255 // SetHighColor
256 void
257 Painter::SetHighColor(const rgb_color& color)
258 {
259 	if (fPatternHandler.HighColor() == color)
260 		return;
261 	fPatternHandler.SetHighColor(color);
262 	if (*(fPatternHandler.GetR5Pattern()) == B_SOLID_HIGH)
263 		_SetRendererColor(color);
264 }
265 
266 
267 // SetLowColor
268 void
269 Painter::SetLowColor(const rgb_color& color)
270 {
271 	fPatternHandler.SetLowColor(color);
272 	if (*(fPatternHandler.GetR5Pattern()) == B_SOLID_LOW)
273 		_SetRendererColor(color);
274 }
275 
276 
277 // SetDrawingMode
278 void
279 Painter::SetDrawingMode(drawing_mode mode)
280 {
281 	if (fDrawingMode != mode) {
282 		fDrawingMode = mode;
283 		_UpdateDrawingMode();
284 	}
285 }
286 
287 
288 // SetBlendingMode
289 void
290 Painter::SetBlendingMode(source_alpha srcAlpha, alpha_function alphaFunc)
291 {
292 	if (fAlphaSrcMode != srcAlpha || fAlphaFncMode != alphaFunc) {
293 		fAlphaSrcMode = srcAlpha;
294 		fAlphaFncMode = alphaFunc;
295 		if (fDrawingMode == B_OP_ALPHA)
296 			_UpdateDrawingMode();
297 	}
298 }
299 
300 
301 // SetPenSize
302 void
303 Painter::SetPenSize(float size)
304 {
305 	fPenSize = size;
306 }
307 
308 
309 // SetStrokeMode
310 void
311 Painter::SetStrokeMode(cap_mode lineCap, join_mode joinMode, float miterLimit)
312 {
313 	fLineCapMode = lineCap;
314 	fLineJoinMode = joinMode;
315 	fMiterLimit = miterLimit;
316 }
317 
318 
319 // SetPattern
320 void
321 Painter::SetPattern(const pattern& p, bool drawingText)
322 {
323 	if (!(p == *fPatternHandler.GetR5Pattern()) || drawingText != fDrawingText) {
324 		fPatternHandler.SetPattern(p);
325 		fDrawingText = drawingText;
326 		_UpdateDrawingMode(fDrawingText);
327 
328 		// update renderer color if necessary
329 		if (fPatternHandler.IsSolidHigh()) {
330 			// pattern was not solid high before
331 			_SetRendererColor(fPatternHandler.HighColor());
332 		} else if (fPatternHandler.IsSolidLow()) {
333 			// pattern was not solid low before
334 			_SetRendererColor(fPatternHandler.LowColor());
335 		}
336 	}
337 }
338 
339 
340 // SetFont
341 void
342 Painter::SetFont(const ServerFont& font)
343 {
344 	fTextRenderer.SetFont(font);
345 	fTextRenderer.SetAntialiasing(!(font.Flags() & B_DISABLE_ANTIALIASING));
346 }
347 
348 
349 // SetFont
350 void
351 Painter::SetFont(const DrawState* state)
352 {
353 	fTextRenderer.SetFont(state->Font());
354 	fTextRenderer.SetAntialiasing(!state->ForceFontAliasing()
355 		&& (state->Font().Flags() & B_DISABLE_ANTIALIASING) == 0);
356 }
357 
358 
359 // #pragma mark - drawing
360 
361 
362 // StrokeLine
363 void
364 Painter::StrokeLine(BPoint a, BPoint b)
365 {
366 	CHECK_CLIPPING_NO_RETURN
367 
368 	// "false" means not to do the pixel center offset,
369 	// because it would mess up our optimized versions
370 	_Transform(&a, false);
371 	_Transform(&b, false);
372 
373 	// first, try an optimized version
374 	if (fPenSize == 1.0
375 		&& (fDrawingMode == B_OP_COPY || fDrawingMode == B_OP_OVER)) {
376 		pattern pat = *fPatternHandler.GetR5Pattern();
377 		if (pat == B_SOLID_HIGH
378 			&& StraightLine(a, b, fPatternHandler.HighColor())) {
379 			return;
380 		} else if (pat == B_SOLID_LOW
381 			&& StraightLine(a, b, fPatternHandler.LowColor())) {
382 			return;
383 		}
384 	}
385 
386 	fPath.remove_all();
387 
388 	if (a == b) {
389 		// special case dots
390 		if (fPenSize == 1.0 && !fSubpixelPrecise) {
391 			if (fClippingRegion->Contains(a)) {
392 				fPixelFormat.blend_pixel((int)a.x, (int)a.y, fRenderer.color(),
393 					255);
394 			}
395 		} else {
396 			fPath.move_to(a.x, a.y);
397 			fPath.line_to(a.x + 1, a.y);
398 			fPath.line_to(a.x + 1, a.y + 1);
399 			fPath.line_to(a.x, a.y + 1);
400 
401 			_FillPath(fPath);
402 		}
403 	} else {
404 		// do the pixel center offset here
405 		// tweak ends to "include" the pixel at the index,
406 		// we need to do this in order to produce results like R5,
407 		// where coordinates were inclusive
408 		if (!fSubpixelPrecise) {
409 			bool centerOnLine = fmodf(fPenSize, 2.0) != 0.0;
410 			if (a.x == b.x) {
411 				// shift to pixel center vertically
412 				if (centerOnLine) {
413 					a.x += 0.5;
414 					b.x += 0.5;
415 				}
416 				// extend on bottom end
417 				if (a.y < b.y)
418 					b.y++;
419 				else
420 					a.y++;
421 			} else if (a.y == b.y) {
422 				if (centerOnLine) {
423 					// shift to pixel center horizontally
424 					a.y += 0.5;
425 					b.y += 0.5;
426 				}
427 				// extend on right end
428 				if (a.x < b.x)
429 					b.x++;
430 				else
431 					a.x++;
432 			} else {
433 				// do this regardless of pensize
434 				if (a.x < b.x)
435 					b.x++;
436 				else
437 					a.x++;
438 				if (a.y < b.y)
439 					b.y++;
440 				else
441 					a.y++;
442 			}
443 		}
444 
445 		fPath.move_to(a.x, a.y);
446 		fPath.line_to(b.x, b.y);
447 
448 		_StrokePath(fPath);
449 	}
450 }
451 
452 
453 // StraightLine
454 bool
455 Painter::StraightLine(BPoint a, BPoint b, const rgb_color& c) const
456 {
457 	if (!fValidClipping)
458 		return false;
459 
460 	if (a.x == b.x) {
461 		// vertical
462 		uint8* dst = fBuffer.row_ptr(0);
463 		uint32 bpr = fBuffer.stride();
464 		int32 x = (int32)a.x;
465 		dst += x * 4;
466 		int32 y1 = (int32)min_c(a.y, b.y);
467 		int32 y2 = (int32)max_c(a.y, b.y);
468 		pixel32 color;
469 		color.data8[0] = c.blue;
470 		color.data8[1] = c.green;
471 		color.data8[2] = c.red;
472 		color.data8[3] = 255;
473 		// draw a line, iterate over clipping boxes
474 		fBaseRenderer.first_clip_box();
475 		do {
476 			if (fBaseRenderer.xmin() <= x &&
477 				fBaseRenderer.xmax() >= x) {
478 				int32 i = max_c(fBaseRenderer.ymin(), y1);
479 				int32 end = min_c(fBaseRenderer.ymax(), y2);
480 				uint8* handle = dst + i * bpr;
481 				for (; i <= end; i++) {
482 					*(uint32*)handle = color.data32;
483 					handle += bpr;
484 				}
485 			}
486 		} while (fBaseRenderer.next_clip_box());
487 
488 		return true;
489 	}
490 
491 	if (a.y == b.y) {
492 		// horizontal
493 		int32 y = (int32)a.y;
494 		if (y < 0 || y >= (int32)fBuffer.height())
495 			return true;
496 
497 		uint8* dst = fBuffer.row_ptr(y);
498 		int32 x1 = (int32)min_c(a.x, b.x);
499 		int32 x2 = (int32)max_c(a.x, b.x);
500 		pixel32 color;
501 		color.data8[0] = c.blue;
502 		color.data8[1] = c.green;
503 		color.data8[2] = c.red;
504 		color.data8[3] = 255;
505 		// draw a line, iterate over clipping boxes
506 		fBaseRenderer.first_clip_box();
507 		do {
508 			if (fBaseRenderer.ymin() <= y &&
509 				fBaseRenderer.ymax() >= y) {
510 				int32 i = max_c(fBaseRenderer.xmin(), x1);
511 				int32 end = min_c(fBaseRenderer.xmax(), x2);
512 				uint32* handle = (uint32*)(dst + i * 4);
513 				for (; i <= end; i++) {
514 					*handle++ = color.data32;
515 				}
516 			}
517 		} while (fBaseRenderer.next_clip_box());
518 
519 		return true;
520 	}
521 	return false;
522 }
523 
524 
525 // #pragma mark -
526 
527 
528 // StrokeTriangle
529 BRect
530 Painter::StrokeTriangle(BPoint pt1, BPoint pt2, BPoint pt3) const
531 {
532 	return _DrawTriangle(pt1, pt2, pt3, false);
533 }
534 
535 
536 // FillTriangle
537 BRect
538 Painter::FillTriangle(BPoint pt1, BPoint pt2, BPoint pt3) const
539 {
540 	return _DrawTriangle(pt1, pt2, pt3, true);
541 }
542 
543 
544 // FillTriangle
545 BRect
546 Painter::FillTriangle(BPoint pt1, BPoint pt2, BPoint pt3,
547 	const BGradient& gradient) const
548 {
549 	CHECK_CLIPPING
550 
551 	_Transform(&pt1);
552 	_Transform(&pt2);
553 	_Transform(&pt3);
554 
555 	fPath.remove_all();
556 
557 	fPath.move_to(pt1.x, pt1.y);
558 	fPath.line_to(pt2.x, pt2.y);
559 	fPath.line_to(pt3.x, pt3.y);
560 
561 	fPath.close_polygon();
562 
563 	return _FillPath(fPath, gradient);
564 }
565 
566 
567 // DrawPolygon
568 BRect
569 Painter::DrawPolygon(BPoint* p, int32 numPts, bool filled, bool closed) const
570 {
571 	CHECK_CLIPPING
572 
573 	if (numPts > 0) {
574 		fPath.remove_all();
575 
576 		_Transform(p);
577 		fPath.move_to(p->x, p->y);
578 
579 		for (int32 i = 1; i < numPts; i++) {
580 			p++;
581 			_Transform(p);
582 			fPath.line_to(p->x, p->y);
583 		}
584 
585 		if (closed)
586 			fPath.close_polygon();
587 
588 		if (filled)
589 			return _FillPath(fPath);
590 
591 		return _StrokePath(fPath);
592 	}
593 	return BRect(0.0, 0.0, -1.0, -1.0);
594 }
595 
596 
597 // FillPolygon
598 BRect
599 Painter::FillPolygon(BPoint* p, int32 numPts, const BGradient& gradient,
600 	bool closed) const
601 {
602 	CHECK_CLIPPING
603 
604 	if (numPts > 0) {
605 		fPath.remove_all();
606 
607 		_Transform(p);
608 		fPath.move_to(p->x, p->y);
609 
610 		for (int32 i = 1; i < numPts; i++) {
611 			p++;
612 			_Transform(p);
613 			fPath.line_to(p->x, p->y);
614 		}
615 
616 		if (closed)
617 			fPath.close_polygon();
618 
619 		return _FillPath(fPath, gradient);
620 	}
621 	return BRect(0.0, 0.0, -1.0, -1.0);
622 }
623 
624 
625 // DrawBezier
626 BRect
627 Painter::DrawBezier(BPoint* p, bool filled) const
628 {
629 	CHECK_CLIPPING
630 
631 	fPath.remove_all();
632 
633 	_Transform(&(p[0]));
634 	_Transform(&(p[1]));
635 	_Transform(&(p[2]));
636 	_Transform(&(p[3]));
637 
638 	fPath.move_to(p[0].x, p[0].y);
639 	fPath.curve4(p[1].x, p[1].y, p[2].x, p[2].y, p[3].x, p[3].y);
640 
641 	if (filled) {
642 		fPath.close_polygon();
643 		return _FillPath(fCurve);
644 	}
645 
646 	return _StrokePath(fCurve);
647 }
648 
649 
650 // FillBezier
651 BRect
652 Painter::FillBezier(BPoint* p, const BGradient& gradient) const
653 {
654 	CHECK_CLIPPING
655 
656 	fPath.remove_all();
657 
658 	_Transform(&(p[0]));
659 	_Transform(&(p[1]));
660 	_Transform(&(p[2]));
661 	_Transform(&(p[3]));
662 
663 	fPath.move_to(p[0].x, p[0].y);
664 	fPath.curve4(p[1].x, p[1].y, p[2].x, p[2].y, p[3].x, p[3].y);
665 
666 	fPath.close_polygon();
667 	return _FillPath(fCurve, gradient);
668 }
669 
670 
671 static void
672 iterate_shape_data(agg::path_storage& path,
673 	const int32& opCount, const uint32* opList,
674 	const int32& ptCount, const BPoint* points,
675 	const BPoint& viewToScreenOffset, float viewScale)
676 {
677 	// TODO: if shapes are ever used more heavily in Haiku,
678 	// it would be nice to use BShape data directly (write
679 	// an AGG "VertexSource" adaptor)
680 	path.remove_all();
681 	for (int32 i = 0; i < opCount; i++) {
682 		uint32 op = opList[i] & 0xFF000000;
683 		if (op & OP_MOVETO) {
684 			path.move_to(
685 				points->x * viewScale + viewToScreenOffset.x,
686 				points->y * viewScale + viewToScreenOffset.y);
687 			points++;
688 		}
689 
690 		if (op & OP_LINETO) {
691 			int32 count = opList[i] & 0x00FFFFFF;
692 			while (count--) {
693 				path.line_to(
694 					points->x * viewScale + viewToScreenOffset.x,
695 					points->y * viewScale + viewToScreenOffset.y);
696 				points++;
697 			}
698 		}
699 
700 		if (op & OP_BEZIERTO) {
701 			int32 count = opList[i] & 0x00FFFFFF;
702 			while (count) {
703 				path.curve4(
704 					points[0].x * viewScale + viewToScreenOffset.x,
705 					points[0].y * viewScale + viewToScreenOffset.y,
706 					points[1].x * viewScale + viewToScreenOffset.x,
707 					points[1].y * viewScale + viewToScreenOffset.y,
708 					points[2].x * viewScale + viewToScreenOffset.x,
709 					points[2].y * viewScale + viewToScreenOffset.y);
710 				points += 3;
711 				count -= 3;
712 			}
713 		}
714 
715 		if ((op & OP_LARGE_ARC_TO_CW) || (op & OP_LARGE_ARC_TO_CCW)
716 			|| (op & OP_SMALL_ARC_TO_CW) || (op & OP_SMALL_ARC_TO_CCW)) {
717 			int32 count = opList[i] & 0x00FFFFFF;
718 			while (count) {
719 				path.arc_to(
720 					points[0].x * viewScale,
721 					points[0].y * viewScale,
722 					points[1].x,
723 					op & (OP_LARGE_ARC_TO_CW | OP_LARGE_ARC_TO_CCW),
724 					op & (OP_SMALL_ARC_TO_CW | OP_LARGE_ARC_TO_CW),
725 					points[2].x * viewScale + viewToScreenOffset.x,
726 					points[2].y * viewScale + viewToScreenOffset.y);
727 				points += 3;
728 				count -= 3;
729 			}
730 		}
731 
732 		if (op & OP_CLOSE)
733 			path.close_polygon();
734 	}
735 }
736 
737 
738 // DrawShape
739 BRect
740 Painter::DrawShape(const int32& opCount, const uint32* opList,
741 	const int32& ptCount, const BPoint* points, bool filled,
742 	const BPoint& viewToScreenOffset, float viewScale) const
743 {
744 	CHECK_CLIPPING
745 
746 	iterate_shape_data(fPath, opCount, opList, ptCount, points,
747 		viewToScreenOffset, viewScale);
748 
749 	if (filled)
750 		return _FillPath(fCurve);
751 
752 	return _StrokePath(fCurve);
753 }
754 
755 
756 // FillShape
757 BRect
758 Painter::FillShape(const int32& opCount, const uint32* opList,
759 	const int32& ptCount, const BPoint* points, const BGradient& gradient,
760 	const BPoint& viewToScreenOffset, float viewScale) const
761 {
762 	CHECK_CLIPPING
763 
764 	iterate_shape_data(fPath, opCount, opList, ptCount, points,
765 		viewToScreenOffset, viewScale);
766 
767 	return _FillPath(fCurve, gradient);
768 }
769 
770 
771 // StrokeRect
772 BRect
773 Painter::StrokeRect(const BRect& r) const
774 {
775 	CHECK_CLIPPING
776 
777 	BPoint a(r.left, r.top);
778 	BPoint b(r.right, r.bottom);
779 	_Transform(&a, false);
780 	_Transform(&b, false);
781 
782 	// first, try an optimized version
783 	if (fPenSize == 1.0 &&
784 		(fDrawingMode == B_OP_COPY || fDrawingMode == B_OP_OVER)) {
785 		pattern p = *fPatternHandler.GetR5Pattern();
786 		if (p == B_SOLID_HIGH) {
787 			BRect rect(a, b);
788 			StrokeRect(rect, fPatternHandler.HighColor());
789 			return _Clipped(rect);
790 		} else if (p == B_SOLID_LOW) {
791 			BRect rect(a, b);
792 			StrokeRect(rect, fPatternHandler.LowColor());
793 			return _Clipped(rect);
794 		}
795 	}
796 
797 	if (fmodf(fPenSize, 2.0) != 0.0) {
798 		// shift coords to center of pixels
799 		a.x += 0.5;
800 		a.y += 0.5;
801 		b.x += 0.5;
802 		b.y += 0.5;
803 	}
804 
805 	fPath.remove_all();
806 	fPath.move_to(a.x, a.y);
807 	if (a.x == b.x || a.y == b.y) {
808 		// special case rects with one pixel height or width
809 		fPath.line_to(b.x, b.y);
810 	} else {
811 		fPath.line_to(b.x, a.y);
812 		fPath.line_to(b.x, b.y);
813 		fPath.line_to(a.x, b.y);
814 	}
815 	fPath.close_polygon();
816 
817 	return _StrokePath(fPath);
818 }
819 
820 
821 // StrokeRect
822 void
823 Painter::StrokeRect(const BRect& r, const rgb_color& c) const
824 {
825 	StraightLine(BPoint(r.left, r.top), BPoint(r.right - 1, r.top), c);
826 	StraightLine(BPoint(r.right, r.top), BPoint(r.right, r.bottom - 1), c);
827 	StraightLine(BPoint(r.right, r.bottom), BPoint(r.left + 1, r.bottom), c);
828 	StraightLine(BPoint(r.left, r.bottom), BPoint(r.left, r.top + 1), c);
829 }
830 
831 
832 // FillRect
833 BRect
834 Painter::FillRect(const BRect& r) const
835 {
836 	CHECK_CLIPPING
837 
838 	// support invalid rects
839 	BPoint a(min_c(r.left, r.right), min_c(r.top, r.bottom));
840 	BPoint b(max_c(r.left, r.right), max_c(r.top, r.bottom));
841 	_Transform(&a, false);
842 	_Transform(&b, false);
843 
844 	// first, try an optimized version
845 	if (fDrawingMode == B_OP_COPY || fDrawingMode == B_OP_OVER) {
846 		pattern p = *fPatternHandler.GetR5Pattern();
847 		if (p == B_SOLID_HIGH) {
848 			BRect rect(a, b);
849 			FillRect(rect, fPatternHandler.HighColor());
850 			return _Clipped(rect);
851 		} else if (p == B_SOLID_LOW) {
852 			BRect rect(a, b);
853 			FillRect(rect, fPatternHandler.LowColor());
854 			return _Clipped(rect);
855 		}
856 	}
857 	if (fDrawingMode == B_OP_ALPHA && fAlphaFncMode == B_ALPHA_OVERLAY) {
858 		pattern p = *fPatternHandler.GetR5Pattern();
859 		if (p == B_SOLID_HIGH) {
860 			BRect rect(a, b);
861 			_BlendRect32(rect, fPatternHandler.HighColor());
862 			return _Clipped(rect);
863 		} else if (p == B_SOLID_LOW) {
864 			rgb_color c = fPatternHandler.LowColor();
865 			if (fAlphaSrcMode == B_CONSTANT_ALPHA)
866 				c.alpha = fPatternHandler.HighColor().alpha;
867 			BRect rect(a, b);
868 			_BlendRect32(rect, c);
869 			return _Clipped(rect);
870 		}
871 	}
872 
873 	// account for stricter interpretation of coordinates in AGG
874 	// the rectangle ranges from the top-left (.0, .0)
875 	// to the bottom-right (.9999, .9999) corner of pixels
876 	b.x += 1.0;
877 	b.y += 1.0;
878 
879 	fPath.remove_all();
880 	fPath.move_to(a.x, a.y);
881 	fPath.line_to(b.x, a.y);
882 	fPath.line_to(b.x, b.y);
883 	fPath.line_to(a.x, b.y);
884 	fPath.close_polygon();
885 
886 	return _FillPath(fPath);
887 }
888 
889 
890 // FillRect
891 BRect
892 Painter::FillRect(const BRect& r, const BGradient& gradient) const
893 {
894 	CHECK_CLIPPING
895 
896 	// support invalid rects
897 	BPoint a(min_c(r.left, r.right), min_c(r.top, r.bottom));
898 	BPoint b(max_c(r.left, r.right), max_c(r.top, r.bottom));
899 	_Transform(&a, false);
900 	_Transform(&b, false);
901 
902 	// first, try an optimized version
903 	if (gradient.GetType() == BGradient::TYPE_LINEAR
904 		&& (fDrawingMode == B_OP_COPY || fDrawingMode == B_OP_OVER)) {
905 		const BGradientLinear* linearGradient
906 			= dynamic_cast<const BGradientLinear*>(&gradient);
907 		if (linearGradient->Start().x == linearGradient->End().x
908 			// TODO: Remove this second check once the optimized method
909 			// handled "upside down" gradients as well...
910 			&& linearGradient->Start().y <= linearGradient->End().y) {
911 			// a vertical gradient
912 			BRect rect(a, b);
913 			FillRectVerticalGradient(rect, *linearGradient);
914 			return _Clipped(rect);
915 		}
916 	}
917 
918 	// account for stricter interpretation of coordinates in AGG
919 	// the rectangle ranges from the top-left (.0, .0)
920 	// to the bottom-right (.9999, .9999) corner of pixels
921 	b.x += 1.0;
922 	b.y += 1.0;
923 
924 	fPath.remove_all();
925 	fPath.move_to(a.x, a.y);
926 	fPath.line_to(b.x, a.y);
927 	fPath.line_to(b.x, b.y);
928 	fPath.line_to(a.x, b.y);
929 	fPath.close_polygon();
930 
931 	return _FillPath(fPath, gradient);
932 }
933 
934 
935 // FillRect
936 void
937 Painter::FillRect(const BRect& r, const rgb_color& c) const
938 {
939 	if (!fValidClipping)
940 		return;
941 
942 	uint8* dst = fBuffer.row_ptr(0);
943 	uint32 bpr = fBuffer.stride();
944 	int32 left = (int32)r.left;
945 	int32 top = (int32)r.top;
946 	int32 right = (int32)r.right;
947 	int32 bottom = (int32)r.bottom;
948 	// get a 32 bit pixel ready with the color
949 	pixel32 color;
950 	color.data8[0] = c.blue;
951 	color.data8[1] = c.green;
952 	color.data8[2] = c.red;
953 	color.data8[3] = c.alpha;
954 	// fill rects, iterate over clipping boxes
955 	fBaseRenderer.first_clip_box();
956 	do {
957 		int32 x1 = max_c(fBaseRenderer.xmin(), left);
958 		int32 x2 = min_c(fBaseRenderer.xmax(), right);
959 		if (x1 <= x2) {
960 			int32 y1 = max_c(fBaseRenderer.ymin(), top);
961 			int32 y2 = min_c(fBaseRenderer.ymax(), bottom);
962 			uint8* offset = dst + x1 * 4;
963 			for (; y1 <= y2; y1++) {
964 //					uint32* handle = (uint32*)(offset + y1 * bpr);
965 //					for (int32 x = x1; x <= x2; x++) {
966 //						*handle++ = color.data32;
967 //					}
968 				gfxset32(offset + y1 * bpr, color.data32, (x2 - x1 + 1) * 4);
969 			}
970 		}
971 	} while (fBaseRenderer.next_clip_box());
972 }
973 
974 
975 // FillRectVerticalGradient
976 void
977 Painter::FillRectVerticalGradient(BRect r, const BGradientLinear& gradient) const
978 {
979 	if (!fValidClipping)
980 		return;
981 
982 	// Make sure the color array is no larger than the screen height.
983 	r = r & fClippingRegion->Frame();
984 
985 	int32 gradientArraySize = r.IntegerHeight() + 1;
986 	uint32 gradientArray[gradientArraySize];
987 	int32 gradientTop = (int32)gradient.Start().y;
988 	int32 gradientBottom = (int32)gradient.End().y;
989 	int32 colorCount = gradientBottom - gradientTop + 1;
990 	if (colorCount < 0) {
991 		// Gradient is upside down. That's currently not supported by this
992 		// method.
993 		return;
994 	}
995 
996 	_MakeGradient(gradient, colorCount, gradientArray,
997 		gradientTop - (int32)r.top, gradientArraySize);
998 
999 	uint8* dst = fBuffer.row_ptr(0);
1000 	uint32 bpr = fBuffer.stride();
1001 	int32 left = (int32)r.left;
1002 	int32 top = (int32)r.top;
1003 	int32 right = (int32)r.right;
1004 	int32 bottom = (int32)r.bottom;
1005 	// fill rects, iterate over clipping boxes
1006 	fBaseRenderer.first_clip_box();
1007 	do {
1008 		int32 x1 = max_c(fBaseRenderer.xmin(), left);
1009 		int32 x2 = min_c(fBaseRenderer.xmax(), right);
1010 		if (x1 <= x2) {
1011 			int32 y1 = max_c(fBaseRenderer.ymin(), top);
1012 			int32 y2 = min_c(fBaseRenderer.ymax(), bottom);
1013 			uint8* offset = dst + x1 * 4;
1014 			for (; y1 <= y2; y1++) {
1015 //					uint32* handle = (uint32*)(offset + y1 * bpr);
1016 //					for (int32 x = x1; x <= x2; x++) {
1017 //						*handle++ = gradientArray[y1 - top];
1018 //					}
1019 				gfxset32(offset + y1 * bpr, gradientArray[y1 - top],
1020 					(x2 - x1 + 1) * 4);
1021 			}
1022 		}
1023 	} while (fBaseRenderer.next_clip_box());
1024 }
1025 
1026 
1027 // FillRectNoClipping
1028 void
1029 Painter::FillRectNoClipping(const clipping_rect& r, const rgb_color& c) const
1030 {
1031 	int32 y = (int32)r.top;
1032 
1033 	uint8* dst = fBuffer.row_ptr(y) + r.left * 4;
1034 	uint32 bpr = fBuffer.stride();
1035 	int32 bytes = (r.right - r.left + 1) * 4;
1036 
1037 	// get a 32 bit pixel ready with the color
1038 	pixel32 color;
1039 	color.data8[0] = c.blue;
1040 	color.data8[1] = c.green;
1041 	color.data8[2] = c.red;
1042 	color.data8[3] = c.alpha;
1043 
1044 	for (; y <= r.bottom; y++) {
1045 //			uint32* handle = (uint32*)dst;
1046 //			for (int32 x = left; x <= right; x++) {
1047 //				*handle++ = color.data32;
1048 //			}
1049 		gfxset32(dst, color.data32, bytes);
1050 		dst += bpr;
1051 	}
1052 }
1053 
1054 
1055 // StrokeRoundRect
1056 BRect
1057 Painter::StrokeRoundRect(const BRect& r, float xRadius, float yRadius) const
1058 {
1059 	CHECK_CLIPPING
1060 
1061 	BPoint lt(r.left, r.top);
1062 	BPoint rb(r.right, r.bottom);
1063 	bool centerOffset = fPenSize == 1.0;
1064 	// TODO: use this when using _StrokePath()
1065 	// bool centerOffset = fmodf(fPenSize, 2.0) != 0.0;
1066 	_Transform(&lt, centerOffset);
1067 	_Transform(&rb, centerOffset);
1068 
1069 	if (fPenSize == 1.0) {
1070 		agg::rounded_rect rect;
1071 		rect.rect(lt.x, lt.y, rb.x, rb.y);
1072 		rect.radius(xRadius, yRadius);
1073 
1074 		return _StrokePath(rect);
1075 	}
1076 
1077 	// NOTE: This implementation might seem a little strange, but it makes
1078 	// stroked round rects look like on R5. A more correct way would be to
1079 	// use _StrokePath() as above (independent from fPenSize).
1080 	// The fact that the bounding box of the round rect is not enlarged
1081 	// by fPenSize/2 is actually on purpose, though one could argue it is
1082 	// unexpected.
1083 
1084 	// enclose the right and bottom edge
1085 	rb.x++;
1086 	rb.y++;
1087 
1088 	agg::rounded_rect outer;
1089 	outer.rect(lt.x, lt.y, rb.x, rb.y);
1090 	outer.radius(xRadius, yRadius);
1091 
1092 	if (gSubpixelAntialiasing) {
1093 		fSubpixRasterizer.reset();
1094 		fSubpixRasterizer.add_path(outer);
1095 
1096 		// don't add an inner hole if the "size is negative", this avoids
1097 		// some defects that can be observed on R5 and could be regarded
1098 		// as a bug.
1099 		if (2 * fPenSize < rb.x - lt.x && 2 * fPenSize < rb.y - lt.y) {
1100 			agg::rounded_rect inner;
1101 			inner.rect(lt.x + fPenSize, lt.y + fPenSize, rb.x - fPenSize,
1102 				rb.y - fPenSize);
1103 			inner.radius(max_c(0.0, xRadius - fPenSize),
1104 				max_c(0.0, yRadius - fPenSize));
1105 
1106 			fSubpixRasterizer.add_path(inner);
1107 		}
1108 
1109 		// make the inner rect work as a hole
1110 		fSubpixRasterizer.filling_rule(agg::fill_even_odd);
1111 
1112 		if (fPenSize > 2) {
1113 			agg::render_scanlines(fSubpixRasterizer, fSubpixPackedScanline,
1114 				fSubpixRenderer);
1115 		} else {
1116 			agg::render_scanlines(fSubpixRasterizer, fSubpixUnpackedScanline,
1117 				fSubpixRenderer);
1118 		}
1119 
1120 		fSubpixRasterizer.filling_rule(agg::fill_non_zero);
1121 	} else {
1122 		fRasterizer.reset();
1123 		fRasterizer.add_path(outer);
1124 
1125 		// don't add an inner hole if the "size is negative", this avoids
1126 		// some defects that can be observed on R5 and could be regarded as
1127 		// a bug.
1128 		if (2 * fPenSize < rb.x - lt.x && 2 * fPenSize < rb.y - lt.y) {
1129 			agg::rounded_rect inner;
1130 			inner.rect(lt.x + fPenSize, lt.y + fPenSize, rb.x - fPenSize,
1131 				rb.y - fPenSize);
1132 			inner.radius(max_c(0.0, xRadius - fPenSize),
1133 				max_c(0.0, yRadius - fPenSize));
1134 
1135 			fRasterizer.add_path(inner);
1136 		}
1137 
1138 		// make the inner rect work as a hole
1139 		fRasterizer.filling_rule(agg::fill_even_odd);
1140 
1141 		if (fPenSize > 2)
1142 			agg::render_scanlines(fRasterizer, fPackedScanline, fRenderer);
1143 		else
1144 			agg::render_scanlines(fRasterizer, fUnpackedScanline, fRenderer);
1145 
1146 		// reset to default
1147 		fRasterizer.filling_rule(agg::fill_non_zero);
1148 	}
1149 
1150 	return _Clipped(_BoundingBox(outer));
1151 }
1152 
1153 
1154 // FillRoundRect
1155 BRect
1156 Painter::FillRoundRect(const BRect& r, float xRadius, float yRadius) const
1157 {
1158 	CHECK_CLIPPING
1159 
1160 	BPoint lt(r.left, r.top);
1161 	BPoint rb(r.right, r.bottom);
1162 	_Transform(&lt, false);
1163 	_Transform(&rb, false);
1164 
1165 	// account for stricter interpretation of coordinates in AGG
1166 	// the rectangle ranges from the top-left (.0, .0)
1167 	// to the bottom-right (.9999, .9999) corner of pixels
1168 	rb.x += 1.0;
1169 	rb.y += 1.0;
1170 
1171 	agg::rounded_rect rect;
1172 	rect.rect(lt.x, lt.y, rb.x, rb.y);
1173 	rect.radius(xRadius, yRadius);
1174 
1175 	return _FillPath(rect);
1176 }
1177 
1178 
1179 // FillRoundRect
1180 BRect
1181 Painter::FillRoundRect(const BRect& r, float xRadius, float yRadius,
1182 	const BGradient& gradient) const
1183 {
1184 	CHECK_CLIPPING
1185 
1186 	BPoint lt(r.left, r.top);
1187 	BPoint rb(r.right, r.bottom);
1188 	_Transform(&lt, false);
1189 	_Transform(&rb, false);
1190 
1191 	// account for stricter interpretation of coordinates in AGG
1192 	// the rectangle ranges from the top-left (.0, .0)
1193 	// to the bottom-right (.9999, .9999) corner of pixels
1194 	rb.x += 1.0;
1195 	rb.y += 1.0;
1196 
1197 	agg::rounded_rect rect;
1198 	rect.rect(lt.x, lt.y, rb.x, rb.y);
1199 	rect.radius(xRadius, yRadius);
1200 
1201 	return _FillPath(rect, gradient);
1202 }
1203 
1204 
1205 // AlignEllipseRect
1206 void
1207 Painter::AlignEllipseRect(BRect* rect, bool filled) const
1208 {
1209 	if (!fSubpixelPrecise) {
1210 		// align rect to pixels
1211 		align_rect_to_pixels(rect);
1212 		// account for "pixel index" versus "pixel area"
1213 		rect->right++;
1214 		rect->bottom++;
1215 		if (!filled && fmodf(fPenSize, 2.0) != 0.0) {
1216 			// align the stroke
1217 			rect->InsetBy(0.5, 0.5);
1218 		}
1219 	}
1220 }
1221 
1222 
1223 // DrawEllipse
1224 BRect
1225 Painter::DrawEllipse(BRect r, bool fill) const
1226 {
1227 	CHECK_CLIPPING
1228 
1229 	AlignEllipseRect(&r, fill);
1230 
1231 	float xRadius = r.Width() / 2.0;
1232 	float yRadius = r.Height() / 2.0;
1233 	BPoint center(r.left + xRadius, r.top + yRadius);
1234 
1235 	int32 divisions = (int32)((xRadius + yRadius + 2 * fPenSize) * M_PI / 2);
1236 	if (divisions < 12)
1237 		divisions = 12;
1238 	if (divisions > 4096)
1239 		divisions = 4096;
1240 
1241 	if (fill) {
1242 		agg::ellipse path(center.x, center.y, xRadius, yRadius, divisions);
1243 
1244 		return _FillPath(path);
1245 	}
1246 
1247 	// NOTE: This implementation might seem a little strange, but it makes
1248 	// stroked ellipses look like on R5. A more correct way would be to use
1249 	// _StrokePath(), but it currently has its own set of problems with
1250 	// narrow ellipses (for small xRadii or yRadii).
1251 	float inset = fPenSize / 2.0;
1252 	agg::ellipse inner(center.x, center.y, max_c(0.0, xRadius - inset),
1253 		max_c(0.0, yRadius - inset), divisions);
1254 	agg::ellipse outer(center.x, center.y, xRadius + inset, yRadius + inset,
1255 		divisions);
1256 
1257 	if (gSubpixelAntialiasing) {
1258 		fSubpixRasterizer.reset();
1259 		fSubpixRasterizer.add_path(outer);
1260 		fSubpixRasterizer.add_path(inner);
1261 
1262 		// make the inner ellipse work as a hole
1263 		fSubpixRasterizer.filling_rule(agg::fill_even_odd);
1264 
1265 		if (fPenSize > 4) {
1266 			agg::render_scanlines(fSubpixRasterizer, fSubpixPackedScanline,
1267 				fSubpixRenderer);
1268 		} else {
1269 			agg::render_scanlines(fSubpixRasterizer, fSubpixUnpackedScanline,
1270 				fSubpixRenderer);
1271 		}
1272 
1273 		// reset to default
1274 		fSubpixRasterizer.filling_rule(agg::fill_non_zero);
1275 	} else {
1276 		fRasterizer.reset();
1277 		fRasterizer.add_path(outer);
1278 		fRasterizer.add_path(inner);
1279 
1280 		// make the inner ellipse work as a hole
1281 		fRasterizer.filling_rule(agg::fill_even_odd);
1282 
1283 		if (fPenSize > 4)
1284 			agg::render_scanlines(fRasterizer, fPackedScanline, fRenderer);
1285 		else
1286 			agg::render_scanlines(fRasterizer, fUnpackedScanline, fRenderer);
1287 
1288 		// reset to default
1289 		fRasterizer.filling_rule(agg::fill_non_zero);
1290 	}
1291 
1292 	return _Clipped(_BoundingBox(outer));
1293 }
1294 
1295 
1296 // FillEllipse
1297 BRect
1298 Painter::FillEllipse(BRect r, const BGradient& gradient) const
1299 {
1300 	CHECK_CLIPPING
1301 
1302 	AlignEllipseRect(&r, true);
1303 
1304 	float xRadius = r.Width() / 2.0;
1305 	float yRadius = r.Height() / 2.0;
1306 	BPoint center(r.left + xRadius, r.top + yRadius);
1307 
1308 	int32 divisions = (int32)((xRadius + yRadius + 2 * fPenSize) * M_PI / 2);
1309 	if (divisions < 12)
1310 		divisions = 12;
1311 	if (divisions > 4096)
1312 		divisions = 4096;
1313 
1314 	agg::ellipse path(center.x, center.y, xRadius, yRadius, divisions);
1315 
1316 	return _FillPath(path, gradient);
1317 }
1318 
1319 
1320 // StrokeArc
1321 BRect
1322 Painter::StrokeArc(BPoint center, float xRadius, float yRadius, float angle,
1323 	float span) const
1324 {
1325 	CHECK_CLIPPING
1326 
1327 	_Transform(&center);
1328 
1329 	double angleRad = (angle * M_PI) / 180.0;
1330 	double spanRad = (span * M_PI) / 180.0;
1331 	agg::bezier_arc arc(center.x, center.y, xRadius, yRadius, -angleRad,
1332 		-spanRad);
1333 
1334 	agg::conv_curve<agg::bezier_arc> path(arc);
1335 	path.approximation_scale(2.0);
1336 
1337 	return _StrokePath(path);
1338 }
1339 
1340 
1341 // FillArc
1342 BRect
1343 Painter::FillArc(BPoint center, float xRadius, float yRadius, float angle,
1344 	float span) const
1345 {
1346 	CHECK_CLIPPING
1347 
1348 	_Transform(&center);
1349 
1350 	double angleRad = (angle * M_PI) / 180.0;
1351 	double spanRad = (span * M_PI) / 180.0;
1352 	agg::bezier_arc arc(center.x, center.y, xRadius, yRadius, -angleRad,
1353 		-spanRad);
1354 
1355 	agg::conv_curve<agg::bezier_arc> segmentedArc(arc);
1356 
1357 	fPath.remove_all();
1358 
1359 	// build a new path by starting at the center point,
1360 	// then traversing the arc, then going back to the center
1361 	fPath.move_to(center.x, center.y);
1362 
1363 	segmentedArc.rewind(0);
1364 	double x;
1365 	double y;
1366 	unsigned cmd = segmentedArc.vertex(&x, &y);
1367 	while (!agg::is_stop(cmd)) {
1368 		fPath.line_to(x, y);
1369 		cmd = segmentedArc.vertex(&x, &y);
1370 	}
1371 
1372 	fPath.close_polygon();
1373 
1374 	return _FillPath(fPath);
1375 }
1376 
1377 
1378 // FillArc
1379 BRect
1380 Painter::FillArc(BPoint center, float xRadius, float yRadius, float angle,
1381 	float span, const BGradient& gradient) const
1382 {
1383 	CHECK_CLIPPING
1384 
1385 	_Transform(&center);
1386 
1387 	double angleRad = (angle * M_PI) / 180.0;
1388 	double spanRad = (span * M_PI) / 180.0;
1389 	agg::bezier_arc arc(center.x, center.y, xRadius, yRadius, -angleRad,
1390 		-spanRad);
1391 
1392 	agg::conv_curve<agg::bezier_arc> segmentedArc(arc);
1393 
1394 	fPath.remove_all();
1395 
1396 	// build a new path by starting at the center point,
1397 	// then traversing the arc, then going back to the center
1398 	fPath.move_to(center.x, center.y);
1399 
1400 	segmentedArc.rewind(0);
1401 	double x;
1402 	double y;
1403 	unsigned cmd = segmentedArc.vertex(&x, &y);
1404 	while (!agg::is_stop(cmd)) {
1405 		fPath.line_to(x, y);
1406 		cmd = segmentedArc.vertex(&x, &y);
1407 	}
1408 
1409 	fPath.close_polygon();
1410 
1411 	return _FillPath(fPath, gradient);
1412 }
1413 
1414 
1415 // #pragma mark -
1416 
1417 
1418 // DrawString
1419 BRect
1420 Painter::DrawString(const char* utf8String, uint32 length, BPoint baseLine,
1421 	const escapement_delta* delta, FontCacheReference* cacheReference)
1422 {
1423 	CHECK_CLIPPING
1424 
1425 	if (!fSubpixelPrecise) {
1426 		baseLine.x = roundf(baseLine.x);
1427 		baseLine.y = roundf(baseLine.y);
1428 	}
1429 
1430 	BRect bounds;
1431 
1432 	// text is not rendered with patterns, but we need to
1433 	// make sure that the previous pattern is restored
1434 	pattern oldPattern = *fPatternHandler.GetR5Pattern();
1435 	SetPattern(B_SOLID_HIGH, true);
1436 
1437 	bounds = fTextRenderer.RenderString(utf8String, length,
1438 		baseLine, fClippingRegion->Frame(), false, NULL, delta,
1439 		cacheReference);
1440 
1441 	SetPattern(oldPattern);
1442 
1443 	return _Clipped(bounds);
1444 }
1445 
1446 
1447 // DrawString
1448 BRect
1449 Painter::DrawString(const char* utf8String, uint32 length,
1450 	const BPoint* offsets, FontCacheReference* cacheReference)
1451 {
1452 	CHECK_CLIPPING
1453 
1454 	// TODO: Round offsets to device pixel grid if !fSubpixelPrecise?
1455 
1456 	BRect bounds;
1457 
1458 	// text is not rendered with patterns, but we need to
1459 	// make sure that the previous pattern is restored
1460 	pattern oldPattern = *fPatternHandler.GetR5Pattern();
1461 	SetPattern(B_SOLID_HIGH, true);
1462 
1463 	bounds = fTextRenderer.RenderString(utf8String, length,
1464 		offsets, fClippingRegion->Frame(), false, NULL,
1465 		cacheReference);
1466 
1467 	SetPattern(oldPattern);
1468 
1469 	return _Clipped(bounds);
1470 }
1471 
1472 
1473 // BoundingBox
1474 BRect
1475 Painter::BoundingBox(const char* utf8String, uint32 length, BPoint baseLine,
1476 	BPoint* penLocation, const escapement_delta* delta,
1477 	FontCacheReference* cacheReference) const
1478 {
1479 	if (!fSubpixelPrecise) {
1480 		baseLine.x = roundf(baseLine.x);
1481 		baseLine.y = roundf(baseLine.y);
1482 	}
1483 
1484 	static BRect dummy;
1485 	return fTextRenderer.RenderString(utf8String, length,
1486 		baseLine, dummy, true, penLocation, delta, cacheReference);
1487 }
1488 
1489 
1490 // BoundingBox
1491 BRect
1492 Painter::BoundingBox(const char* utf8String, uint32 length,
1493 	const BPoint* offsets, BPoint* penLocation,
1494 	FontCacheReference* cacheReference) const
1495 {
1496 	// TODO: Round offsets to device pixel grid if !fSubpixelPrecise?
1497 
1498 	static BRect dummy;
1499 	return fTextRenderer.RenderString(utf8String, length,
1500 		offsets, dummy, true, penLocation, cacheReference);
1501 }
1502 
1503 
1504 // StringWidth
1505 float
1506 Painter::StringWidth(const char* utf8String, uint32 length,
1507 	const escapement_delta* delta)
1508 {
1509 	return Font().StringWidth(utf8String, length, delta);
1510 }
1511 
1512 
1513 // #pragma mark -
1514 
1515 
1516 // DrawBitmap
1517 BRect
1518 Painter::DrawBitmap(const ServerBitmap* bitmap, BRect bitmapRect,
1519 	BRect viewRect, uint32 options) const
1520 {
1521 	CHECK_CLIPPING
1522 
1523 	BRect touched = _Clipped(viewRect);
1524 
1525 	if (bitmap && bitmap->IsValid() && touched.IsValid()) {
1526 		// the native bitmap coordinate system
1527 		BRect actualBitmapRect(bitmap->Bounds());
1528 
1529 		TRACE("Painter::DrawBitmap()\n");
1530 		TRACE("   actualBitmapRect = (%.1f, %.1f) - (%.1f, %.1f)\n",
1531 			actualBitmapRect.left, actualBitmapRect.top,
1532 			actualBitmapRect.right, actualBitmapRect.bottom);
1533 		TRACE("   bitmapRect = (%.1f, %.1f) - (%.1f, %.1f)\n",
1534 			bitmapRect.left, bitmapRect.top, bitmapRect.right,
1535 			bitmapRect.bottom);
1536 		TRACE("   viewRect = (%.1f, %.1f) - (%.1f, %.1f)\n",
1537 			viewRect.left, viewRect.top, viewRect.right, viewRect.bottom);
1538 
1539 		agg::rendering_buffer srcBuffer;
1540 		srcBuffer.attach(bitmap->Bits(), bitmap->Width(), bitmap->Height(),
1541 			bitmap->BytesPerRow());
1542 
1543 		_DrawBitmap(srcBuffer, bitmap->ColorSpace(), actualBitmapRect,
1544 			bitmapRect, viewRect, options);
1545 	}
1546 	return touched;
1547 }
1548 
1549 
1550 // #pragma mark -
1551 
1552 
1553 // FillRegion
1554 BRect
1555 Painter::FillRegion(const BRegion* region) const
1556 {
1557 	CHECK_CLIPPING
1558 
1559 	BRegion copy(*region);
1560 	int32 count = copy.CountRects();
1561 	BRect touched = FillRect(copy.RectAt(0));
1562 	for (int32 i = 1; i < count; i++) {
1563 		touched = touched | FillRect(copy.RectAt(i));
1564 	}
1565 	return touched;
1566 }
1567 
1568 
1569 // FillRegion
1570 BRect
1571 Painter::FillRegion(const BRegion* region, const BGradient& gradient) const
1572 {
1573 	CHECK_CLIPPING
1574 
1575 	BRegion copy(*region);
1576 	int32 count = copy.CountRects();
1577 	BRect touched = FillRect(copy.RectAt(0), gradient);
1578 	for (int32 i = 1; i < count; i++) {
1579 		touched = touched | FillRect(copy.RectAt(i), gradient);
1580 	}
1581 	return touched;
1582 }
1583 
1584 
1585 // InvertRect
1586 BRect
1587 Painter::InvertRect(const BRect& r) const
1588 {
1589 	CHECK_CLIPPING
1590 
1591 	BRegion region(r);
1592 	if (fClippingRegion)
1593 		region.IntersectWith(fClippingRegion);
1594 
1595 	// implementation only for B_RGB32 at the moment
1596 	int32 count = region.CountRects();
1597 	for (int32 i = 0; i < count; i++) {
1598 		_InvertRect32(region.RectAt(i));
1599 	}
1600 	return _Clipped(r);
1601 }
1602 
1603 
1604 // #pragma mark - private
1605 
1606 
1607 // _Transform
1608 inline void
1609 Painter::_Transform(BPoint* point, bool centerOffset) const
1610 {
1611 	// rounding
1612 	if (!fSubpixelPrecise) {
1613 		// TODO: validate usage of floor() for values < 0
1614 		point->x = (int32)point->x;
1615 		point->y = (int32)point->y;
1616 	}
1617 	// this code is supposed to move coordinates to the center of pixels,
1618 	// as AGG considers (0,0) to be the "upper left corner" of a pixel,
1619 	// but BViews are less strict on those details
1620 	if (centerOffset) {
1621 		point->x += 0.5;
1622 		point->y += 0.5;
1623 	}
1624 }
1625 
1626 
1627 // _Transform
1628 inline BPoint
1629 Painter::_Transform(const BPoint& point, bool centerOffset) const
1630 {
1631 	BPoint ret = point;
1632 	_Transform(&ret, centerOffset);
1633 	return ret;
1634 }
1635 
1636 
1637 // _Clipped
1638 BRect
1639 Painter::_Clipped(const BRect& rect) const
1640 {
1641 	if (rect.IsValid())
1642 		return BRect(rect & fClippingRegion->Frame());
1643 
1644 	return BRect(rect);
1645 }
1646 
1647 
1648 // _UpdateDrawingMode
1649 void
1650 Painter::_UpdateDrawingMode(bool drawingText)
1651 {
1652 	// The AGG renderers have their own color setting, however
1653 	// almost all drawing mode classes ignore the color given
1654 	// by the AGG renderer and use the colors from the PatternHandler
1655 	// instead. If we have a B_SOLID_* pattern, we can actually use
1656 	// the color in the renderer and special versions of drawing modes
1657 	// that don't use PatternHandler and are more efficient. This
1658 	// has been implemented for B_OP_COPY and a couple others (the
1659 	// DrawingMode*Solid ones) as of now. The PixelFormat knows the
1660 	// PatternHandler and makes its decision based on the pattern.
1661 	// The last parameter to SetDrawingMode() is a special flag
1662 	// for when Painter is used to draw text. In this case, another
1663 	// special version of B_OP_COPY is used that acts like R5 in that
1664 	// anti-aliased pixel are not rendered against the actual background
1665 	// but the current low color instead. This way, the frame buffer
1666 	// doesn't need to be read.
1667 	// When a solid pattern is used, _SetRendererColor()
1668 	// has to be called so that all internal colors in the renderes
1669 	// are up to date for use by the solid drawing mode version.
1670 	fPixelFormat.SetDrawingMode(fDrawingMode, fAlphaSrcMode, fAlphaFncMode,
1671 		drawingText);
1672 	if (drawingText)
1673 		fPatternHandler.MakeOpCopyColorCache();
1674 }
1675 
1676 
1677 // _SetRendererColor
1678 void
1679 Painter::_SetRendererColor(const rgb_color& color) const
1680 {
1681 	fRenderer.color(agg::rgba(color.red / 255.0, color.green / 255.0,
1682 		color.blue / 255.0, color.alpha / 255.0));
1683 	fSubpixRenderer.color(agg::rgba(color.red / 255.0, color.green / 255.0,
1684 		color.blue / 255.0, color.alpha / 255.0));
1685 // TODO: bitmap fonts not yet correctly setup in AGGTextRenderer
1686 //	fRendererBin.color(agg::rgba(color.red / 255.0, color.green / 255.0,
1687 //		color.blue / 255.0, color.alpha / 255.0));
1688 }
1689 
1690 
1691 // #pragma mark -
1692 
1693 
1694 // _DrawTriangle
1695 inline BRect
1696 Painter::_DrawTriangle(BPoint pt1, BPoint pt2, BPoint pt3, bool fill) const
1697 {
1698 	CHECK_CLIPPING
1699 
1700 	_Transform(&pt1);
1701 	_Transform(&pt2);
1702 	_Transform(&pt3);
1703 
1704 	fPath.remove_all();
1705 
1706 	fPath.move_to(pt1.x, pt1.y);
1707 	fPath.line_to(pt2.x, pt2.y);
1708 	fPath.line_to(pt3.x, pt3.y);
1709 
1710 	fPath.close_polygon();
1711 
1712 	if (fill)
1713 		return _FillPath(fPath);
1714 
1715 	return _StrokePath(fPath);
1716 }
1717 
1718 
1719 // copy_bitmap_row_cmap8_copy
1720 static inline void
1721 copy_bitmap_row_cmap8_copy(uint8* dst, const uint8* src, int32 numPixels,
1722 	const rgb_color* colorMap)
1723 {
1724 	uint32* d = (uint32*)dst;
1725 	const uint8* s = src;
1726 	while (numPixels--) {
1727 		const rgb_color c = colorMap[*s++];
1728 		*d++ = (c.alpha << 24) | (c.red << 16) | (c.green << 8) | (c.blue);
1729 	}
1730 }
1731 
1732 
1733 // copy_bitmap_row_cmap8_over
1734 static inline void
1735 copy_bitmap_row_cmap8_over(uint8* dst, const uint8* src, int32 numPixels,
1736 	const rgb_color* colorMap)
1737 {
1738 	uint32* d = (uint32*)dst;
1739 	const uint8* s = src;
1740 	while (numPixels--) {
1741 		const rgb_color c = colorMap[*s++];
1742 		if (c.alpha)
1743 			*d = (c.alpha << 24) | (c.red << 16) | (c.green << 8) | (c.blue);
1744 		d++;
1745 	}
1746 }
1747 
1748 
1749 // copy_bitmap_row_bgr32_copy
1750 static inline void
1751 copy_bitmap_row_bgr32_copy(uint8* dst, const uint8* src, int32 numPixels,
1752 	const rgb_color* colorMap)
1753 {
1754 	memcpy(dst, src, numPixels * 4);
1755 }
1756 
1757 
1758 // copy_bitmap_row_bgr32_over
1759 static inline void
1760 copy_bitmap_row_bgr32_over(uint8* dst, const uint8* src, int32 numPixels,
1761 	const rgb_color* colorMap)
1762 {
1763 	uint32* d = (uint32*)dst;
1764 	uint32* s = (uint32*)src;
1765 	while (numPixels--) {
1766 		if (*s != B_TRANSPARENT_MAGIC_RGBA32)
1767 			*(uint32*)d = *(uint32*)s;
1768 		d++;
1769 		s++;
1770 	}
1771 }
1772 
1773 
1774 // copy_bitmap_row_bgr32_alpha
1775 static inline void
1776 copy_bitmap_row_bgr32_alpha(uint8* dst, const uint8* src, int32 numPixels,
1777 	const rgb_color* colorMap)
1778 {
1779 	uint32* d = (uint32*)dst;
1780 	int32 bytes = numPixels * 4;
1781 	uint8 buffer[bytes];
1782 	uint8* b = buffer;
1783 	while (numPixels--) {
1784 		if (src[3] == 255) {
1785 			*(uint32*)b = *(uint32*)src;
1786 		} else {
1787 			*(uint32*)b = *d;
1788 			b[0] = ((src[0] - b[0]) * src[3] + (b[0] << 8)) >> 8;
1789 			b[1] = ((src[1] - b[1]) * src[3] + (b[1] << 8)) >> 8;
1790 			b[2] = ((src[2] - b[2]) * src[3] + (b[2] << 8)) >> 8;
1791 		}
1792 		d++;
1793 		b += 4;
1794 		src += 4;
1795 	}
1796 	memcpy(dst, buffer, bytes);
1797 }
1798 
1799 
1800 // _TransparentMagicToAlpha
1801 template<typename sourcePixel>
1802 void
1803 Painter::_TransparentMagicToAlpha(sourcePixel* buffer, uint32 width,
1804 	uint32 height, uint32 sourceBytesPerRow, sourcePixel transparentMagic,
1805 	BBitmap* output) const
1806 {
1807 	uint8* sourceRow = (uint8*)buffer;
1808 	uint8* destRow = (uint8*)output->Bits();
1809 	uint32 destBytesPerRow = output->BytesPerRow();
1810 
1811 	for (uint32 y = 0; y < height; y++) {
1812 		sourcePixel* pixel = (sourcePixel*)sourceRow;
1813 		uint32* destPixel = (uint32*)destRow;
1814 		for (uint32 x = 0; x < width; x++, pixel++, destPixel++) {
1815 			if (*pixel == transparentMagic)
1816 				*destPixel &= 0x00ffffff;
1817 		}
1818 
1819 		sourceRow += sourceBytesPerRow;
1820 		destRow += destBytesPerRow;
1821 	}
1822 }
1823 
1824 
1825 // _DrawBitmap
1826 void
1827 Painter::_DrawBitmap(agg::rendering_buffer& srcBuffer, color_space format,
1828 	BRect actualBitmapRect, BRect bitmapRect, BRect viewRect,
1829 	uint32 options) const
1830 {
1831 	if (!fValidClipping
1832 		|| !bitmapRect.IsValid() || !bitmapRect.Intersects(actualBitmapRect)
1833 		|| !viewRect.IsValid()) {
1834 		return;
1835 	}
1836 
1837 	if (!fSubpixelPrecise) {
1838 		align_rect_to_pixels(&bitmapRect);
1839 		align_rect_to_pixels(&viewRect);
1840 	}
1841 
1842 	TRACE("Painter::_DrawBitmap()\n");
1843 	TRACE("   bitmapRect = (%.1f, %.1f) - (%.1f, %.1f)\n",
1844 		bitmapRect.left, bitmapRect.top, bitmapRect.right, bitmapRect.bottom);
1845 	TRACE("   viewRect = (%.1f, %.1f) - (%.1f, %.1f)\n",
1846 		viewRect.left, viewRect.top, viewRect.right, viewRect.bottom);
1847 
1848 	double xScale = (viewRect.Width() + 1) / (bitmapRect.Width() + 1);
1849 	double yScale = (viewRect.Height() + 1) / (bitmapRect.Height() + 1);
1850 
1851 	if (xScale == 0.0 || yScale == 0.0)
1852 		return;
1853 
1854 	// compensate for the lefttop offset the actualBitmapRect might have
1855 	// actualBitmapRect has the right size, but put it at B_ORIGIN
1856 	// bitmapRect is already in good coordinates
1857 	actualBitmapRect.OffsetBy(-actualBitmapRect.left, -actualBitmapRect.top);
1858 
1859 	// constrain rect to passed bitmap bounds
1860 	// and transfer the changes to the viewRect with the right scale
1861 	if (bitmapRect.left < actualBitmapRect.left) {
1862 		float diff = actualBitmapRect.left - bitmapRect.left;
1863 		viewRect.left += diff * xScale;
1864 		bitmapRect.left = actualBitmapRect.left;
1865 	}
1866 	if (bitmapRect.top < actualBitmapRect.top) {
1867 		float diff = actualBitmapRect.top - bitmapRect.top;
1868 		viewRect.top += diff * yScale;
1869 		bitmapRect.top = actualBitmapRect.top;
1870 	}
1871 	if (bitmapRect.right > actualBitmapRect.right) {
1872 		float diff = bitmapRect.right - actualBitmapRect.right;
1873 		viewRect.right -= diff * xScale;
1874 		bitmapRect.right = actualBitmapRect.right;
1875 	}
1876 	if (bitmapRect.bottom > actualBitmapRect.bottom) {
1877 		float diff = bitmapRect.bottom - actualBitmapRect.bottom;
1878 		viewRect.bottom -= diff * yScale;
1879 		bitmapRect.bottom = actualBitmapRect.bottom;
1880 	}
1881 
1882 	double xOffset = viewRect.left - bitmapRect.left;
1883 	double yOffset = viewRect.top - bitmapRect.top;
1884 
1885 	// optimized code path for B_CMAP8 and no scale
1886 	if (xScale == 1.0 && yScale == 1.0) {
1887 		if (format == B_CMAP8) {
1888 			if (fDrawingMode == B_OP_COPY) {
1889 				_DrawBitmapNoScale32(copy_bitmap_row_cmap8_copy, 1,
1890 					srcBuffer, (int32)xOffset, (int32)yOffset, viewRect);
1891 				return;
1892 			}
1893 			if (fDrawingMode == B_OP_OVER) {
1894 				_DrawBitmapNoScale32(copy_bitmap_row_cmap8_over, 1,
1895 					srcBuffer, (int32)xOffset, (int32)yOffset, viewRect);
1896 				return;
1897 			}
1898 		} else if (format == B_RGB32) {
1899 			if (fDrawingMode == B_OP_OVER) {
1900 				_DrawBitmapNoScale32(copy_bitmap_row_bgr32_over, 4,
1901 					srcBuffer, (int32)xOffset, (int32)yOffset, viewRect);
1902 				return;
1903 			}
1904 		}
1905 	}
1906 
1907 	BBitmap* temp = NULL;
1908 	ObjectDeleter<BBitmap> tempDeleter;
1909 
1910 	if ((format != B_RGBA32 && format != B_RGB32)
1911 		|| (format == B_RGB32 && fDrawingMode != B_OP_COPY
1912 #if 1
1913 // Enabling this would make the behavior compatible to BeOS, which
1914 // treats B_RGB32 bitmaps as B_RGB*A*32 bitmaps in B_OP_ALPHA - unlike in
1915 // all other drawing modes, where B_TRANSPARENT_MAGIC_RGBA32 is handled.
1916 // B_RGB32 bitmaps therefore don't draw correctly on BeOS if they actually
1917 // use this color, unless the alpha channel contains 255 for all other
1918 // pixels, which is inconsistent.
1919 			&& fDrawingMode != B_OP_ALPHA
1920 #endif
1921 		)) {
1922 		temp = new (nothrow) BBitmap(actualBitmapRect, B_BITMAP_NO_SERVER_LINK,
1923 			B_RGBA32);
1924 		if (temp == NULL) {
1925 			fprintf(stderr, "Painter::_DrawBitmap() - "
1926 				"out of memory for creating temporary conversion bitmap\n");
1927 			return;
1928 		}
1929 
1930 		tempDeleter.SetTo(temp);
1931 
1932 		status_t err = temp->ImportBits(srcBuffer.buf(),
1933 			srcBuffer.height() * srcBuffer.stride(),
1934 			srcBuffer.stride(), 0, format);
1935 		if (err < B_OK) {
1936 			fprintf(stderr, "Painter::_DrawBitmap() - "
1937 				"colorspace conversion failed: %s\n", strerror(err));
1938 			return;
1939 		}
1940 
1941 		// the original bitmap might have had some of the
1942 		// transaparent magic colors set that we now need to
1943 		// make transparent in our RGBA32 bitmap again.
1944 		switch (format) {
1945 			case B_RGB32:
1946 				_TransparentMagicToAlpha((uint32 *)srcBuffer.buf(),
1947 					srcBuffer.width(), srcBuffer.height(),
1948 					srcBuffer.stride(), B_TRANSPARENT_MAGIC_RGBA32,
1949 					temp);
1950 				break;
1951 
1952 			// TODO: not sure if this applies to B_RGBA15 too. It
1953 			// should not because B_RGBA15 actually has an alpha
1954 			// channel itself and it should have been preserved
1955 			// when importing the bitmap. Maybe it applies to
1956 			// B_RGB16 though?
1957 			case B_RGB15:
1958 				_TransparentMagicToAlpha((uint16 *)srcBuffer.buf(),
1959 					srcBuffer.width(), srcBuffer.height(),
1960 					srcBuffer.stride(), B_TRANSPARENT_MAGIC_RGBA15,
1961 					temp);
1962 				break;
1963 
1964 			default:
1965 				break;
1966 		}
1967 
1968 		srcBuffer.attach((uint8*)temp->Bits(),
1969 			(uint32)actualBitmapRect.IntegerWidth() + 1,
1970 			(uint32)actualBitmapRect.IntegerHeight() + 1,
1971 			temp->BytesPerRow());
1972 	}
1973 
1974 	// maybe we can use an optimized version if there is no scale
1975 	if (xScale == 1.0 && yScale == 1.0) {
1976 		if (fDrawingMode == B_OP_COPY) {
1977 			_DrawBitmapNoScale32(copy_bitmap_row_bgr32_copy, 4, srcBuffer,
1978 				(int32)xOffset, (int32)yOffset, viewRect);
1979 			return;
1980 		}
1981 		if (fDrawingMode == B_OP_OVER || (fDrawingMode == B_OP_ALPHA
1982 				 && fAlphaSrcMode == B_PIXEL_ALPHA
1983 				 && fAlphaFncMode == B_ALPHA_OVERLAY)) {
1984 			_DrawBitmapNoScale32(copy_bitmap_row_bgr32_alpha, 4, srcBuffer,
1985 				(int32)xOffset, (int32)yOffset, viewRect);
1986 			return;
1987 		}
1988 	}
1989 
1990 	if (fDrawingMode == B_OP_COPY) {
1991 		if ((options & B_FILTER_BITMAP_BILINEAR) != 0) {
1992 			_DrawBitmapBilinearCopy32(srcBuffer, xOffset, yOffset, xScale,
1993 				yScale, viewRect);
1994 		} else {
1995 			_DrawBitmapNearestNeighborCopy32(srcBuffer, xOffset, yOffset,
1996 				xScale, yScale, viewRect);
1997 		}
1998 		return;
1999 	}
2000 
2001 	// for all other cases (non-optimized drawing mode or scaled drawing)
2002 	_DrawBitmapGeneric32(srcBuffer, xOffset, yOffset, xScale, yScale, viewRect,
2003 		options);
2004 }
2005 
2006 
2007 #define DEBUG_DRAW_BITMAP 0
2008 
2009 
2010 // _DrawBitmapNoScale32
2011 template <class F>
2012 void
2013 Painter::_DrawBitmapNoScale32(F copyRowFunction, uint32 bytesPerSourcePixel,
2014 	agg::rendering_buffer& srcBuffer, int32 xOffset, int32 yOffset,
2015 	BRect viewRect) const
2016 {
2017 	// NOTE: this would crash if viewRect was large enough to read outside the
2018 	// bitmap, so make sure this is not the case before calling this function!
2019 	uint8* dst = fBuffer.row_ptr(0);
2020 	uint32 dstBPR = fBuffer.stride();
2021 
2022 	const uint8* src = srcBuffer.row_ptr(0);
2023 	uint32 srcBPR = srcBuffer.stride();
2024 
2025 	int32 left = (int32)viewRect.left;
2026 	int32 top = (int32)viewRect.top;
2027 	int32 right = (int32)viewRect.right;
2028 	int32 bottom = (int32)viewRect.bottom;
2029 
2030 #if DEBUG_DRAW_BITMAP
2031 if (left - xOffset < 0 || left - xOffset >= (int32)srcBuffer.width() ||
2032 	right - xOffset >= (int32)srcBuffer.width() ||
2033 	top - yOffset < 0 || top - yOffset >= (int32)srcBuffer.height() ||
2034 	bottom - yOffset >= (int32)srcBuffer.height()) {
2035 
2036 	char message[256];
2037 	sprintf(message, "reading outside of bitmap (%ld, %ld, %ld, %ld) "
2038 			"(%d, %d) (%ld, %ld)",
2039 		left - xOffset, top - yOffset, right - xOffset, bottom - yOffset,
2040 		srcBuffer.width(), srcBuffer.height(), xOffset, yOffset);
2041 	debugger(message);
2042 }
2043 #endif
2044 
2045 	const rgb_color* colorMap = SystemPalette();
2046 
2047 	// copy rects, iterate over clipping boxes
2048 	fBaseRenderer.first_clip_box();
2049 	do {
2050 		int32 x1 = max_c(fBaseRenderer.xmin(), left);
2051 		int32 x2 = min_c(fBaseRenderer.xmax(), right);
2052 		if (x1 <= x2) {
2053 			int32 y1 = max_c(fBaseRenderer.ymin(), top);
2054 			int32 y2 = min_c(fBaseRenderer.ymax(), bottom);
2055 			if (y1 <= y2) {
2056 				uint8* dstHandle = dst + y1 * dstBPR + x1 * 4;
2057 				const uint8* srcHandle = src + (y1 - yOffset) * srcBPR
2058 					+ (x1 - xOffset) * bytesPerSourcePixel;
2059 
2060 				for (; y1 <= y2; y1++) {
2061 					copyRowFunction(dstHandle, srcHandle, x2 - x1 + 1, colorMap);
2062 
2063 					dstHandle += dstBPR;
2064 					srcHandle += srcBPR;
2065 				}
2066 			}
2067 		}
2068 	} while (fBaseRenderer.next_clip_box());
2069 }
2070 
2071 
2072 // _DrawBitmapNearestNeighborCopy32
2073 void
2074 Painter::_DrawBitmapNearestNeighborCopy32(agg::rendering_buffer& srcBuffer,
2075 	double xOffset, double yOffset, double xScale, double yScale,
2076 	BRect viewRect) const
2077 {
2078 	//bigtime_t now = system_time();
2079 	uint32 dstWidth = viewRect.IntegerWidth() + 1;
2080 	uint32 dstHeight = viewRect.IntegerHeight() + 1;
2081 	uint32 srcWidth = srcBuffer.width();
2082 	uint32 srcHeight = srcBuffer.height();
2083 
2084 	// Do not calculate more filter weights than necessary and also
2085 	// keep the stack based allocations reasonably sized
2086 	if (fClippingRegion->Frame().IntegerWidth() + 1 < (int32)dstWidth)
2087 		dstWidth = fClippingRegion->Frame().IntegerWidth() + 1;
2088 	if (fClippingRegion->Frame().IntegerHeight() + 1 < (int32)dstHeight)
2089 		dstHeight = fClippingRegion->Frame().IntegerHeight() + 1;
2090 
2091 	// When calculating less filter weights than specified by viewRect,
2092 	// we need to compensate the offset.
2093 	uint32 filterWeightXIndexOffset = 0;
2094 	uint32 filterWeightYIndexOffset = 0;
2095 	if (fClippingRegion->Frame().left > viewRect.left) {
2096 		filterWeightXIndexOffset = (int32)(fClippingRegion->Frame().left
2097 			- viewRect.left);
2098 	}
2099 	if (fClippingRegion->Frame().top > viewRect.top) {
2100 		filterWeightYIndexOffset = (int32)(fClippingRegion->Frame().top
2101 			- viewRect.top);
2102 	}
2103 
2104 	// should not pose a problem with stack overflows
2105 	// (needs around 6Kb for 1920x1200)
2106 	uint16 xIndices[dstWidth];
2107 	uint16 yIndices[dstHeight];
2108 
2109 	// Extract the cropping information for the source bitmap,
2110 	// If only a part of the source bitmap is to be drawn with scale,
2111 	// the offset will be different from the viewRect left top corner.
2112 	int32 xBitmapShift = (int32)(viewRect.left - xOffset);
2113 	int32 yBitmapShift = (int32)(viewRect.top - yOffset);
2114 
2115 	for (uint32 i = 0; i < dstWidth; i++) {
2116 		// index into source
2117 		uint16 index = (uint16)((i + filterWeightXIndexOffset) * srcWidth
2118 			/ (srcWidth * xScale));
2119 		// round down to get the left pixel
2120 		xIndices[i] = index;
2121 		// handle cropped source bitmap
2122 		xIndices[i] += xBitmapShift;
2123 		// precompute index for 32 bit pixels
2124 		xIndices[i] *= 4;
2125 	}
2126 
2127 	for (uint32 i = 0; i < dstHeight; i++) {
2128 		// index into source
2129 		uint16 index = (uint16)((i + filterWeightYIndexOffset) * srcHeight
2130 			/ (srcHeight * yScale));
2131 		// round down to get the top pixel
2132 		yIndices[i] = index;
2133 		// handle cropped source bitmap
2134 		yIndices[i] += yBitmapShift;
2135 	}
2136 //printf("X: %d ... %d, %d (%ld or %f)\n",
2137 //	xIndices[0], xIndices[dstWidth - 2], xIndices[dstWidth - 1], dstWidth,
2138 //	srcWidth * xScale);
2139 //printf("Y: %d ... %d, %d (%ld or %f)\n",
2140 //	yIndices[0], yIndices[dstHeight - 2], yIndices[dstHeight - 1], dstHeight,
2141 //	srcHeight * yScale);
2142 
2143 	const int32 left = (int32)viewRect.left;
2144 	const int32 top = (int32)viewRect.top;
2145 	const int32 right = (int32)viewRect.right;
2146 	const int32 bottom = (int32)viewRect.bottom;
2147 
2148 	const uint32 dstBPR = fBuffer.stride();
2149 
2150 	// iterate over clipping boxes
2151 	fBaseRenderer.first_clip_box();
2152 	do {
2153 		const int32 x1 = max_c(fBaseRenderer.xmin(), left);
2154 		const int32 x2 = min_c(fBaseRenderer.xmax(), right);
2155 		if (x1 > x2)
2156 			continue;
2157 
2158 		int32 y1 = max_c(fBaseRenderer.ymin(), top);
2159 		int32 y2 = min_c(fBaseRenderer.ymax(), bottom);
2160 		if (y1 > y2)
2161 			continue;
2162 
2163 		// buffer offset into destination
2164 		uint8* dst = fBuffer.row_ptr(y1) + x1 * 4;
2165 
2166 		// x and y are needed as indeces into the wheight arrays, so the
2167 		// offset into the target buffer needs to be compensated
2168 		const int32 xIndexL = x1 - left - filterWeightXIndexOffset;
2169 		const int32 xIndexR = x2 - left - filterWeightXIndexOffset;
2170 		y1 -= top + filterWeightYIndexOffset;
2171 		y2 -= top + filterWeightYIndexOffset;
2172 
2173 //printf("x: %ld - %ld\n", xIndexL, xIndexR);
2174 //printf("y: %ld - %ld\n", y1, y2);
2175 
2176 		for (; y1 <= y2; y1++) {
2177 			// buffer offset into source (top row)
2178 			register const uint8* src = srcBuffer.row_ptr(yIndices[y1]);
2179 			// buffer handle for destination to be incremented per pixel
2180 			register uint32* d = (uint32*)dst;
2181 
2182 			for (int32 x = xIndexL; x <= xIndexR; x++) {
2183 				*d = *(uint32*)(src + xIndices[x]);
2184 				d++;
2185 			}
2186 			dst += dstBPR;
2187 		}
2188 	} while (fBaseRenderer.next_clip_box());
2189 
2190 //printf("draw bitmap %.5fx%.5f: %lld\n", xScale, yScale, system_time() - now);
2191 }
2192 
2193 
2194 // _DrawBitmapBilinearCopy32
2195 void
2196 Painter::_DrawBitmapBilinearCopy32(agg::rendering_buffer& srcBuffer,
2197 	double xOffset, double yOffset, double xScale, double yScale,
2198 	BRect viewRect) const
2199 {
2200 	//bigtime_t now = system_time();
2201 	uint32 dstWidth = viewRect.IntegerWidth() + 1;
2202 	uint32 dstHeight = viewRect.IntegerHeight() + 1;
2203 	uint32 srcWidth = srcBuffer.width();
2204 	uint32 srcHeight = srcBuffer.height();
2205 
2206 	// Do not calculate more filter weights than necessary and also
2207 	// keep the stack based allocations reasonably sized
2208 	if (fClippingRegion->Frame().IntegerWidth() + 1 < (int32)dstWidth)
2209 		dstWidth = fClippingRegion->Frame().IntegerWidth() + 1;
2210 	if (fClippingRegion->Frame().IntegerHeight() + 1 < (int32)dstHeight)
2211 		dstHeight = fClippingRegion->Frame().IntegerHeight() + 1;
2212 
2213 	// When calculating less filter weights than specified by viewRect,
2214 	// we need to compensate the offset.
2215 	uint32 filterWeightXIndexOffset = 0;
2216 	uint32 filterWeightYIndexOffset = 0;
2217 	if (fClippingRegion->Frame().left > viewRect.left) {
2218 		filterWeightXIndexOffset = (int32)(fClippingRegion->Frame().left
2219 			- viewRect.left);
2220 	}
2221 	if (fClippingRegion->Frame().top > viewRect.top) {
2222 		filterWeightYIndexOffset = (int32)(fClippingRegion->Frame().top
2223 			- viewRect.top);
2224 	}
2225 
2226 	struct FilterInfo {
2227 		uint16 index;	// index into source bitmap row/column
2228 		uint16 weight;	// weight of the pixel at index [0..255]
2229 	};
2230 
2231 //#define FILTER_INFOS_ON_HEAP
2232 #ifdef FILTER_INFOS_ON_HEAP
2233 	FilterInfo* xWeights = new (nothrow) FilterInfo[dstWidth];
2234 	FilterInfo* yWeights = new (nothrow) FilterInfo[dstHeight];
2235 	if (xWeights == NULL || yWeights == NULL) {
2236 		delete[] xWeights;
2237 		delete[] yWeights;
2238 		return;
2239 	}
2240 #else
2241 	// stack based saves about 200µs on 1.85 GHz Core 2 Duo
2242 	// should not pose a problem with stack overflows
2243 	// (needs around 12Kb for 1920x1200)
2244 	FilterInfo xWeights[dstWidth];
2245 	FilterInfo yWeights[dstHeight];
2246 #endif
2247 
2248 	// Extract the cropping information for the source bitmap,
2249 	// If only a part of the source bitmap is to be drawn with scale,
2250 	// the offset will be different from the viewRect left top corner.
2251 	int32 xBitmapShift = (int32)(viewRect.left - xOffset);
2252 	int32 yBitmapShift = (int32)(viewRect.top - yOffset);
2253 
2254 	for (uint32 i = 0; i < dstWidth; i++) {
2255 		// fractional index into source
2256 		// NOTE: It is very important to calculate the fractional index
2257 		// into the source pixel grid like this to prevent out of bounds
2258 		// access! It will result in the rightmost pixel of the destination
2259 		// to access the rightmost pixel of the source with a weighting
2260 		// of 255. This in turn will trigger an optimization in the loop
2261 		// that also prevents out of bounds access.
2262 		float index = (i + filterWeightXIndexOffset) * (srcWidth - 1)
2263 			/ (srcWidth * xScale - 1);
2264 		// round down to get the left pixel
2265 		xWeights[i].index = (uint16)index;
2266 		xWeights[i].weight = 255 - (uint16)((index - xWeights[i].index) * 255);
2267 		// handle cropped source bitmap
2268 		xWeights[i].index += xBitmapShift;
2269 		// precompute index for 32 bit pixels
2270 		xWeights[i].index *= 4;
2271 	}
2272 
2273 	for (uint32 i = 0; i < dstHeight; i++) {
2274 		// fractional index into source
2275 		// NOTE: It is very important to calculate the fractional index
2276 		// into the source pixel grid like this to prevent out of bounds
2277 		// access! It will result in the bottommost pixel of the destination
2278 		// to access the bottommost pixel of the source with a weighting
2279 		// of 255. This in turn will trigger an optimization in the loop
2280 		// that also prevents out of bounds access.
2281 		float index = (i + filterWeightYIndexOffset) * (srcHeight - 1)
2282 			/ (srcHeight * yScale - 1);
2283 		// round down to get the top pixel
2284 		yWeights[i].index = (uint16)index;
2285 		yWeights[i].weight = 255 - (uint16)((index - yWeights[i].index) * 255);
2286 		// handle cropped source bitmap
2287 		yWeights[i].index += yBitmapShift;
2288 	}
2289 //printf("X: %d/%d ... %d/%d, %d/%d (%ld)\n",
2290 //	xWeights[0].index, xWeights[0].weight,
2291 //	xWeights[dstWidth - 2].index, xWeights[dstWidth - 2].weight,
2292 //	xWeights[dstWidth - 1].index, xWeights[dstWidth - 1].weight,
2293 //	dstWidth);
2294 //printf("Y: %d/%d ... %d/%d, %d/%d (%ld)\n",
2295 //	yWeights[0].index, yWeights[0].weight,
2296 //	yWeights[dstHeight - 2].index, yWeights[dstHeight - 2].weight,
2297 //	yWeights[dstHeight - 1].index, yWeights[dstHeight - 1].weight,
2298 //	dstHeight);
2299 
2300 	const int32 left = (int32)viewRect.left;
2301 	const int32 top = (int32)viewRect.top;
2302 	const int32 right = (int32)viewRect.right;
2303 	const int32 bottom = (int32)viewRect.bottom;
2304 
2305 	const uint32 dstBPR = fBuffer.stride();
2306 	const uint32 srcBPR = srcBuffer.stride();
2307 
2308 	// Figure out which version of the code we want to use...
2309 	enum {
2310 		kOptimizeForLowFilterRatio = 0,
2311 		kUseDefaultVersion,
2312 		kUseSIMDVersion
2313 	};
2314 
2315 	int codeSelect = kUseDefaultVersion;
2316 
2317 	uint32 neededSIMDFlags = APPSERVER_SIMD_MMX | APPSERVER_SIMD_SSE;
2318 	if ((gAppServerSIMDFlags & neededSIMDFlags) == neededSIMDFlags)
2319 		codeSelect = kUseSIMDVersion;
2320 	else {
2321 		if (xScale == yScale && (xScale == 1.5 || xScale == 2.0
2322 			|| xScale == 2.5 || xScale == 3.0)) {
2323 			codeSelect = kOptimizeForLowFilterRatio;
2324 		}
2325 	}
2326 
2327 	// iterate over clipping boxes
2328 	fBaseRenderer.first_clip_box();
2329 	do {
2330 		const int32 x1 = max_c(fBaseRenderer.xmin(), left);
2331 		const int32 x2 = min_c(fBaseRenderer.xmax(), right);
2332 		if (x1 > x2)
2333 			continue;
2334 
2335 		int32 y1 = max_c(fBaseRenderer.ymin(), top);
2336 		int32 y2 = min_c(fBaseRenderer.ymax(), bottom);
2337 		if (y1 > y2)
2338 			continue;
2339 
2340 		// buffer offset into destination
2341 		uint8* dst = fBuffer.row_ptr(y1) + x1 * 4;
2342 
2343 		// x and y are needed as indeces into the wheight arrays, so the
2344 		// offset into the target buffer needs to be compensated
2345 		const int32 xIndexL = x1 - left - filterWeightXIndexOffset;
2346 		const int32 xIndexR = x2 - left - filterWeightXIndexOffset;
2347 		y1 -= top + filterWeightYIndexOffset;
2348 		y2 -= top + filterWeightYIndexOffset;
2349 
2350 //printf("x: %ld - %ld\n", xIndexL, xIndexR);
2351 //printf("y: %ld - %ld\n", y1, y2);
2352 
2353 		switch (codeSelect) {
2354 			case kOptimizeForLowFilterRatio:
2355 			{
2356 				// In this mode, we anticipate to hit many destination pixels
2357 				// that map directly to a source pixel, we have more branches
2358 				// in the inner loop but save time because of the special
2359 				// cases. If there are too few direct hit pixels, the branches
2360 				// only waste time.
2361 				for (; y1 <= y2; y1++) {
2362 					// cache the weight of the top and bottom row
2363 					const uint16 wTop = yWeights[y1].weight;
2364 					const uint16 wBottom = 255 - yWeights[y1].weight;
2365 
2366 					// buffer offset into source (top row)
2367 					register const uint8* src
2368 						= srcBuffer.row_ptr(yWeights[y1].index);
2369 					// buffer handle for destination to be incremented per
2370 					// pixel
2371 					register uint8* d = dst;
2372 
2373 					if (wTop == 255) {
2374 						for (int32 x = xIndexL; x <= xIndexR; x++) {
2375 							const uint8* s = src + xWeights[x].index;
2376 							// This case is important to prevent out
2377 							// of bounds access at bottom edge of the source
2378 							// bitmap. If the scale is low and integer, it will
2379 							// also help the speed.
2380 							if (xWeights[x].weight == 255) {
2381 								// As above, but to prevent out of bounds
2382 								// on the right edge.
2383 								*(uint32*)d = *(uint32*)s;
2384 							} else {
2385 								// Only the left and right pixels are
2386 								// interpolated, since the top row has 100%
2387 								// weight.
2388 								const uint16 wLeft = xWeights[x].weight;
2389 								const uint16 wRight = 255 - wLeft;
2390 								d[0] = (s[0] * wLeft + s[4] * wRight) >> 8;
2391 								d[1] = (s[1] * wLeft + s[5] * wRight) >> 8;
2392 								d[2] = (s[2] * wLeft + s[6] * wRight) >> 8;
2393 							}
2394 							d += 4;
2395 						}
2396 					} else {
2397 						for (int32 x = xIndexL; x <= xIndexR; x++) {
2398 							const uint8* s = src + xWeights[x].index;
2399 							if (xWeights[x].weight == 255) {
2400 								// Prevent out of bounds access on the right
2401 								// edge or simply speed up.
2402 								const uint8* sBottom = s + srcBPR;
2403 								d[0] = (s[0] * wTop + sBottom[0] * wBottom)
2404 									>> 8;
2405 								d[1] = (s[1] * wTop + sBottom[1] * wBottom)
2406 									>> 8;
2407 								d[2] = (s[2] * wTop + sBottom[2] * wBottom)
2408 									>> 8;
2409 							} else {
2410 								// calculate the weighted sum of all four
2411 								// interpolated pixels
2412 								const uint16 wLeft = xWeights[x].weight;
2413 								const uint16 wRight = 255 - wLeft;
2414 								// left and right of top row
2415 								uint32 t0 = (s[0] * wLeft + s[4] * wRight)
2416 									* wTop;
2417 								uint32 t1 = (s[1] * wLeft + s[5] * wRight)
2418 									* wTop;
2419 								uint32 t2 = (s[2] * wLeft + s[6] * wRight)
2420 									* wTop;
2421 
2422 								// left and right of bottom row
2423 								s += srcBPR;
2424 								t0 += (s[0] * wLeft + s[4] * wRight) * wBottom;
2425 								t1 += (s[1] * wLeft + s[5] * wRight) * wBottom;
2426 								t2 += (s[2] * wLeft + s[6] * wRight) * wBottom;
2427 
2428 								d[0] = t0 >> 16;
2429 								d[1] = t1 >> 16;
2430 								d[2] = t2 >> 16;
2431 							}
2432 							d += 4;
2433 						}
2434 					}
2435 					dst += dstBPR;
2436 				}
2437 				break;
2438 			}
2439 
2440 			case kUseDefaultVersion:
2441 			{
2442 				// In this mode we anticipate many pixels wich need filtering,
2443 				// there are no special cases for direct hit pixels except for
2444 				// the last column/row and the right/bottom corner pixel.
2445 
2446 				// The last column/row handling does not need to be performed
2447 				// for all clipping rects!
2448 				int32 yMax = y2;
2449 				if (yWeights[yMax].weight == 255)
2450 					yMax--;
2451 				int32 xIndexMax = xIndexR;
2452 				if (xWeights[xIndexMax].weight == 255)
2453 					xIndexMax--;
2454 
2455 				for (; y1 <= yMax; y1++) {
2456 					// cache the weight of the top and bottom row
2457 					const uint16 wTop = yWeights[y1].weight;
2458 					const uint16 wBottom = 255 - yWeights[y1].weight;
2459 
2460 					// buffer offset into source (top row)
2461 					register const uint8* src
2462 						= srcBuffer.row_ptr(yWeights[y1].index);
2463 					// buffer handle for destination to be incremented per
2464 					// pixel
2465 					register uint8* d = dst;
2466 
2467 					for (int32 x = xIndexL; x <= xIndexMax; x++) {
2468 						const uint8* s = src + xWeights[x].index;
2469 						// calculate the weighted sum of all four
2470 						// interpolated pixels
2471 						const uint16 wLeft = xWeights[x].weight;
2472 						const uint16 wRight = 255 - wLeft;
2473 						// left and right of top row
2474 						uint32 t0 = (s[0] * wLeft + s[4] * wRight) * wTop;
2475 						uint32 t1 = (s[1] * wLeft + s[5] * wRight) * wTop;
2476 						uint32 t2 = (s[2] * wLeft + s[6] * wRight) * wTop;
2477 
2478 						// left and right of bottom row
2479 						s += srcBPR;
2480 						t0 += (s[0] * wLeft + s[4] * wRight) * wBottom;
2481 						t1 += (s[1] * wLeft + s[5] * wRight) * wBottom;
2482 						t2 += (s[2] * wLeft + s[6] * wRight) * wBottom;
2483 						d[0] = t0 >> 16;
2484 						d[1] = t1 >> 16;
2485 						d[2] = t2 >> 16;
2486 						d += 4;
2487 					}
2488 					// last column of pixels if necessary
2489 					if (xIndexMax < xIndexR) {
2490 						const uint8* s = src + xWeights[xIndexR].index;
2491 						const uint8* sBottom = s + srcBPR;
2492 						d[0] = (s[0] * wTop + sBottom[0] * wBottom) >> 8;
2493 						d[1] = (s[1] * wTop + sBottom[1] * wBottom) >> 8;
2494 						d[2] = (s[2] * wTop + sBottom[2] * wBottom) >> 8;
2495 					}
2496 
2497 					dst += dstBPR;
2498 				}
2499 
2500 				// last row of pixels if necessary
2501 				// buffer offset into source (bottom row)
2502 				register const uint8* src
2503 					= srcBuffer.row_ptr(yWeights[y2].index);
2504 				// buffer handle for destination to be incremented per pixel
2505 				register uint8* d = dst;
2506 
2507 				if (yMax < y2) {
2508 					for (int32 x = xIndexL; x <= xIndexMax; x++) {
2509 						const uint8* s = src + xWeights[x].index;
2510 						const uint16 wLeft = xWeights[x].weight;
2511 						const uint16 wRight = 255 - wLeft;
2512 						d[0] = (s[0] * wLeft + s[4] * wRight) >> 8;
2513 						d[1] = (s[1] * wLeft + s[5] * wRight) >> 8;
2514 						d[2] = (s[2] * wLeft + s[6] * wRight) >> 8;
2515 						d += 4;
2516 					}
2517 				}
2518 
2519 				// pixel in bottom right corner if necessary
2520 				if (yMax < y2 && xIndexMax < xIndexR) {
2521 					const uint8* s = src + xWeights[xIndexR].index;
2522 					*(uint32*)d = *(uint32*)s;
2523 				}
2524 				break;
2525 			}
2526 
2527 #ifdef __INTEL__
2528 			case kUseSIMDVersion:
2529 			{
2530 				// Basically the same as the "standard" mode, but we use SIMD
2531 				// routines for the processing of the single display lines.
2532 
2533 				// The last column/row handling does not need to be performed
2534 				// for all clipping rects!
2535 				int32 yMax = y2;
2536 				if (yWeights[yMax].weight == 255)
2537 					yMax--;
2538 				int32 xIndexMax = xIndexR;
2539 				if (xWeights[xIndexMax].weight == 255)
2540 					xIndexMax--;
2541 
2542 				for (; y1 <= yMax; y1++) {
2543 					// cache the weight of the top and bottom row
2544 					const uint16 wTop = yWeights[y1].weight;
2545 					const uint16 wBottom = 255 - yWeights[y1].weight;
2546 
2547 					// buffer offset into source (top row)
2548 					const uint8* src = srcBuffer.row_ptr(yWeights[y1].index);
2549 					// buffer handle for destination to be incremented per
2550 					// pixel
2551 					uint8* d = dst;
2552 					bilinear_scale_xloop_mmxsse(src, dst, xWeights,	xIndexL,
2553 						xIndexMax, wTop, srcBPR);
2554 					// increase pointer by processed pixels
2555 					d += (xIndexMax - xIndexL + 1) * 4;
2556 
2557 					// last column of pixels if necessary
2558 					if (xIndexMax < xIndexR) {
2559 						const uint8* s = src + xWeights[xIndexR].index;
2560 						const uint8* sBottom = s + srcBPR;
2561 						d[0] = (s[0] * wTop + sBottom[0] * wBottom) >> 8;
2562 						d[1] = (s[1] * wTop + sBottom[1] * wBottom) >> 8;
2563 						d[2] = (s[2] * wTop + sBottom[2] * wBottom) >> 8;
2564 					}
2565 
2566 					dst += dstBPR;
2567 				}
2568 
2569 				// last row of pixels if necessary
2570 				// buffer offset into source (bottom row)
2571 				register const uint8* src
2572 					= srcBuffer.row_ptr(yWeights[y2].index);
2573 				// buffer handle for destination to be incremented per pixel
2574 				register uint8* d = dst;
2575 
2576 				if (yMax < y2) {
2577 					for (int32 x = xIndexL; x <= xIndexMax; x++) {
2578 						const uint8* s = src + xWeights[x].index;
2579 						const uint16 wLeft = xWeights[x].weight;
2580 						const uint16 wRight = 255 - wLeft;
2581 						d[0] = (s[0] * wLeft + s[4] * wRight) >> 8;
2582 						d[1] = (s[1] * wLeft + s[5] * wRight) >> 8;
2583 						d[2] = (s[2] * wLeft + s[6] * wRight) >> 8;
2584 						d += 4;
2585 					}
2586 				}
2587 
2588 				// pixel in bottom right corner if necessary
2589 				if (yMax < y2 && xIndexMax < xIndexR) {
2590 					const uint8* s = src + xWeights[xIndexR].index;
2591 					*(uint32*)d = *(uint32*)s;
2592 				}
2593 				break;
2594 			}
2595 #endif	// __INTEL__
2596 		}
2597 	} while (fBaseRenderer.next_clip_box());
2598 
2599 #ifdef FILTER_INFOS_ON_HEAP
2600 	delete[] xWeights;
2601 	delete[] yWeights;
2602 #endif
2603 //printf("draw bitmap %.5fx%.5f: %lld\n", xScale, yScale, system_time() - now);
2604 }
2605 
2606 
2607 // _DrawBitmapGeneric32
2608 void
2609 Painter::_DrawBitmapGeneric32(agg::rendering_buffer& srcBuffer,
2610 	double xOffset, double yOffset, double xScale, double yScale,
2611 	BRect viewRect, uint32 options) const
2612 {
2613 	TRACE("Painter::_DrawBitmapGeneric32()\n");
2614 	TRACE("   offset: %.1f, %.1f\n", xOffset, yOffset);
2615 	TRACE("   scale: %.3f, %.3f\n", xScale, yScale);
2616 	TRACE("   viewRect: (%.1f, %.1f) - (%.1f, %.1f)\n",
2617 		viewRect.left, viewRect.top, viewRect.right, viewRect.bottom);
2618 	// AGG pipeline
2619 
2620 	// pixel format attached to bitmap
2621 	typedef agg::pixfmt_bgra32 pixfmt_image;
2622 	pixfmt_image pixf_img(srcBuffer);
2623 
2624 	agg::trans_affine srcMatrix;
2625 	// NOTE: R5 seems to ignore this offset when drawing bitmaps
2626 	//	srcMatrix *= agg::trans_affine_translation(-actualBitmapRect.left,
2627 	//		-actualBitmapRect.top);
2628 
2629 	agg::trans_affine imgMatrix;
2630 	imgMatrix *= agg::trans_affine_translation(xOffset - viewRect.left,
2631 		yOffset - viewRect.top);
2632 	imgMatrix *= agg::trans_affine_scaling(xScale, yScale);
2633 	imgMatrix *= agg::trans_affine_translation(viewRect.left, viewRect.top);
2634 	imgMatrix.invert();
2635 
2636 	// image interpolator
2637 	typedef agg::span_interpolator_linear<> interpolator_type;
2638 	interpolator_type interpolator(imgMatrix);
2639 
2640 	// scanline allocator
2641 	agg::span_allocator<pixfmt_image::color_type> spanAllocator;
2642 
2643 	// image accessor attached to pixel format of bitmap
2644 	typedef agg::image_accessor_clip<pixfmt_image> source_type;
2645 	source_type source(pixf_img, agg::rgba8(0, 0, 0, 0));
2646 
2647 	// clip to the current clipping region's frame
2648 	viewRect = viewRect & fClippingRegion->Frame();
2649 	// convert to pixel coords (versus pixel indices)
2650 	viewRect.right++;
2651 	viewRect.bottom++;
2652 
2653 	// path enclosing the bitmap
2654 	fPath.remove_all();
2655 	fPath.move_to(viewRect.left, viewRect.top);
2656 	fPath.line_to(viewRect.right, viewRect.top);
2657 	fPath.line_to(viewRect.right, viewRect.bottom);
2658 	fPath.line_to(viewRect.left, viewRect.bottom);
2659 	fPath.close_polygon();
2660 
2661 	agg::conv_transform<agg::path_storage> transformedPath(fPath, srcMatrix);
2662 	fRasterizer.reset();
2663 	fRasterizer.add_path(transformedPath);
2664 
2665 	if ((options & B_FILTER_BITMAP_BILINEAR) != 0) {
2666 		// image filter (bilinear)
2667 		typedef agg::span_image_filter_rgba_bilinear<
2668 			source_type, interpolator_type> span_gen_type;
2669 		span_gen_type spanGenerator(source, interpolator);
2670 
2671 		// render the path with the bitmap as scanline fill
2672 		agg::render_scanlines_aa(fRasterizer, fUnpackedScanline, fBaseRenderer,
2673 			spanAllocator, spanGenerator);
2674 	} else {
2675 		// image filter (nearest neighbor)
2676 		typedef agg::span_image_filter_rgba_nn<
2677 			source_type, interpolator_type> span_gen_type;
2678 		span_gen_type spanGenerator(source, interpolator);
2679 
2680 		// render the path with the bitmap as scanline fill
2681 		agg::render_scanlines_aa(fRasterizer, fUnpackedScanline, fBaseRenderer,
2682 			spanAllocator, spanGenerator);
2683 	}
2684 }
2685 
2686 
2687 // _InvertRect32
2688 void
2689 Painter::_InvertRect32(BRect r) const
2690 {
2691 	int32 width = r.IntegerWidth() + 1;
2692 	for (int32 y = (int32)r.top; y <= (int32)r.bottom; y++) {
2693 		uint8* dst = fBuffer.row_ptr(y);
2694 		dst += (int32)r.left * 4;
2695 		for (int32 i = 0; i < width; i++) {
2696 			dst[0] = 255 - dst[0];
2697 			dst[1] = 255 - dst[1];
2698 			dst[2] = 255 - dst[2];
2699 			dst += 4;
2700 		}
2701 	}
2702 }
2703 
2704 
2705 // _BlendRect32
2706 void
2707 Painter::_BlendRect32(const BRect& r, const rgb_color& c) const
2708 {
2709 	if (!fValidClipping)
2710 		return;
2711 
2712 	uint8* dst = fBuffer.row_ptr(0);
2713 	uint32 bpr = fBuffer.stride();
2714 
2715 	int32 left = (int32)r.left;
2716 	int32 top = (int32)r.top;
2717 	int32 right = (int32)r.right;
2718 	int32 bottom = (int32)r.bottom;
2719 
2720 	// fill rects, iterate over clipping boxes
2721 	fBaseRenderer.first_clip_box();
2722 	do {
2723 		int32 x1 = max_c(fBaseRenderer.xmin(), left);
2724 		int32 x2 = min_c(fBaseRenderer.xmax(), right);
2725 		if (x1 <= x2) {
2726 			int32 y1 = max_c(fBaseRenderer.ymin(), top);
2727 			int32 y2 = min_c(fBaseRenderer.ymax(), bottom);
2728 
2729 			uint8* offset = dst + x1 * 4 + y1 * bpr;
2730 			for (; y1 <= y2; y1++) {
2731 				blend_line32(offset, x2 - x1 + 1, c.red, c.green, c.blue,
2732 					c.alpha);
2733 				offset += bpr;
2734 			}
2735 		}
2736 	} while (fBaseRenderer.next_clip_box());
2737 }
2738 
2739 
2740 // #pragma mark -
2741 
2742 
2743 template<class VertexSource>
2744 BRect
2745 Painter::_BoundingBox(VertexSource& path) const
2746 {
2747 	double left = 0.0;
2748 	double top = 0.0;
2749 	double right = -1.0;
2750 	double bottom = -1.0;
2751 	uint32 pathID[1];
2752 	pathID[0] = 0;
2753 	agg::bounding_rect(path, pathID, 0, 1, &left, &top, &right, &bottom);
2754 	return BRect(left, top, right, bottom);
2755 }
2756 
2757 
2758 // agg_line_cap_mode_for
2759 inline agg::line_cap_e
2760 agg_line_cap_mode_for(cap_mode mode)
2761 {
2762 	switch (mode) {
2763 		case B_BUTT_CAP:
2764 			return agg::butt_cap;
2765 		case B_SQUARE_CAP:
2766 			return agg::square_cap;
2767 		case B_ROUND_CAP:
2768 			return agg::round_cap;
2769 	}
2770 	return agg::butt_cap;
2771 }
2772 
2773 
2774 // agg_line_join_mode_for
2775 inline agg::line_join_e
2776 agg_line_join_mode_for(join_mode mode)
2777 {
2778 	switch (mode) {
2779 		case B_MITER_JOIN:
2780 			return agg::miter_join;
2781 		case B_ROUND_JOIN:
2782 			return agg::round_join;
2783 		case B_BEVEL_JOIN:
2784 		case B_BUTT_JOIN: // ??
2785 		case B_SQUARE_JOIN: // ??
2786 			return agg::bevel_join;
2787 	}
2788 	return agg::miter_join;
2789 }
2790 
2791 // _StrokePath
2792 template<class VertexSource>
2793 BRect
2794 Painter::_StrokePath(VertexSource& path) const
2795 {
2796 	agg::conv_stroke<VertexSource> stroke(path);
2797 	stroke.width(fPenSize);
2798 
2799 	stroke.line_cap(agg_line_cap_mode_for(fLineCapMode));
2800 	stroke.line_join(agg_line_join_mode_for(fLineJoinMode));
2801 	stroke.miter_limit(fMiterLimit);
2802 
2803 	if (gSubpixelAntialiasing) {
2804 		fSubpixRasterizer.reset();
2805 		fSubpixRasterizer.add_path(stroke);
2806 
2807 		agg::render_scanlines(fSubpixRasterizer,
2808 			fSubpixPackedScanline, fSubpixRenderer);
2809 	} else {
2810 		fRasterizer.reset();
2811 		fRasterizer.add_path(stroke);
2812 
2813 		agg::render_scanlines(fRasterizer, fPackedScanline, fRenderer);
2814 	}
2815 
2816 	BRect touched = _BoundingBox(path);
2817 	float penSize = ceilf(fPenSize / 2.0);
2818 	touched.InsetBy(-penSize, -penSize);
2819 
2820 	return _Clipped(touched);
2821 }
2822 
2823 
2824 // _FillPath
2825 template<class VertexSource>
2826 BRect
2827 Painter::_FillPath(VertexSource& path) const
2828 {
2829 	if (gSubpixelAntialiasing) {
2830 		fSubpixRasterizer.reset();
2831 		fSubpixRasterizer.add_path(path);
2832 		agg::render_scanlines(fSubpixRasterizer,
2833 			fSubpixPackedScanline, fSubpixRenderer);
2834 	} else {
2835 		fRasterizer.reset();
2836 		fRasterizer.add_path(path);
2837 		agg::render_scanlines(fRasterizer, fPackedScanline, fRenderer);
2838 	}
2839 
2840 	return _Clipped(_BoundingBox(path));
2841 }
2842 
2843 
2844 // _FillPath
2845 template<class VertexSource>
2846 BRect
2847 Painter::_FillPath(VertexSource& path, const BGradient& gradient) const
2848 {
2849 	GTRACE("Painter::_FillPath\n");
2850 
2851 	switch(gradient.GetType()) {
2852 		case BGradient::TYPE_LINEAR: {
2853 			GTRACE(("Painter::_FillPath> type == TYPE_LINEAR\n"));
2854 			_FillPathGradientLinear(path, *((const BGradientLinear*) &gradient));
2855 			break;
2856 		}
2857 		case BGradient::TYPE_RADIAL: {
2858 			GTRACE(("Painter::_FillPathGradient> type == TYPE_RADIAL\n"));
2859 			_FillPathGradientRadial(path,
2860 				*((const BGradientRadial*) &gradient));
2861 			break;
2862 		}
2863 		case BGradient::TYPE_RADIAL_FOCUS: {
2864 			GTRACE(("Painter::_FillPathGradient> type == TYPE_RADIAL_FOCUS\n"));
2865 			_FillPathGradientRadialFocus(path,
2866 				*((const BGradientRadialFocus*) &gradient));
2867 			break;
2868 		}
2869 		case BGradient::TYPE_DIAMOND: {
2870 			GTRACE(("Painter::_FillPathGradient> type == TYPE_DIAMOND\n"));
2871 			_FillPathGradientDiamond(path,
2872 				*((const BGradientDiamond*) &gradient));
2873 			break;
2874 		}
2875 		case BGradient::TYPE_CONIC: {
2876 			GTRACE(("Painter::_FillPathGradient> type == TYPE_CONIC\n"));
2877 			_FillPathGradientConic(path,
2878 				*((const BGradientConic*) &gradient));
2879 			break;
2880 		}
2881 		case BGradient::TYPE_NONE: {
2882 			GTRACE(("Painter::_FillPathGradient> type == TYPE_NONE\n"));
2883 			break;
2884 		}
2885 	}
2886 
2887 	return _Clipped(_BoundingBox(path));
2888 }
2889 
2890 
2891 // _MakeGradient
2892 void
2893 Painter::_MakeGradient(const BGradient& gradient, int32 colorCount,
2894 	uint32* colors, int32 arrayOffset, int32 arraySize) const
2895 {
2896 	BGradient::ColorStop* from = gradient.ColorStopAt(0);
2897 
2898 	if (!from)
2899 		return;
2900 
2901 	// current index into "colors" array
2902 //	int32 index = (int32)floorf(colorCount * from->offset + 0.5)
2903 //		+ arrayOffset;
2904 	int32 index = (int32)floorf(colorCount * from->offset / 255 + 0.5)
2905 		+ arrayOffset;
2906 	if (index > arraySize)
2907 		index = arraySize;
2908 	// Make sure we fill the entire array in case the gradient is outside.
2909 	if (index > 0) {
2910 		uint8* c = (uint8*)&colors[0];
2911 		for (int32 i = 0; i < index; i++) {
2912 			c[0] = from->color.blue;
2913 			c[1] = from->color.green;
2914 			c[2] = from->color.red;
2915 			c[3] = from->color.alpha;
2916 			c += 4;
2917 		}
2918 	}
2919 
2920 	// interpolate "from" to "to"
2921 	int32 stopCount = gradient.CountColorStops();
2922 	for (int32 i = 1; i < stopCount; i++) {
2923 		// find the step with the next offset
2924 		BGradient::ColorStop* to = gradient.ColorStopAtFast(i);
2925 
2926 		// interpolate
2927 //		int32 offset = (int32)floorf((colorCount - 1) * to->offset + 0.5);
2928 		int32 offset = (int32)floorf((colorCount - 1)
2929 			* to->offset / 255 + 0.5);
2930 		if (offset > colorCount - 1)
2931 			offset = colorCount - 1;
2932 		offset += arrayOffset;
2933 		int32 dist = offset - index;
2934 		if (dist >= 0) {
2935 			int32 startIndex = max_c(index, 0);
2936 			int32 stopIndex = min_c(offset, arraySize - 1);
2937 			uint8* c = (uint8*)&colors[startIndex];
2938 			for (int32 i = startIndex; i <= stopIndex; i++) {
2939 				float f = (float)(offset - i) / (float)(dist + 1);
2940 				float t = 1.0 - f;
2941 				c[0] = (uint8)floorf(from->color.blue * f
2942 					+ to->color.blue * t + 0.5);
2943 				c[1] = (uint8)floorf(from->color.green * f
2944 					+ to->color.green * t + 0.5);
2945 				c[2] = (uint8)floorf(from->color.red * f
2946 					+ to->color.red * t + 0.5);
2947 				c[3] = (uint8)floorf(from->color.alpha * f
2948 					+ to->color.alpha * t + 0.5);
2949 				c += 4;
2950 			}
2951 		}
2952 		index = offset + 1;
2953 		// the current "to" will be the "from" in the next interpolation
2954 		from = to;
2955 	}
2956 	//  make sure we fill the entire array
2957 	if (index < arraySize) {
2958 		int32 startIndex = max_c(index, 0);
2959 		uint8* c = (uint8*)&colors[startIndex];
2960 		for (int32 i = startIndex; i < arraySize; i++) {
2961 			c[0] = from->color.blue;
2962 			c[1] = from->color.green;
2963 			c[2] = from->color.red;
2964 			c[3] = from->color.alpha;
2965 			c += 4;
2966 		}
2967 	}
2968 }
2969 
2970 
2971 // _MakeGradient
2972 template<class Array>
2973 void
2974 Painter::_MakeGradient(Array& array, const BGradient& gradient) const
2975 {
2976 	for (int i = 0; i < gradient.CountColorStops() - 1; i++) {
2977 		BGradient::ColorStop* from = gradient.ColorStopAtFast(i);
2978 		BGradient::ColorStop* to = gradient.ColorStopAtFast(i + 1);
2979 		agg::rgba8 fromColor(from->color.red, from->color.green,
2980 							 from->color.blue, from->color.alpha);
2981 		agg::rgba8 toColor(to->color.red, to->color.green,
2982 						   to->color.blue, to->color.alpha);
2983 		GTRACE("Painter::_MakeGradient> fromColor(%d, %d, %d) offset = %f\n",
2984 			   fromColor.r, fromColor.g, fromColor.b, from->offset);
2985 		GTRACE("Painter::_MakeGradient> toColor(%d, %d, %d) offset = %f\n",
2986 			   toColor.r, toColor.g, toColor.b, to->offset);
2987 		float dist = to->offset - from->offset;
2988 		GTRACE("Painter::_MakeGradient> dist = %f\n", dist);
2989 		// TODO: Review this... offset should better be on [0..1]
2990 		if (dist > 0) {
2991 			for (int j = (int)from->offset; j <= (int)to->offset; j++) {
2992 				float f = (float)(to->offset - j) / (float)(dist + 1);
2993 				array[j] = toColor.gradient(fromColor, f);
2994 				GTRACE("Painter::_MakeGradient> array[%d](%d, %d, %d)\n",
2995 					   array[j].r, array[j].g, array[j].b);
2996 			}
2997 		}
2998 	}
2999 }
3000 
3001 
3002 // _CalcLinearGradientTransform
3003 void Painter::_CalcLinearGradientTransform(BPoint startPoint, BPoint endPoint,
3004 	agg::trans_affine& matrix, float gradient_d2) const
3005 {
3006 	float dx = endPoint.x - startPoint.x;
3007 	float dy = endPoint.y - startPoint.y;
3008 
3009 	matrix.reset();
3010 	matrix *= agg::trans_affine_scaling(sqrt(dx * dx + dy * dy) / gradient_d2);
3011 	matrix *= agg::trans_affine_rotation(atan2(dy, dx));
3012 	matrix *= agg::trans_affine_translation(startPoint.x, startPoint.y);
3013 	matrix.invert();
3014 }
3015 
3016 
3017 // _FillPathGradientLinear
3018 template<class VertexSource>
3019 void
3020 Painter::_FillPathGradientLinear(VertexSource& path,
3021 	const BGradientLinear& linear) const
3022 {
3023 	GTRACE("Painter::_FillPathGradientLinear\n");
3024 
3025 	BPoint start = linear.Start();
3026 	BPoint end = linear.End();
3027 
3028 	typedef agg::span_interpolator_linear<> interpolator_type;
3029 	typedef agg::pod_auto_array<agg::rgba8, 256> color_array_type;
3030 	typedef agg::span_allocator<agg::rgba8> span_allocator_type;
3031 	typedef agg::gradient_x	gradient_func_type;
3032 	typedef agg::span_gradient<agg::rgba8, interpolator_type,
3033 				gradient_func_type, color_array_type> span_gradient_type;
3034 	typedef agg::renderer_scanline_aa<renderer_base, span_allocator_type,
3035 				span_gradient_type> renderer_gradient_type;
3036 
3037 	gradient_func_type gradientFunc;
3038 	agg::trans_affine gradientMatrix;
3039 	interpolator_type spanInterpolator(gradientMatrix);
3040 	span_allocator_type spanAllocator;
3041 	color_array_type colorArray;
3042 
3043 	_MakeGradient(colorArray, linear);
3044 
3045 	span_gradient_type spanGradient(spanInterpolator, gradientFunc, colorArray,
3046 		0, 100);
3047 
3048 	renderer_gradient_type gradientRenderer(fBaseRenderer, spanAllocator,
3049 		spanGradient);
3050 
3051 	_CalcLinearGradientTransform(start, end, gradientMatrix);
3052 
3053 	fRasterizer.reset();
3054 	fRasterizer.add_path(path);
3055 	agg::render_scanlines(fRasterizer, fPackedScanline, gradientRenderer);
3056 }
3057 
3058 
3059 // _FillPathGradientRadial
3060 template<class VertexSource>
3061 void
3062 Painter::_FillPathGradientRadial(VertexSource& path,
3063 	const BGradientRadial& radial) const
3064 {
3065 	GTRACE("Painter::_FillPathGradientRadial\n");
3066 
3067 	BPoint center = radial.Center();
3068 // TODO: finish this
3069 //	float radius = radial.Radius();
3070 
3071 	typedef agg::span_interpolator_linear<> interpolator_type;
3072 	typedef agg::pod_auto_array<agg::rgba8, 256> color_array_type;
3073 	typedef agg::span_allocator<agg::rgba8> span_allocator_type;
3074 	typedef agg::gradient_radial gradient_func_type;
3075 	typedef agg::span_gradient<agg::rgba8, interpolator_type,
3076 	gradient_func_type, color_array_type> span_gradient_type;
3077 	typedef agg::renderer_scanline_aa<renderer_base, span_allocator_type,
3078 	span_gradient_type> renderer_gradient_type;
3079 
3080 	gradient_func_type gradientFunc;
3081 	agg::trans_affine gradientMatrix;
3082 	interpolator_type spanInterpolator(gradientMatrix);
3083 	span_allocator_type spanAllocator;
3084 	color_array_type colorArray;
3085 
3086 	_MakeGradient(colorArray, radial);
3087 
3088 	span_gradient_type spanGradient(spanInterpolator, gradientFunc, colorArray,
3089 		0, 100);
3090 
3091 	renderer_gradient_type gradientRenderer(fBaseRenderer, spanAllocator,
3092 		spanGradient);
3093 
3094 	gradientMatrix.reset();
3095 	gradientMatrix *= agg::trans_affine_translation(center.x, center.y);
3096 	gradientMatrix.invert();
3097 
3098 //	_CalcLinearGradientTransform(start, end, gradientMtx);
3099 
3100 	fRasterizer.reset();
3101 	fRasterizer.add_path(path);
3102 	agg::render_scanlines(fRasterizer, fPackedScanline, gradientRenderer);
3103 }
3104 
3105 
3106 // _FillPathGradientRadialFocus
3107 template<class VertexSource>
3108 void
3109 Painter::_FillPathGradientRadialFocus(VertexSource& path,
3110 	const BGradientRadialFocus& focus) const
3111 {
3112 	GTRACE("Painter::_FillPathGradientRadialFocus\n");
3113 
3114 	BPoint center = focus.Center();
3115 // TODO: finish this.
3116 //	BPoint focal = focus.Focal();
3117 //	float radius = focus.Radius();
3118 
3119 	typedef agg::span_interpolator_linear<> interpolator_type;
3120 	typedef agg::pod_auto_array<agg::rgba8, 256> color_array_type;
3121 	typedef agg::span_allocator<agg::rgba8> span_allocator_type;
3122 	typedef agg::gradient_radial_focus gradient_func_type;
3123 	typedef agg::span_gradient<agg::rgba8, interpolator_type,
3124 	gradient_func_type, color_array_type> span_gradient_type;
3125 	typedef agg::renderer_scanline_aa<renderer_base, span_allocator_type,
3126 	span_gradient_type> renderer_gradient_type;
3127 
3128 	gradient_func_type gradientFunc;
3129 	agg::trans_affine gradientMatrix;
3130 	interpolator_type spanInterpolator(gradientMatrix);
3131 	span_allocator_type spanAllocator;
3132 	color_array_type colorArray;
3133 
3134 	_MakeGradient(colorArray, focus);
3135 
3136 	span_gradient_type spanGradient(spanInterpolator, gradientFunc, colorArray,
3137 		0, 100);
3138 
3139 	renderer_gradient_type gradientRenderer(fBaseRenderer, spanAllocator,
3140 		spanGradient);
3141 
3142 	gradientMatrix.reset();
3143 	gradientMatrix *= agg::trans_affine_translation(center.x, center.y);
3144 	gradientMatrix.invert();
3145 
3146 	//	_CalcLinearGradientTransform(start, end, gradientMatrix);
3147 
3148 	fRasterizer.reset();
3149 	fRasterizer.add_path(path);
3150 	agg::render_scanlines(fRasterizer, fPackedScanline, gradientRenderer);
3151 }
3152 
3153 
3154 // _FillPathGradientDiamond
3155 template<class VertexSource>
3156 void
3157 Painter::_FillPathGradientDiamond(VertexSource& path,
3158 	const BGradientDiamond& diamond) const
3159 {
3160 	GTRACE("Painter::_FillPathGradientDiamond\n");
3161 
3162 	BPoint center = diamond.Center();
3163 //	float radius = diamond.Radius();
3164 
3165 	typedef agg::span_interpolator_linear<> interpolator_type;
3166 	typedef agg::pod_auto_array<agg::rgba8, 256> color_array_type;
3167 	typedef agg::span_allocator<agg::rgba8> span_allocator_type;
3168 	typedef agg::gradient_diamond gradient_func_type;
3169 	typedef agg::span_gradient<agg::rgba8, interpolator_type,
3170 	gradient_func_type, color_array_type> span_gradient_type;
3171 	typedef agg::renderer_scanline_aa<renderer_base, span_allocator_type,
3172 	span_gradient_type> renderer_gradient_type;
3173 
3174 	gradient_func_type gradientFunc;
3175 	agg::trans_affine gradientMatrix;
3176 	interpolator_type spanInterpolator(gradientMatrix);
3177 	span_allocator_type spanAllocator;
3178 	color_array_type colorArray;
3179 
3180 	_MakeGradient(colorArray, diamond);
3181 
3182 	span_gradient_type spanGradient(spanInterpolator, gradientFunc, colorArray,
3183 		0, 100);
3184 
3185 	renderer_gradient_type gradientRenderer(fBaseRenderer, spanAllocator,
3186 		spanGradient);
3187 
3188 	gradientMatrix.reset();
3189 	gradientMatrix *= agg::trans_affine_translation(center.x, center.y);
3190 	gradientMatrix.invert();
3191 
3192 	//	_CalcLinearGradientTransform(start, end, gradientMatrix);
3193 
3194 	fRasterizer.reset();
3195 	fRasterizer.add_path(path);
3196 	agg::render_scanlines(fRasterizer, fPackedScanline, gradientRenderer);
3197 }
3198 
3199 
3200 // _FillPathGradientConic
3201 template<class VertexSource>
3202 void
3203 Painter::_FillPathGradientConic(VertexSource& path,
3204 	const BGradientConic& conic) const
3205 {
3206 	GTRACE("Painter::_FillPathGradientConic\n");
3207 
3208 	BPoint center = conic.Center();
3209 //	float radius = conic.Radius();
3210 
3211 	typedef agg::span_interpolator_linear<> interpolator_type;
3212 	typedef agg::pod_auto_array<agg::rgba8, 256> color_array_type;
3213 	typedef agg::span_allocator<agg::rgba8> span_allocator_type;
3214 	typedef agg::gradient_conic gradient_func_type;
3215 	typedef agg::span_gradient<agg::rgba8, interpolator_type,
3216 	gradient_func_type, color_array_type> span_gradient_type;
3217 	typedef agg::renderer_scanline_aa<renderer_base, span_allocator_type,
3218 	span_gradient_type> renderer_gradient_type;
3219 
3220 	gradient_func_type gradientFunc;
3221 	agg::trans_affine gradientMatrix;
3222 	interpolator_type spanInterpolator(gradientMatrix);
3223 	span_allocator_type spanAllocator;
3224 	color_array_type colorArray;
3225 
3226 	_MakeGradient(colorArray, conic);
3227 
3228 	span_gradient_type spanGradient(spanInterpolator, gradientFunc, colorArray,
3229 		0, 100);
3230 
3231 	renderer_gradient_type gradientRenderer(fBaseRenderer, spanAllocator,
3232 		spanGradient);
3233 
3234 	gradientMatrix.reset();
3235 	gradientMatrix *= agg::trans_affine_translation(center.x, center.y);
3236 	gradientMatrix.invert();
3237 
3238 	//	_CalcLinearGradientTransform(start, end, gradientMatrix);
3239 
3240 	fRasterizer.reset();
3241 	fRasterizer.add_path(path);
3242 	agg::render_scanlines(fRasterizer, fPackedScanline, gradientRenderer);
3243 }
3244