xref: /haiku/src/tests/servers/app/painter/Painter.cpp (revision 94c484bb7c27eba3871eb61c43da221c9ef691aa)
1 // Painter.cpp
2 
3 #include <stdio.h>
4 #include <string.h>
5 
6 #include <Bitmap.h>
7 #include <GraphicsDefs.h>
8 #include <Region.h>
9 
10 #include <agg_bezier_arc.h>
11 #include <agg_bounding_rect.h>
12 #include <agg_conv_curve.h>
13 #include <agg_conv_stroke.h>
14 #include <agg_ellipse.h>
15 #include <agg_path_storage.h>
16 #include <agg_rounded_rect.h>
17 #include <agg_span_image_filter_rgba32.h>
18 #include <agg_span_interpolator_linear.h>
19 
20 #include "LayerData.h"
21 
22 #include "AGGTextRenderer.h"
23 #include "DrawingMode.h"
24 #include "DrawingModeFactory.h"
25 #include "FontManager.h"
26 #include "PatternHandler.h"
27 #include "RenderingBuffer.h"
28 #include "ShapeConverter.h"
29 #include "ServerBitmap.h"
30 #include "ServerFont.h"
31 
32 #include "Painter.h"
33 
34 int
roundf(float v)35 roundf(float v)
36 {
37 	if (v >= 0.0)
38 		return (int)floorf(v + 0.5);
39 	else
40 		return (int)floorf(v - 0.5);
41 }
42 
43 // constructor
Painter()44 Painter::Painter()
45 	: fBuffer(NULL),
46 	  fPixelFormat(NULL),
47 	  fBaseRenderer(NULL),
48 	  fOutlineRenderer(NULL),
49 	  fOutlineRasterizer(NULL),
50 	  fScanline(NULL),
51 	  fRasterizer(NULL),
52 	  fRenderer(NULL),
53 	  fFontRendererSolid(NULL),
54 	  fFontRendererBin(NULL),
55 	  fLineProfile(),
56 	  fSubpixelPrecise(false),
57 	  fScale(1.0),
58 	  fPenSize(1.0),
59 	  fOrigin(0.0, 0.0),
60 	  fClippingRegion(NULL),
61 	  fDrawingMode(B_OP_COPY),
62 	  fAlphaSrcMode(B_PIXEL_ALPHA),
63 //	  fAlphaSrcMode(B_CONSTANT_ALPHA),
64 	  fAlphaFncMode(B_ALPHA_OVERLAY),
65 	  fPenLocation(0.0, 0.0),
66 	  fPatternHandler(new PatternHandler()),
67 	  fTextRenderer(new AGGTextRenderer()),
68 	  fLastFamilyAndStyle(0)
69 {
70 	if (fontserver)
71 		fFont = *fontserver->GetSystemPlain();
72 
73 	_UpdateFont();
74 	_UpdateLineWidth();
75 }
76 
77 // destructor
~Painter()78 Painter::~Painter()
79 {
80 	_MakeEmpty();
81 
82 	delete fClippingRegion;
83 	delete fPatternHandler;
84 	delete fTextRenderer;
85 }
86 
87 // #pragma mark -
88 
89 // AttachToBuffer
90 void
AttachToBuffer(RenderingBuffer * buffer)91 Painter::AttachToBuffer(RenderingBuffer* buffer)
92 {
93 	if (buffer && buffer->InitCheck() >= B_OK) {
94 		// clean up previous stuff
95 		_MakeEmpty();
96 
97 		fBuffer = new agg::rendering_buffer();
98 		fBuffer->attach((uint8*)buffer->Bits(),
99 						buffer->Width(),
100 						buffer->Height(),
101 						buffer->BytesPerRow());
102 
103 		fPixelFormat = new pixfmt(*fBuffer, fPatternHandler);
104 		fPixelFormat->set_drawing_mode(DrawingModeFactory::DrawingModeFor(fDrawingMode,
105 																		  fAlphaSrcMode,
106 																		  fAlphaFncMode,
107 																		  false));
108 
109 		fBaseRenderer = new renderer_base(*fPixelFormat);
110 
111 		// These are the AGG renderes and rasterizes which
112 		// will be used for stroking paths
113 rgb_color color = fPatternHandler->HighColor().GetColor32();
114 #if ALIASED_DRAWING
115 		fOutlineRenderer = new outline_renderer_type(*fBaseRenderer);
116 		fOutlineRasterizer = new outline_rasterizer_type(*fOutlineRenderer);
117 #else
118 		fOutlineRenderer = new outline_renderer_type(*fBaseRenderer, fLineProfile);
119 		fOutlineRasterizer = new outline_rasterizer_type(*fOutlineRenderer);
120 
121 		// attach our line profile to the renderer, it keeps a pointer
122 		fOutlineRenderer->profile(fLineProfile);
123 #endif
124 		// the renderer used for filling paths
125 		fRenderer = new renderer_type(*fBaseRenderer);
126 		fRasterizer = new rasterizer_type();
127 		fScanline = new scanline_type();
128 
129 #if ALIASED_DRAWING
130 		fRasterizer->gamma(agg::gamma_threshold(0.5));
131 #endif
132 
133 		// These are renderers needed for drawing text
134 		fFontRendererSolid = new font_renderer_solid_type(*fBaseRenderer);
135 		fFontRendererBin = new font_renderer_bin_type(*fBaseRenderer);
136 
137 		_SetRendererColor(fPatternHandler->HighColor().GetColor32());
138 		_RebuildClipping();
139 	}
140 }
141 
142 // DetachFromBuffer
143 void
DetachFromBuffer()144 Painter::DetachFromBuffer()
145 {
146 	_MakeEmpty();
147 }
148 
149 // SetDrawData
150 void
SetDrawData(const DrawData * data)151 Painter::SetDrawData(const DrawData* data)
152 {
153 	// for now...
154 	SetHighColor(data->highcolor.GetColor32());
155 	SetLowColor(data->lowcolor.GetColor32());
156 	SetScale(data->scale);
157 	SetPenSize(data->pensize);
158 //	fOrigin = data->coordOrigin;
159 	SetDrawingMode(data->draw_mode);
160 	SetBlendingMode(data->alphaSrcMode, data->alphaFncMode);
161 	SetPenLocation(data->penlocation);
162 	SetFont(data->font);
163 //	if (data->clipReg) {
164 //		ConstrainClipping(*data->clipReg);
165 //	}
166 	fPatternHandler->SetPattern(data->patt);
167 }
168 
169 // #pragma mark -
170 
171 // ConstrainClipping
172 void
ConstrainClipping(const BRegion & region)173 Painter::ConstrainClipping(const BRegion& region)
174 {
175 	// The idea is that if the clipping region was
176 	// never constrained, there is *no* clipping.
177 	// This is of course different from having
178 	// an *empty* clipping region.
179 	if (!fClippingRegion)
180 		fClippingRegion = new BRegion(region);
181 	else
182 		*fClippingRegion = region;
183 	_RebuildClipping();
184 }
185 
186 // SetHighColor
187 void
SetHighColor(const rgb_color & color)188 Painter::SetHighColor(const rgb_color& color)
189 {
190 	fPatternHandler->SetHighColor(color);
191 }
192 
193 // SetLowColor
194 void
SetLowColor(const rgb_color & color)195 Painter::SetLowColor(const rgb_color& color)
196 {
197 	fPatternHandler->SetLowColor(color);;
198 }
199 
200 // SetScale
201 void
SetScale(float scale)202 Painter::SetScale(float scale)
203 {
204 	if (fScale != scale) {
205 		fScale = scale;
206 		_RebuildClipping();
207 		_UpdateLineWidth();
208 	}
209 }
210 
211 // SetPenSize
212 void
SetPenSize(float size)213 Painter::SetPenSize(float size)
214 {
215 	if (fPenSize != size) {
216 		fPenSize = size;
217 		_UpdateLineWidth();
218 	}
219 }
220 
221 // SetOrigin
222 void
SetOrigin(const BPoint & origin)223 Painter::SetOrigin(const BPoint& origin)
224 {
225 	// NOTE: The BeBook says that the coordinate system
226 	// of a view cannot be changed during an update, because
227 	// it would mess up the clipping, and this is indeed
228 	// what would happen in this implementation as well.
229 	// I don't know yet what actually happens if you still
230 	// try to call SetOrigin() from within BView::Draw()
231 	fOrigin = origin;
232 	_RebuildClipping();
233 }
234 
235 // SetDrawingMode
236 void
SetDrawingMode(drawing_mode mode)237 Painter::SetDrawingMode(drawing_mode mode)
238 {
239 	if (fDrawingMode != mode) {
240 		fDrawingMode = mode;
241 		if (fPixelFormat) {
242 			fPixelFormat->set_drawing_mode(DrawingModeFactory::DrawingModeFor(fDrawingMode,
243 																			  fAlphaSrcMode,
244 																			  fAlphaFncMode));
245 		}
246 	}
247 }
248 
249 // SetBlendingMode
250 void
SetBlendingMode(source_alpha alphaSrcMode,alpha_function alphaFncMode)251 Painter::SetBlendingMode(source_alpha alphaSrcMode, alpha_function alphaFncMode)
252 {
253 	if (fAlphaSrcMode != alphaSrcMode || fAlphaFncMode != alphaFncMode) {
254 		fAlphaSrcMode = alphaSrcMode;
255 		fAlphaFncMode = alphaFncMode;
256 		if (fDrawingMode == B_OP_ALPHA && fPixelFormat) {
257 			fPixelFormat->set_drawing_mode(DrawingModeFactory::DrawingModeFor(fDrawingMode,
258 																			  fAlphaSrcMode,
259 																			  fAlphaFncMode));
260 		}
261 	}
262 }
263 
264 // SetPenLocation
265 void
SetPenLocation(const BPoint & location)266 Painter::SetPenLocation(const BPoint& location)
267 {
268 	fPenLocation = location;
269 }
270 
271 // SetFont
272 void
SetFont(const BFont & font)273 Painter::SetFont(const BFont& font)
274 {
275 	//fFont.SetFamilyAndStyle(font.GetFamily(), font.GetStyle());
276 	fFont.SetSpacing(font.Spacing());
277 	fFont.SetShear(font.Shear());
278 	fFont.SetRotation(font.Rotation());
279 	fFont.SetSize(font.Size());
280 
281 	_UpdateFont();
282 }
283 
284 // SetFont
285 void
SetFont(const ServerFont & font)286 Painter::SetFont(const ServerFont& font)
287 {
288 	fFont = font;
289 	_UpdateFont();
290 }
291 
292 // #pragma mark -
293 
294 // StrokeLine
295 BRect
StrokeLine(BPoint a,BPoint b,const pattern & p)296 Painter::StrokeLine(BPoint a, BPoint b, const pattern& p)
297 {
298 	_Transform(&a);
299 	_Transform(&b);
300 
301 	BRect touched(a, b);
302 
303 	// first, try an optimized version
304 	float penSize = _Transform(fPenSize);
305 	if (penSize == 1.0 &&
306 		(fDrawingMode == B_OP_COPY || fDrawingMode == B_OP_OVER)) {
307 		pattern pat = *fPatternHandler->GetR5Pattern();
308 		if (pat == B_SOLID_HIGH &&
309 			StraightLine(a, b, fPatternHandler->HighColor().GetColor32())) {
310 			SetPenLocation(b);
311 			return _Clipped(touched);
312 		} else if (pat == B_SOLID_LOW &&
313 			StraightLine(a, b, fPatternHandler->LowColor().GetColor32())) {
314 			SetPenLocation(b);
315 			return _Clipped(touched);
316 		}
317 	}
318 
319 	agg::path_storage path;
320 	path.move_to(a.x, a.y);
321 	path.line_to(b.x, b.y);
322 
323 	touched = _StrokePath(path, p);
324 
325 	SetPenLocation(b);
326 
327 	return _Clipped(touched);
328 }
329 
330 // StrokeLine
331 BRect
StrokeLine(BPoint b,const pattern & p)332 Painter::StrokeLine(BPoint b, const pattern& p)
333 {
334 	// TODO: move this function elsewhere
335 	return StrokeLine(fPenLocation, b);
336 }
337 
338 // StraightLine
339 bool
StraightLine(BPoint a,BPoint b,const rgb_color & c) const340 Painter::StraightLine(BPoint a, BPoint b, const rgb_color& c) const
341 {
342 	if (fBuffer) {
343 		if (a.x == b.x) {
344 			// vertical
345 			uint8* dst = fBuffer->row(0);
346 			uint32 bpr = fBuffer->stride();
347 			int32 x = (int32)a.x;
348 			dst += x * 4;
349 			int32 y1 = (int32)min_c(a.y, b.y);
350 			int32 y2 = (int32)max_c(a.y, b.y);
351 			// draw a line, iterate over clipping boxes
352 			fBaseRenderer->first_clip_box();
353 			do {
354 				if (fBaseRenderer->xmin() <= x &&
355 					fBaseRenderer->xmax() >= x) {
356 					int32 i = max_c(fBaseRenderer->ymin(), y1);
357 					int32 end = min_c(fBaseRenderer->ymax(), y2);
358 					uint8* handle = dst + i * bpr;
359 					for (; i <= end; i++) {
360 						handle[0] = c.blue;
361 						handle[1] = c.green;
362 						handle[2] = c.red;
363 						handle += bpr;
364 					}
365 				}
366 			} while (fBaseRenderer->next_clip_box());
367 
368 			return true;
369 
370 		} else if (a.y == b.y) {
371 			// horizontal
372 			uint8* dst = fBuffer->row(0);
373 			uint32 bpr = fBuffer->stride();
374 			int32 y = (int32)a.y;
375 			dst += y * bpr;
376 			int32 x1 = (int32)min_c(a.x, b.x);
377 			int32 x2 = (int32)max_c(a.x, b.x);
378 			// draw a line, iterate over clipping boxes
379 			fBaseRenderer->first_clip_box();
380 			do {
381 				if (fBaseRenderer->ymin() <= y &&
382 					fBaseRenderer->ymax() >= y) {
383 					int32 i = max_c(fBaseRenderer->xmin(), x1);
384 					int32 end = min_c(fBaseRenderer->xmax(), x2);
385 					uint8* handle = dst + i * 4;
386 					for (; i <= end; i++) {
387 						handle[0] = c.blue;
388 						handle[1] = c.green;
389 						handle[2] = c.red;
390 						handle += 4;
391 					}
392 				}
393 			} while (fBaseRenderer->next_clip_box());
394 
395 			return true;
396 		}
397 	}
398 	return false;
399 }
400 
401 // #pragma mark -
402 
403 // StrokeTriangle
404 void
StrokeTriangle(BPoint pt1,BPoint pt2,BPoint pt3,const pattern & p) const405 Painter::StrokeTriangle(BPoint pt1, BPoint pt2, BPoint pt3, const pattern& p) const
406 {
407 	_DrawTriangle(pt1, pt2, pt3, p, false);
408 }
409 
410 // FillTriangle
411 void
FillTriangle(BPoint pt1,BPoint pt2,BPoint pt3,const pattern & p) const412 Painter::FillTriangle(BPoint pt1, BPoint pt2, BPoint pt3, const pattern& p) const
413 {
414 	_DrawTriangle(pt1, pt2, pt3, p, true);
415 }
416 
417 // StrokePolygon
418 void
StrokePolygon(const BPoint * ptArray,int32 numPts,bool closed,const pattern & p) const419 Painter::StrokePolygon(const BPoint* ptArray, int32 numPts,
420 					   bool closed, const pattern& p) const
421 {
422 	_DrawPolygon(ptArray, numPts, closed, p, false);
423 }
424 
425 // FillPolygon
426 void
FillPolygon(const BPoint * ptArray,int32 numPts,bool closed,const pattern & p) const427 Painter::FillPolygon(const BPoint* ptArray, int32 numPts,
428 					   bool closed, const pattern& p) const
429 {
430 	_DrawPolygon(ptArray, numPts, closed, p, true);
431 }
432 
433 // StrokeBezier
434 void
StrokeBezier(const BPoint * controlPoints,const pattern & p) const435 Painter::StrokeBezier(const BPoint* controlPoints, const pattern& p) const
436 {
437 	agg::path_storage curve;
438 
439 	BPoint p1(controlPoints[0]);
440 	BPoint p2(controlPoints[1]);
441 	BPoint p3(controlPoints[2]);
442 	BPoint p4(controlPoints[3]);
443 	_Transform(&p1);
444 	_Transform(&p2);
445 	_Transform(&p3);
446 	_Transform(&p4);
447 
448 	curve.move_to(p1.x, p1.y);
449 	curve.curve4(p1.x, p1.y,
450 				 p2.x, p2.y,
451 				 p3.x, p3.y);
452 
453 
454 	agg::conv_curve<agg::path_storage> path(curve);
455 
456 	_StrokePath(path, p);
457 }
458 
459 // FillBezier
460 void
FillBezier(const BPoint * controlPoints,const pattern & p) const461 Painter::FillBezier(const BPoint* controlPoints, const pattern& p) const
462 {
463 	agg::path_storage curve;
464 
465 	BPoint p1(controlPoints[0]);
466 	BPoint p2(controlPoints[1]);
467 	BPoint p3(controlPoints[2]);
468 	BPoint p4(controlPoints[3]);
469 	_Transform(&p1);
470 	_Transform(&p2);
471 	_Transform(&p3);
472 	_Transform(&p4);
473 
474 	curve.move_to(p1.x, p1.y);
475 	curve.curve4(p1.x, p1.y,
476 				 p2.x, p2.y,
477 				 p3.x, p3.y);
478 	curve.close_polygon();
479 
480 	agg::conv_curve<agg::path_storage> path(curve);
481 
482 	_FillPath(path, p);
483 }
484 
485 // StrokeShape
486 void
StrokeShape(BShape * shape,const pattern & p) const487 Painter::StrokeShape(/*const */BShape* shape, const pattern& p) const
488 {
489 	_DrawShape(shape, p, false);
490 }
491 
492 // FillShape
493 void
FillShape(BShape * shape,const pattern & p) const494 Painter::FillShape(/*const */BShape* shape, const pattern& p) const
495 {
496 	_DrawShape(shape, p, true);
497 }
498 
499 // StrokeRect
500 BRect
StrokeRect(const BRect & r,const pattern & p) const501 Painter::StrokeRect(const BRect& r, const pattern& p) const
502 {
503 	BPoint a(r.left, r.top);
504 	BPoint b(r.right, r.bottom);
505 	_Transform(&a);
506 	_Transform(&b);
507 
508 	// first, try an optimized version
509 	float penSize = _Transform(fPenSize);
510 	if (penSize == 1.0 &&
511 		(fDrawingMode == B_OP_COPY || fDrawingMode == B_OP_OVER)) {
512 // TODO: fix me
513 //		pattern p = *fPatternHandler->GetR5Pattern();
514 		if (p == B_SOLID_HIGH) {
515 			BRect rect(a, b);
516 			StrokeRect(rect,
517 					   fPatternHandler->HighColor().GetColor32());
518 			return _Clipped(rect);
519 		} else if (p == B_SOLID_LOW) {
520 			BRect rect(a, b);
521 			StrokeRect(rect,
522 					   fPatternHandler->LowColor().GetColor32());
523 			return _Clipped(rect);
524 		}
525 	}
526 
527 	agg::path_storage path;
528 	path.move_to(a.x, a.y);
529 	path.line_to(b.x, a.y);
530 	path.line_to(b.x, b.y);
531 	path.line_to(a.x, b.y);
532 	path.close_polygon();
533 
534 	return _StrokePath(path, p);
535 }
536 
537 // StrokeRect
538 void
StrokeRect(const BRect & r,const rgb_color & c) const539 Painter::StrokeRect(const BRect& r, const rgb_color& c) const
540 {
541 	StraightLine(BPoint(r.left, r.top),
542 				 BPoint(r.right - 1, r.top), c);
543 	StraightLine(BPoint(r.right, r.top),
544 				 BPoint(r.right, r.bottom - 1), c);
545 	StraightLine(BPoint(r.right, r.bottom),
546 				 BPoint(r.left + 1, r.bottom), c);
547 	StraightLine(BPoint(r.left, r.bottom),
548 				 BPoint(r.left, r.top + 1), c);
549 }
550 
551 // FillRect
552 BRect
FillRect(const BRect & r,const pattern & p) const553 Painter::FillRect(const BRect& r, const pattern& p) const
554 {
555 	BPoint a(r.left, r.top);
556 	BPoint b(r.right, r.bottom);
557 	_Transform(&a, false);
558 	_Transform(&b, false);
559 
560 	// first, try an optimized version
561 	if (fDrawingMode == B_OP_COPY || fDrawingMode == B_OP_OVER) {
562 		pattern pat = *fPatternHandler->GetR5Pattern();
563 		if (pat == B_SOLID_HIGH) {
564 			BRect rect(a, b);
565 			FillRect(rect, fPatternHandler->HighColor().GetColor32());
566 			return _Clipped(rect);
567 		} else if (pat == B_SOLID_LOW) {
568 			BRect rect(a, b);
569 			FillRect(rect, fPatternHandler->LowColor().GetColor32());
570 			return _Clipped(rect);
571 		}
572 	}
573 
574 	// account for stricter interpretation of coordinates in AGG
575 	// the rectangle ranges from the top-left (.0, .0)
576 	// to the bottom-right (.9999, .9999) corner of pixels
577 	b.x += 1.0;
578 	b.y += 1.0;
579 
580 	agg::path_storage path;
581 	path.move_to(a.x, a.y);
582 	path.line_to(b.x, a.y);
583 	path.line_to(b.x, b.y);
584 	path.line_to(a.x, b.y);
585 	path.close_polygon();
586 
587 	return _FillPath(path, p);
588 }
589 
590 // FillRect
591 void
FillRect(const BRect & r,const rgb_color & c) const592 Painter::FillRect(const BRect& r, const rgb_color& c) const
593 {
594 	if (fBuffer) {
595 		uint8* dst = fBuffer->row(0);
596 		uint32 bpr = fBuffer->stride();
597 		int32 left = (int32)r.left;
598 		int32 top = (int32)r.top;
599 		int32 right = (int32)r.right;
600 		int32 bottom = (int32)r.bottom;
601 		// fill rects, iterate over clipping boxes
602 		fBaseRenderer->first_clip_box();
603 		do {
604 			int32 x1 = max_c(fBaseRenderer->xmin(), left);
605 			int32 x2 = min_c(fBaseRenderer->xmax(), right);
606 			if (x1 <= x2) {
607 				int32 y1 = max_c(fBaseRenderer->ymin(), top);
608 				int32 y2 = min_c(fBaseRenderer->ymax(), bottom);
609 				uint8* offset = dst + x1 * 4;
610 				for (; y1 <= y2; y1++) {
611 					uint8* handle = offset + y1 * bpr;
612 					for (int32 x = x1; x <= x2; x++) {
613 						handle[0] = c.blue;
614 						handle[1] = c.green;
615 						handle[2] = c.red;
616 						handle += 4;
617 					}
618 				}
619 			}
620 		} while (fBaseRenderer->next_clip_box());
621 	}
622 }
623 
624 // StrokeRoundRect
625 void
StrokeRoundRect(const BRect & r,float xRadius,float yRadius,const pattern & p) const626 Painter::StrokeRoundRect(const BRect& r, float xRadius, float yRadius,
627 						 const pattern& p) const
628 {
629 	BPoint lt(r.left, r.top);
630 	BPoint rb(r.right, r.bottom);
631 	_Transform(&lt);
632 	_Transform(&rb);
633 
634 	_Transform(&xRadius);
635 	_Transform(&yRadius);
636 
637 	agg::rounded_rect rect;
638 	rect.rect(lt.x, lt.y, rb.x, rb.y);
639 	rect.radius(xRadius, yRadius);
640 
641 	_StrokePath(rect, p);
642 }
643 
644 // FillRoundRect
645 void
FillRoundRect(const BRect & r,float xRadius,float yRadius,const pattern & p) const646 Painter::FillRoundRect(const BRect& r, float xRadius, float yRadius,
647 					   const pattern& p) const
648 {
649 	BPoint lt(r.left, r.top);
650 	BPoint rb(r.right, r.bottom);
651 	_Transform(&lt, false);
652 	_Transform(&rb, false);
653 
654 	// account for stricter interpretation of coordinates in AGG
655 	// the rectangle ranges from the top-left (.0, .0)
656 	// to the bottom-right (.9999, .9999) corner of pixels
657 	rb.x += 1.0;
658 	rb.y += 1.0;
659 
660 	_Transform(&xRadius);
661 	_Transform(&yRadius);
662 
663 	agg::rounded_rect rect;
664 	rect.rect(lt.x, lt.y, rb.x, rb.y);
665 	rect.radius(xRadius, yRadius);
666 
667 	_FillPath(rect, p);
668 }
669 
670 // StrokeEllipse
671 void
StrokeEllipse(BPoint center,float xRadius,float yRadius,const pattern & p) const672 Painter::StrokeEllipse(BPoint center, float xRadius, float yRadius,
673 					   const pattern& p) const
674 {
675 	_DrawEllipse(center, xRadius, yRadius, p, false);
676 }
677 
678 // FillEllipse
679 void
FillEllipse(BPoint center,float xRadius,float yRadius,const pattern & p) const680 Painter::FillEllipse(BPoint center, float xRadius, float yRadius,
681 					 const pattern& p) const
682 {
683 	_DrawEllipse(center, xRadius, yRadius, p, true);
684 }
685 
686 // StrokeArc
687 void
StrokeArc(BPoint center,float xRadius,float yRadius,float angle,float span,const pattern & p) const688 Painter::StrokeArc(BPoint center, float xRadius, float yRadius,
689 				   float angle, float span, const pattern& p) const
690 {
691 	_Transform(&center);
692 	_Transform(&xRadius);
693 	_Transform(&yRadius);
694 
695 	double angleRad = (angle * PI) / 180.0;
696 	double spanRad = (span * PI) / 180.0;
697 	agg::bezier_arc arc(center.x, center.y, xRadius, yRadius,
698 						-angleRad, -spanRad);
699 
700 	agg::conv_curve<agg::bezier_arc> path(arc);
701 
702 	_StrokePath(path, p);
703 }
704 
705 // FillArc
706 void
FillArc(BPoint center,float xRadius,float yRadius,float angle,float span,const pattern & p) const707 Painter::FillArc(BPoint center, float xRadius, float yRadius,
708 				 float angle, float span, const pattern& p) const
709 {
710 	_Transform(&center);
711 	_Transform(&xRadius);
712 	_Transform(&yRadius);
713 
714 	double angleRad = (angle * PI) / 180.0;
715 	double spanRad = (span * PI) / 180.0;
716 	agg::bezier_arc arc(center.x, center.y, xRadius, yRadius,
717 						-angleRad, -spanRad);
718 
719 	agg::conv_curve<agg::bezier_arc> segmentedArc(arc);
720 
721 	agg::path_storage path;
722 
723 	// build a new path by starting at the center point,
724 	// then traversing the arc, then going back to the center
725 	path.move_to(center.x, center.y);
726 
727 	segmentedArc.rewind(0);
728 	double x;
729 	double y;
730 	unsigned cmd = segmentedArc.vertex(&x, &y);
731 	while (!agg::is_stop(cmd)) {
732 		path.line_to(x, y);
733 		cmd = segmentedArc.vertex(&x, &y);
734 	}
735 
736 	path.close_polygon();
737 
738 	_FillPath(path, p);
739 }
740 
741 // #pragma mark -
742 
743 // DrawChar
744 BRect
DrawChar(char aChar)745 Painter::DrawChar(char aChar)
746 {
747 	// TODO: to be moved elsewhere
748 	return DrawChar(aChar, fPenLocation);
749 }
750 
751 // DrawChar
752 BRect
DrawChar(char aChar,BPoint baseLine)753 Painter::DrawChar(char aChar, BPoint baseLine)
754 {
755 	// TODO: to be moved elsewhere
756 	char wrapper[2];
757 	wrapper[0] = aChar;
758 	wrapper[1] = 0;
759 	return DrawString(wrapper, 1, baseLine);
760 }
761 
762 // DrawString
763 BRect
DrawString(const char * utf8String,uint32 length,const escapement_delta * delta)764 Painter::DrawString(const char* utf8String, uint32 length,
765 					const escapement_delta* delta)
766 {
767 	// TODO: to be moved elsewhere
768 	return DrawString(utf8String, length, fPenLocation, delta);
769 }
770 
771 // DrawString
772 BRect
DrawString(const char * utf8String,uint32 length,BPoint baseLine,const escapement_delta * delta)773 Painter::DrawString(const char* utf8String, uint32 length,
774 					BPoint baseLine, const escapement_delta* delta)
775 {
776 	BRect bounds(0.0, 0.0, -1.0, -1.0);
777 	fPatternHandler->SetPattern(B_SOLID_HIGH);
778 
779 	if (fBuffer) {
780 
781 		Transformable transform;
782 		transform.ShearBy(B_ORIGIN, (90.0 - fFont.Shear()) * PI / 180.0, 0.0);
783 		transform.RotateBy(B_ORIGIN, -fFont.Rotation() * PI / 180.0);
784 		transform.TranslateBy(baseLine);
785 		transform.ScaleBy(B_ORIGIN, fScale, fScale);
786 		transform.TranslateBy(fOrigin);
787 
788 		BRect clippingFrame;
789 		if (fClippingRegion)
790 			clippingFrame = _Transform(fClippingRegion->Frame());
791 
792 		bounds = fTextRenderer->RenderString(utf8String,
793 											 length,
794 											 fFontRendererSolid,
795 											 fFontRendererBin,
796 											 transform,
797 											 clippingFrame,
798 											 false,
799 											 &fPenLocation);
800 		// pen location is not transformed in quite the same way,
801 		// or transformations would add up
802 		transform.Reset();
803 		transform.RotateBy(B_ORIGIN, -fFont.Rotation());
804 		transform.TranslateBy(baseLine);
805 		transform.Transform(&fPenLocation);
806 	}
807 	return _Clipped(bounds);
808 }
809 
810 // DrawString
811 BRect
DrawString(const char * utf8String,const escapement_delta * delta)812 Painter::DrawString(const char* utf8String, const escapement_delta* delta)
813 {
814 	// TODO: to be moved elsewhere
815 	return DrawString(utf8String, strlen(utf8String), fPenLocation, delta);
816 }
817 
818 // DrawString
819 BRect
DrawString(const char * utf8String,BPoint baseLine,const escapement_delta * delta)820 Painter::DrawString(const char* utf8String, BPoint baseLine,
821 					const escapement_delta* delta)
822 {
823 	// TODO: to be moved elsewhere
824 	return DrawString(utf8String, strlen(utf8String), baseLine, delta);
825 }
826 
827 // #pragma mark -
828 
829 // DrawBitmap
830 void
DrawBitmap(const BBitmap * bitmap,BRect bitmapRect,BRect viewRect) const831 Painter::DrawBitmap(const BBitmap* bitmap,
832 					BRect bitmapRect, BRect viewRect) const
833 {
834 	if (bitmap && bitmap->IsValid()) {
835 		// the native bitmap coordinate system
836 		// (can have left top corner offset)
837 		BRect actualBitmapRect(bitmap->Bounds());
838 
839 		agg::rendering_buffer srcBuffer;
840 		srcBuffer.attach((uint8*)bitmap->Bits(),
841 						 (uint32)actualBitmapRect.IntegerWidth() + 1,
842 						 (uint32)actualBitmapRect.IntegerHeight() + 1,
843 						 bitmap->BytesPerRow());
844 
845 		_DrawBitmap(srcBuffer, bitmap->ColorSpace(), actualBitmapRect, bitmapRect, viewRect);
846 	}
847 }
848 
849 // DrawBitmap
850 void
DrawBitmap(const ServerBitmap * bitmap,BRect bitmapRect,BRect viewRect) const851 Painter::DrawBitmap(const ServerBitmap* bitmap,
852 					BRect bitmapRect, BRect viewRect) const
853 {
854 	if (bitmap && bitmap->InitCheck()) {
855 		// the native bitmap coordinate system
856 		BRect actualBitmapRect(bitmap->Bounds());
857 
858 		agg::rendering_buffer srcBuffer;
859 		srcBuffer.attach(bitmap->Bits(),
860 						 bitmap->Width(),
861 						 bitmap->Height(),
862 						 bitmap->BytesPerRow());
863 
864 		_DrawBitmap(srcBuffer, bitmap->ColorSpace(), actualBitmapRect, bitmapRect, viewRect);
865 	}
866 }
867 
868 // #pragma mark -
869 
870 // FillRegion
871 void
FillRegion(const BRegion * region,const pattern & p=B_SOLID_HIGH) const872 Painter::FillRegion(const BRegion* region, const pattern& p = B_SOLID_HIGH) const
873 {
874 	BRegion copy(*region);
875 	int32 count = copy.CountRects();
876 	for (int32 i = 0; i < count; i++) {
877 		FillRect(copy.RectAt(i), p);
878 	}
879 }
880 
881 // InvertRect
882 void
InvertRect(const BRect & r) const883 Painter::InvertRect(const BRect& r) const
884 {
885 	BRegion region(r);
886 	if (fClippingRegion) {
887 		region.IntersectWith(fClippingRegion);
888 	}
889 	// implementation only for B_RGB32 at the moment
890 	int32 count = region.CountRects();
891 	for (int32 i = 0; i < count; i++) {
892 		BRect r = region.RectAt(i);
893 		_Transform(&r);
894 		_InvertRect32(r);
895 	}
896 }
897 
898 // BoundingBox
899 BRect
BoundingBox(const char * utf8String,uint32 length,const BPoint & baseLine) const900 Painter::BoundingBox(const char* utf8String, uint32 length,
901 					 const BPoint& baseLine) const
902 {
903 	Transformable transform;
904 	transform.TranslateBy(baseLine);
905 
906 	BRect dummy;
907 	return fTextRenderer->RenderString(utf8String,
908 									length,
909 									fFontRendererSolid,
910 									fFontRendererBin,
911 									transform, dummy, true);
912 }
913 
914 // #pragma mark -
915 
916 // _MakeEmpty
917 void
_MakeEmpty()918 Painter::_MakeEmpty()
919 {
920 	delete fBuffer;
921 	fBuffer = NULL;
922 
923 	delete fPixelFormat;
924 	fPixelFormat = NULL;
925 
926 	delete fBaseRenderer;
927 	fBaseRenderer = NULL;
928 
929 	delete fOutlineRenderer;
930 	fOutlineRenderer = NULL;
931 
932 	delete fOutlineRasterizer;
933 	fOutlineRasterizer = NULL;
934 
935 	delete fScanline;
936 	fScanline = NULL;
937 
938 	delete fRasterizer;
939 	fRasterizer = NULL;
940 
941 	delete fRenderer;
942 	fRenderer = NULL;
943 
944 	delete fFontRendererSolid;
945 	fFontRendererSolid = NULL;
946 
947 	delete fFontRendererBin;
948 	fFontRendererBin = NULL;
949 }
950 
951 // _Transform
952 void
_Transform(BPoint * point,bool centerOffset) const953 Painter::_Transform(BPoint* point, bool centerOffset) const
954 {
955 	*point += fOrigin;
956 	// rounding
957 	if (!fSubpixelPrecise) {
958 		// TODO: validate usage of floor() for values < 0
959 		point->x = floorf(point->x);
960 		point->y = floorf(point->y);
961 	}
962 	// apply the scale
963 	point->x *= fScale;
964 	point->y *= fScale;
965 	// this code is supposed to move coordinates to the center of pixels,
966 	// as AGG considers (0,0) to be the "upper left corner" of a pixel,
967 	// but BViews are less strict on those details
968 	if (centerOffset) {
969 		point->x += 0.5;
970 		point->y += 0.5;
971 	}
972 }
973 
974 // _Transform
975 BPoint
_Transform(const BPoint & point,bool centerOffset) const976 Painter::_Transform(const BPoint& point, bool centerOffset) const
977 {
978 	BPoint ret = point;
979 	_Transform(&ret, centerOffset);
980 	return ret;
981 }
982 
983 // _Transform
984 void
_Transform(float * width) const985 Painter::_Transform(float* width) const
986 {
987 	*width *= fScale;
988 	if (*width < 1)
989 		*width = 1;
990 }
991 
992 // _Transform
993 float
_Transform(const float & width) const994 Painter::_Transform(const float& width) const
995 {
996 	float w = width * fScale;
997 	if (w < 1)
998 		w = 1;
999 	return w;
1000 }
1001 
1002 // _Transform
1003 void
_Transform(BRect * rect) const1004 Painter::_Transform(BRect* rect) const
1005 {
1006 	// TODO integrate this function more
1007 	rect->right++;
1008 	rect->bottom++;
1009 	rect->left += fOrigin.x;
1010 	rect->top += fOrigin.y;
1011 	rect->right += fOrigin.x;
1012 	rect->bottom += fOrigin.y;
1013 	rect->left *= fScale;
1014 	rect->top *= fScale;
1015 	rect->right *= fScale;
1016 	rect->bottom *= fScale;
1017 	rect->right--;
1018 	rect->bottom--;
1019 }
1020 
1021 // _Transform
1022 BRect
_Transform(const BRect & rect) const1023 Painter::_Transform(const BRect& rect) const
1024 {
1025 	BRect ret = rect;
1026 	_Transform(&ret);
1027 	return ret;
1028 }
1029 
1030 // _Clipped
1031 BRect
_Clipped(const BRect & rect) const1032 Painter::_Clipped(const BRect& rect) const
1033 {
1034 	if (rect.IsValid() && fClippingRegion)
1035 		return rect & _Transform(fClippingRegion->Frame());
1036 	return rect;
1037 }
1038 
1039 // #pragma mark -
1040 
1041 // _RebuildClipping
1042 void
_RebuildClipping()1043 Painter::_RebuildClipping()
1044 {
1045 	if (fBaseRenderer) {
1046 		fBaseRenderer->reset_clipping(!fClippingRegion);
1047 		if (fClippingRegion) {
1048 			int32 count = fClippingRegion->CountRects();
1049 			for (int32 i = 0; i < count; i++) {
1050 				BRect r = fClippingRegion->RectAt(i);
1051 				// NOTE: The rounding here appears to give somewhat
1052 				// different results compared to Be's implementation,
1053 				// though I was unable to figure out the difference
1054 				BPoint lt(r.LeftTop());
1055 				BPoint rb(r.RightBottom());
1056 				// offset to bottom right corner of pixel before transformation
1057 				rb += BPoint(1.0, 1.0);
1058 				// apply transformation
1059 				lt += fOrigin;
1060 				lt.x *= fScale;
1061 				lt.y *= fScale;
1062 				rb += fOrigin;
1063 				rb.x *= fScale;
1064 				rb.y *= fScale;
1065 				// undo offset to bottom right corner after transformation
1066 				rb -= BPoint(1.0, 1.0);
1067 //				fBaseRenderer->add_clip_box(floorf(lt.x),
1068 //											floorf(lt.y),
1069 //											ceilf(rb.x),
1070 //											ceilf(rb.y));
1071 				fBaseRenderer->add_clip_box(roundf(lt.x),
1072 											roundf(lt.y),
1073 											roundf(rb.x),
1074 											roundf(rb.y));
1075 			}
1076 		}
1077 	}
1078 }
1079 
1080 // _UpdateFont
1081 void
_UpdateFont()1082 Painter::_UpdateFont()
1083 {
1084 	if (fLastFamilyAndStyle != fFont.GetFamilyAndStyle()) {
1085 		fLastFamilyAndStyle = fFont.GetFamilyAndStyle();
1086 
1087 		bool success = false;
1088 		success = fTextRenderer->SetFont(fFont);
1089 		if (!success)
1090 			fprintf(stderr, "unable to set font\n");
1091 	}
1092 
1093 	fTextRenderer->SetPointSize(fFont.Size());
1094 }
1095 
1096 // _UpdateLineWidth
1097 void
_UpdateLineWidth()1098 Painter::_UpdateLineWidth()
1099 {
1100 	float width = fPenSize;
1101 	_Transform(&width);
1102 
1103 	fLineProfile.width(width);
1104 }
1105 
1106 // #pragma mark -
1107 
1108 // _DrawTriangle
1109 inline void
_DrawTriangle(BPoint pt1,BPoint pt2,BPoint pt3,const pattern & p,bool fill) const1110 Painter::_DrawTriangle(BPoint pt1, BPoint pt2, BPoint pt3,
1111 					   const pattern& p, bool fill) const
1112 {
1113 	_Transform(&pt1);
1114 	_Transform(&pt2);
1115 	_Transform(&pt3);
1116 
1117 	agg::path_storage path;
1118 
1119 	path.move_to(pt1.x, pt1.y);
1120 	path.line_to(pt2.x, pt2.y);
1121 	path.line_to(pt3.x, pt3.y);
1122 
1123 	path.close_polygon();
1124 
1125 	if (fill)
1126 		_FillPath(path, p);
1127 	else
1128 		_StrokePath(path, p);
1129 }
1130 
1131 // _DrawEllipse
1132 inline void
_DrawEllipse(BPoint center,float xRadius,float yRadius,const pattern & p,bool fill) const1133 Painter::_DrawEllipse(BPoint center, float xRadius, float yRadius,
1134 					  const pattern& p, bool fill) const
1135 {
1136 	// TODO: I think the conversion and the offset of
1137 	// pixel centers might not be correct here, and it
1138 	// might even be necessary to treat Fill and Stroke
1139 	// differently, as with Fill-/StrokeRect().
1140 	_Transform(&center);
1141 	_Transform(&xRadius);
1142 	_Transform(&yRadius);
1143 
1144 	float width = fPenSize;
1145 	_Transform(&width);
1146 
1147 	int32 divisions = (int32)max_c(12, ((xRadius + yRadius) * PI) / 2 * (int32)width);
1148 
1149 	agg::ellipse path(center.x, center.y, xRadius, yRadius, divisions);
1150 
1151 	if (fill)
1152 		_FillPath(path, p);
1153 	else
1154 		_StrokePath(path, p);
1155 }
1156 
1157 // _DrawShape
1158 inline void
_DrawShape(BShape * shape,const pattern & p,bool fill) const1159 Painter::_DrawShape(/*const */BShape* shape, const pattern& p, bool fill) const
1160 {
1161 	// TODO: untested
1162 	agg::path_storage path;
1163 	ShapeConverter converter(&path);
1164 
1165 	// account for our view coordinate system
1166 	converter.ScaleBy(B_ORIGIN, fScale, fScale);
1167 	converter.TranslateBy(fOrigin);
1168 	// offset locations to center of pixels
1169 	converter.TranslateBy(BPoint(0.5, 0.5));
1170 
1171 	converter.Iterate(shape);
1172 
1173 	if (fill)
1174 		_FillPath(path, p);
1175 	else
1176 		_StrokePath(path, p);
1177 }
1178 
1179 // _DrawPolygon
1180 inline void
_DrawPolygon(const BPoint * ptArray,int32 numPts,bool closed,const pattern & p,bool fill) const1181 Painter::_DrawPolygon(const BPoint* ptArray, int32 numPts,
1182 					  bool closed, const pattern& p, bool fill) const
1183 {
1184 	if (numPts > 0) {
1185 
1186 		agg::path_storage path;
1187 		BPoint point = _Transform(*ptArray);
1188 		path.move_to(point.x, point.y);
1189 
1190 		for (int32 i = 1; i < numPts; i++) {
1191 			ptArray++;
1192 			point = _Transform(*ptArray);
1193 			path.line_to(point.x, point.y);
1194 		}
1195 
1196 		if (closed)
1197 			path.close_polygon();
1198 
1199 		if (fill)
1200 			_FillPath(path, p);
1201 		else
1202 			_StrokePath(path, p);
1203 	}
1204 }
1205 
1206 // _DrawBitmap
1207 void
_DrawBitmap(const agg::rendering_buffer & srcBuffer,color_space format,BRect actualBitmapRect,BRect bitmapRect,BRect viewRect) const1208 Painter::_DrawBitmap(const agg::rendering_buffer& srcBuffer, color_space format,
1209 					 BRect actualBitmapRect, BRect bitmapRect, BRect viewRect) const
1210 {
1211 	switch (format) {
1212 		case B_RGB32:
1213 		case B_RGBA32:
1214 			_DrawBitmap32(srcBuffer, actualBitmapRect, bitmapRect, viewRect);
1215 			break;
1216 		default:
1217 fprintf(stderr, "Painter::_DrawBitmap() - non-native colorspace: %d\n", format);
1218 #ifdef __HAIKU__
1219 			// TODO: this is only a temporary implementation,
1220 			// to really handle other colorspaces, one would
1221 			// rather do the conversion with much less overhead,
1222 			// for example in the nn filter (hm), or in the
1223 			// scanline generator
1224 			BBitmap temp(actualBitmapRect, 0, B_RGB32);
1225 			status_t err = temp.ImportBits(srcBuffer.buf(),
1226 										   srcBuffer.height() * srcBuffer.stride(),
1227 										   srcBuffer.stride(),
1228 										   0, format);
1229 			if (err >= B_OK) {
1230 				agg::rendering_buffer convertedBuffer;
1231 				convertedBuffer.attach((uint8*)temp.Bits(),
1232 									   (uint32)actualBitmapRect.IntegerWidth() + 1,
1233 									   (uint32)actualBitmapRect.IntegerHeight() + 1,
1234 									   temp.BytesPerRow());
1235 				_DrawBitmap32(convertedBuffer, actualBitmapRect, bitmapRect, viewRect);
1236 			} else {
1237 fprintf(stderr, "Painter::_DrawBitmap() - colorspace conversion failed: %s\n", strerror(err));
1238 			}
1239 #endif // __HAIKU__
1240 			break;
1241 	}
1242 }
1243 
1244 // _DrawBitmap32
1245 void
_DrawBitmap32(const agg::rendering_buffer & srcBuffer,BRect actualBitmapRect,BRect bitmapRect,BRect viewRect) const1246 Painter::_DrawBitmap32(const agg::rendering_buffer& srcBuffer,
1247 					   BRect actualBitmapRect, BRect bitmapRect, BRect viewRect) const
1248 {
1249 typedef agg::span_allocator<agg::rgba8> span_alloc_type;
1250 typedef agg::span_interpolator_linear<> interpolator_type;
1251 typedef agg::span_image_filter_rgba32_nn<agg::order_bgra32,
1252 										 interpolator_type> span_gen_type;
1253 typedef agg::renderer_scanline_aa<renderer_base, span_gen_type> image_renderer_type;
1254 
1255 	if (bitmapRect.IsValid() && bitmapRect.Intersects(actualBitmapRect)
1256 		&& viewRect.IsValid()) {
1257 
1258 		// compensate for the lefttop offset the actualBitmapRect might have
1259 // NOTE: I have no clue why enabling the next call gives a wrong result!
1260 // According to the BeBook, bitmapRect is supposed to be in native
1261 // bitmap space!
1262 //		bitmapRect.OffsetBy(-actualBitmapRect.left, -actualBitmapRect.top);
1263 		actualBitmapRect.OffsetBy(-actualBitmapRect.left, -actualBitmapRect.top);
1264 
1265 		// calculate the scaling
1266 		double xScale = (viewRect.Width() + 1) / (bitmapRect.Width() + 1);
1267 		double yScale = (viewRect.Height() + 1) / (bitmapRect.Height() + 1);
1268 
1269 		// constrain rect to passed bitmap bounds
1270 		// and transfer the changes to the viewRect
1271 		if (bitmapRect.left < actualBitmapRect.left) {
1272 			float diff = actualBitmapRect.left - bitmapRect.left;
1273 			viewRect.left += diff * xScale;
1274 			bitmapRect.left = actualBitmapRect.left;
1275 		}
1276 		if (bitmapRect.top < actualBitmapRect.top) {
1277 			float diff = actualBitmapRect.top - bitmapRect.top;
1278 			viewRect.top += diff;
1279 			bitmapRect.top = actualBitmapRect.top;
1280 		}
1281 		if (bitmapRect.right > actualBitmapRect.right) {
1282 			float diff = bitmapRect.right - actualBitmapRect.right;
1283 			viewRect.right -= diff;
1284 			bitmapRect.right = actualBitmapRect.right;
1285 		}
1286 		if (bitmapRect.bottom > actualBitmapRect.bottom) {
1287 			float diff = bitmapRect.right - actualBitmapRect.bottom;
1288 			viewRect.bottom -= diff;
1289 			bitmapRect.bottom = actualBitmapRect.bottom;
1290 		}
1291 
1292 		float xOffset = viewRect.left - (bitmapRect.left * xScale);
1293 		float yOffset = viewRect.top - (bitmapRect.top * yScale);
1294 
1295 		agg::trans_affine srcMatrix;
1296 //		srcMatrix *= agg::trans_affine_translation(-actualBitmapRect.left, -actualBitmapRect.top);
1297 		srcMatrix *= agg::trans_affine_scaling(fScale, fScale);
1298 		srcMatrix *= agg::trans_affine_translation(fOrigin.x, fOrigin.y);
1299 
1300 		agg::trans_affine imgMatrix;
1301 		imgMatrix *= agg::trans_affine_scaling(xScale, yScale);
1302 		imgMatrix *= agg::trans_affine_translation(xOffset, yOffset);
1303 		imgMatrix *= agg::trans_affine_scaling(fScale, fScale);
1304 		imgMatrix *= agg::trans_affine_translation(fOrigin.x, fOrigin.y);
1305 		imgMatrix.invert();
1306 
1307 		span_alloc_type sa;
1308 		interpolator_type interpolator(imgMatrix);
1309 
1310 		span_gen_type sg(sa, srcBuffer, agg::rgba(0, 0, 0, 0), interpolator);
1311 
1312 		image_renderer_type ri(*fBaseRenderer, sg);
1313 
1314 		agg::rasterizer_scanline_aa<> pf;
1315 		agg::scanline_u8 sl;
1316 
1317 		// path encloses image
1318 		agg::path_storage path;
1319 		path.move_to(viewRect.left, viewRect.top);
1320 		path.line_to(viewRect.right + 1, viewRect.top);
1321 		path.line_to(viewRect.right + 1, viewRect.bottom + 1);
1322 		path.line_to(viewRect.left, viewRect.bottom + 1);
1323 		path.close_polygon();
1324 
1325 		agg::conv_transform<agg::path_storage> tr(path, srcMatrix);
1326 
1327 		pf.add_path(tr);
1328 		agg::render_scanlines(pf, sl, ri);
1329 	}
1330 }
1331 
1332 // _InvertRect32
1333 void
_InvertRect32(BRect r) const1334 Painter::_InvertRect32(BRect r) const
1335 {
1336 	if (fBuffer) {
1337 		int32 width = r.IntegerWidth() + 1;
1338 		for (int32 y = (int32)r.top; y <= (int32)r.bottom; y++) {
1339 			uint8* dst = fBuffer->row(y);
1340 			dst += (int32)r.left * 4;
1341 			for (int32 i = 0; i < width; i++) {
1342 				dst[0] = 255 - dst[0];
1343 				dst[1] = 255 - dst[1];
1344 				dst[2] = 255 - dst[2];
1345 				dst += 4;
1346 			}
1347 		}
1348 	}
1349 }
1350 
1351 // #pragma mark -
1352 
1353 template<class VertexSource>
1354 BRect
_BoundingBox(VertexSource & path) const1355 Painter::_BoundingBox(VertexSource& path) const
1356 {
1357 	double left = 0.0;
1358 	double top = 0.0;
1359 	double right = -1.0;
1360 	double bottom = -1.0;
1361 	uint32 pathID[1];
1362 	pathID[0] = 0;
1363 	agg::bounding_rect(path, pathID, 0, 1, &left, &top, &right, &bottom);
1364 	return BRect(left, top, right, bottom);
1365 }
1366 
1367 
1368 // _StrokePath
1369 template<class VertexSource>
1370 BRect
_StrokePath(VertexSource & path,const pattern & p) const1371 Painter::_StrokePath(VertexSource& path, const pattern& p) const
1372 {
1373 // We're now used by app_server and SetDrawData() was called prior to
1374 // this and it means the pattern is already set
1375 //	fPatternHandler->SetPattern(p);
1376 //	_SetPattern(p);
1377 
1378 #if ALIASED_DRAWING
1379 	float width = fPenSize;
1380 	_Transform(&width);
1381 	if (width > 1.0) {
1382 		agg::conv_stroke<VertexSource> stroke(path);
1383 		stroke.width(width);
1384 
1385 		fRasterizer->add_path(stroke);
1386 		agg::render_scanlines(*fRasterizer, *fScanline, *fRenderer);
1387 	} else {
1388 		fOutlineRasterizer->add_path(path);
1389 	}
1390 #else
1391 	fOutlineRasterizer->add_path(path);
1392 #endif
1393 
1394 	return _Clipped(_BoundingBox(path));
1395 }
1396 
1397 // _FillPath
1398 template<class VertexSource>
1399 BRect
_FillPath(VertexSource & path,const pattern & p) const1400 Painter::_FillPath(VertexSource& path, const pattern& p) const
1401 {
1402 // We're now used by app_server and SetDrawData() was called prior to
1403 // this and it means the pattern is already set
1404 //	fPatternHandler->SetPattern(p);
1405 //	_SetPattern(p);
1406 
1407 	fRasterizer->add_path(path);
1408 	agg::render_scanlines(*fRasterizer, *fScanline, *fRenderer);
1409 
1410 	return _Clipped(_BoundingBox(path));
1411 }
1412 
1413 // _SetPattern
1414 void
_SetPattern(const pattern & p) const1415 Painter::_SetPattern(const pattern& p) const
1416 {
1417 	if (!(p == *fPatternHandler->GetR5Pattern())) {
1418 printf("Painter::_SetPattern()\n");
1419 		fPatternHandler->SetPattern(p);
1420 		DrawingMode* mode = NULL;
1421 		if (p == B_SOLID_HIGH) {
1422 			_SetRendererColor(fPatternHandler->HighColor().GetColor32());
1423 			mode = DrawingModeFactory::DrawingModeFor(fDrawingMode,
1424 													  fAlphaSrcMode,
1425 													  fAlphaFncMode,
1426 													  true);
1427 		} else if (p == B_SOLID_LOW) {
1428 			_SetRendererColor(fPatternHandler->LowColor().GetColor32());
1429 			mode = DrawingModeFactory::DrawingModeFor(fDrawingMode,
1430 													  fAlphaSrcMode,
1431 													  fAlphaFncMode,
1432 													  true);
1433 		} else {
1434 			mode = DrawingModeFactory::DrawingModeFor(fDrawingMode,
1435 													  fAlphaSrcMode,
1436 													  fAlphaFncMode,
1437 													  false);
1438 		}
1439 		fPixelFormat->set_drawing_mode(mode);
1440 	}
1441 }
1442 
1443 // _SetRendererColor
1444 void
_SetRendererColor(const rgb_color & color) const1445 Painter::_SetRendererColor(const rgb_color& color) const
1446 {
1447 
1448 	if (fOutlineRenderer)
1449 #if ALIASED_DRAWING
1450 		fOutlineRenderer->line_color(agg::rgba(color.red / 255.0,
1451 											   color.green / 255.0,
1452 											   color.blue / 255.0));
1453 #else
1454 		fOutlineRenderer->color(agg::rgba(color.red / 255.0,
1455 										  color.green / 255.0,
1456 										  color.blue / 255.0));
1457 #endif
1458 	if (fRenderer)
1459 		fRenderer->color(agg::rgba(color.red / 255.0,
1460 								   color.green / 255.0,
1461 								   color.blue / 255.0));
1462 	if (fFontRendererSolid)
1463 		fFontRendererSolid->color(agg::rgba(color.red / 255.0,
1464 											color.green / 255.0,
1465 											color.blue / 255.0));
1466 	if (fFontRendererBin)
1467 		fFontRendererBin->color(agg::rgba(color.red / 255.0,
1468 										  color.green / 255.0,
1469 										  color.blue / 255.0));
1470 
1471 }
1472