libroot_debug: Merge guarded heap into libroot_debug.
[haiku.git] / src / tests / servers / app / painter / Painter.cpp
blob3b4052d2c540112a327284221dc7696f06cc905d
1 // Painter.cpp
3 #include <stdio.h>
4 #include <string.h>
6 #include <Bitmap.h>
7 #include <GraphicsDefs.h>
8 #include <Region.h>
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>
20 #include "LayerData.h"
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"
32 #include "Painter.h"
34 int
35 roundf(float v)
37 if (v >= 0.0)
38 return (int)floorf(v + 0.5);
39 else
40 return (int)floorf(v - 0.5);
43 // constructor
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)
70 if (fontserver)
71 fFont = *fontserver->GetSystemPlain();
73 _UpdateFont();
74 _UpdateLineWidth();
77 // destructor
78 Painter::~Painter()
80 _MakeEmpty();
82 delete fClippingRegion;
83 delete fPatternHandler;
84 delete fTextRenderer;
87 // #pragma mark -
89 // AttachToBuffer
90 void
91 Painter::AttachToBuffer(RenderingBuffer* buffer)
93 if (buffer && buffer->InitCheck() >= B_OK) {
94 // clean up previous stuff
95 _MakeEmpty();
97 fBuffer = new agg::rendering_buffer();
98 fBuffer->attach((uint8*)buffer->Bits(),
99 buffer->Width(),
100 buffer->Height(),
101 buffer->BytesPerRow());
103 fPixelFormat = new pixfmt(*fBuffer, fPatternHandler);
104 fPixelFormat->set_drawing_mode(DrawingModeFactory::DrawingModeFor(fDrawingMode,
105 fAlphaSrcMode,
106 fAlphaFncMode,
107 false));
109 fBaseRenderer = new renderer_base(*fPixelFormat);
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);
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();
129 #if ALIASED_DRAWING
130 fRasterizer->gamma(agg::gamma_threshold(0.5));
131 #endif
133 // These are renderers needed for drawing text
134 fFontRendererSolid = new font_renderer_solid_type(*fBaseRenderer);
135 fFontRendererBin = new font_renderer_bin_type(*fBaseRenderer);
137 _SetRendererColor(fPatternHandler->HighColor().GetColor32());
138 _RebuildClipping();
142 // DetachFromBuffer
143 void
144 Painter::DetachFromBuffer()
146 _MakeEmpty();
149 // SetDrawData
150 void
151 Painter::SetDrawData(const DrawData* data)
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);
169 // #pragma mark -
171 // ConstrainClipping
172 void
173 Painter::ConstrainClipping(const BRegion& region)
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();
186 // SetHighColor
187 void
188 Painter::SetHighColor(const rgb_color& color)
190 fPatternHandler->SetHighColor(color);
193 // SetLowColor
194 void
195 Painter::SetLowColor(const rgb_color& color)
197 fPatternHandler->SetLowColor(color);;
200 // SetScale
201 void
202 Painter::SetScale(float scale)
204 if (fScale != scale) {
205 fScale = scale;
206 _RebuildClipping();
207 _UpdateLineWidth();
211 // SetPenSize
212 void
213 Painter::SetPenSize(float size)
215 if (fPenSize != size) {
216 fPenSize = size;
217 _UpdateLineWidth();
221 // SetOrigin
222 void
223 Painter::SetOrigin(const BPoint& origin)
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();
235 // SetDrawingMode
236 void
237 Painter::SetDrawingMode(drawing_mode mode)
239 if (fDrawingMode != mode) {
240 fDrawingMode = mode;
241 if (fPixelFormat) {
242 fPixelFormat->set_drawing_mode(DrawingModeFactory::DrawingModeFor(fDrawingMode,
243 fAlphaSrcMode,
244 fAlphaFncMode));
249 // SetBlendingMode
250 void
251 Painter::SetBlendingMode(source_alpha alphaSrcMode, alpha_function alphaFncMode)
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));
264 // SetPenLocation
265 void
266 Painter::SetPenLocation(const BPoint& location)
268 fPenLocation = location;
271 // SetFont
272 void
273 Painter::SetFont(const BFont& font)
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());
281 _UpdateFont();
284 // SetFont
285 void
286 Painter::SetFont(const ServerFont& font)
288 fFont = font;
289 _UpdateFont();
292 // #pragma mark -
294 // StrokeLine
295 BRect
296 Painter::StrokeLine(BPoint a, BPoint b, const pattern& p)
298 _Transform(&a);
299 _Transform(&b);
301 BRect touched(a, b);
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);
319 agg::path_storage path;
320 path.move_to(a.x, a.y);
321 path.line_to(b.x, b.y);
323 touched = _StrokePath(path, p);
325 SetPenLocation(b);
327 return _Clipped(touched);
330 // StrokeLine
331 BRect
332 Painter::StrokeLine(BPoint b, const pattern& p)
334 // TODO: move this function elsewhere
335 return StrokeLine(fPenLocation, b);
338 // StraightLine
339 bool
340 Painter::StraightLine(BPoint a, BPoint b, const rgb_color& c) const
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;
366 } while (fBaseRenderer->next_clip_box());
368 return true;
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;
393 } while (fBaseRenderer->next_clip_box());
395 return true;
398 return false;
401 // #pragma mark -
403 // StrokeTriangle
404 void
405 Painter::StrokeTriangle(BPoint pt1, BPoint pt2, BPoint pt3, const pattern& p) const
407 _DrawTriangle(pt1, pt2, pt3, p, false);
410 // FillTriangle
411 void
412 Painter::FillTriangle(BPoint pt1, BPoint pt2, BPoint pt3, const pattern& p) const
414 _DrawTriangle(pt1, pt2, pt3, p, true);
417 // StrokePolygon
418 void
419 Painter::StrokePolygon(const BPoint* ptArray, int32 numPts,
420 bool closed, const pattern& p) const
422 _DrawPolygon(ptArray, numPts, closed, p, false);
425 // FillPolygon
426 void
427 Painter::FillPolygon(const BPoint* ptArray, int32 numPts,
428 bool closed, const pattern& p) const
430 _DrawPolygon(ptArray, numPts, closed, p, true);
433 // StrokeBezier
434 void
435 Painter::StrokeBezier(const BPoint* controlPoints, const pattern& p) const
437 agg::path_storage curve;
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);
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);
454 agg::conv_curve<agg::path_storage> path(curve);
456 _StrokePath(path, p);
459 // FillBezier
460 void
461 Painter::FillBezier(const BPoint* controlPoints, const pattern& p) const
463 agg::path_storage curve;
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);
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();
480 agg::conv_curve<agg::path_storage> path(curve);
482 _FillPath(path, p);
485 // StrokeShape
486 void
487 Painter::StrokeShape(/*const */BShape* shape, const pattern& p) const
489 _DrawShape(shape, p, false);
492 // FillShape
493 void
494 Painter::FillShape(/*const */BShape* shape, const pattern& p) const
496 _DrawShape(shape, p, true);
499 // StrokeRect
500 BRect
501 Painter::StrokeRect(const BRect& r, const pattern& p) const
503 BPoint a(r.left, r.top);
504 BPoint b(r.right, r.bottom);
505 _Transform(&a);
506 _Transform(&b);
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);
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();
534 return _StrokePath(path, p);
537 // StrokeRect
538 void
539 Painter::StrokeRect(const BRect& r, const rgb_color& c) const
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);
551 // FillRect
552 BRect
553 Painter::FillRect(const BRect& r, const pattern& p) const
555 BPoint a(r.left, r.top);
556 BPoint b(r.right, r.bottom);
557 _Transform(&a, false);
558 _Transform(&b, false);
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);
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;
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();
587 return _FillPath(path, p);
590 // FillRect
591 void
592 Painter::FillRect(const BRect& r, const rgb_color& c) const
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;
620 } while (fBaseRenderer->next_clip_box());
624 // StrokeRoundRect
625 void
626 Painter::StrokeRoundRect(const BRect& r, float xRadius, float yRadius,
627 const pattern& p) const
629 BPoint lt(r.left, r.top);
630 BPoint rb(r.right, r.bottom);
631 _Transform(&lt);
632 _Transform(&rb);
634 _Transform(&xRadius);
635 _Transform(&yRadius);
637 agg::rounded_rect rect;
638 rect.rect(lt.x, lt.y, rb.x, rb.y);
639 rect.radius(xRadius, yRadius);
641 _StrokePath(rect, p);
644 // FillRoundRect
645 void
646 Painter::FillRoundRect(const BRect& r, float xRadius, float yRadius,
647 const pattern& p) const
649 BPoint lt(r.left, r.top);
650 BPoint rb(r.right, r.bottom);
651 _Transform(&lt, false);
652 _Transform(&rb, false);
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;
660 _Transform(&xRadius);
661 _Transform(&yRadius);
663 agg::rounded_rect rect;
664 rect.rect(lt.x, lt.y, rb.x, rb.y);
665 rect.radius(xRadius, yRadius);
667 _FillPath(rect, p);
670 // StrokeEllipse
671 void
672 Painter::StrokeEllipse(BPoint center, float xRadius, float yRadius,
673 const pattern& p) const
675 _DrawEllipse(center, xRadius, yRadius, p, false);
678 // FillEllipse
679 void
680 Painter::FillEllipse(BPoint center, float xRadius, float yRadius,
681 const pattern& p) const
683 _DrawEllipse(center, xRadius, yRadius, p, true);
686 // StrokeArc
687 void
688 Painter::StrokeArc(BPoint center, float xRadius, float yRadius,
689 float angle, float span, const pattern& p) const
691 _Transform(&center);
692 _Transform(&xRadius);
693 _Transform(&yRadius);
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);
700 agg::conv_curve<agg::bezier_arc> path(arc);
702 _StrokePath(path, p);
705 // FillArc
706 void
707 Painter::FillArc(BPoint center, float xRadius, float yRadius,
708 float angle, float span, const pattern& p) const
710 _Transform(&center);
711 _Transform(&xRadius);
712 _Transform(&yRadius);
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);
719 agg::conv_curve<agg::bezier_arc> segmentedArc(arc);
721 agg::path_storage path;
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);
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);
736 path.close_polygon();
738 _FillPath(path, p);
741 // #pragma mark -
743 // DrawChar
744 BRect
745 Painter::DrawChar(char aChar)
747 // TODO: to be moved elsewhere
748 return DrawChar(aChar, fPenLocation);
751 // DrawChar
752 BRect
753 Painter::DrawChar(char aChar, BPoint baseLine)
755 // TODO: to be moved elsewhere
756 char wrapper[2];
757 wrapper[0] = aChar;
758 wrapper[1] = 0;
759 return DrawString(wrapper, 1, baseLine);
762 // DrawString
763 BRect
764 Painter::DrawString(const char* utf8String, uint32 length,
765 const escapement_delta* delta)
767 // TODO: to be moved elsewhere
768 return DrawString(utf8String, length, fPenLocation, delta);
771 // DrawString
772 BRect
773 Painter::DrawString(const char* utf8String, uint32 length,
774 BPoint baseLine, const escapement_delta* delta)
776 BRect bounds(0.0, 0.0, -1.0, -1.0);
777 fPatternHandler->SetPattern(B_SOLID_HIGH);
779 if (fBuffer) {
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);
788 BRect clippingFrame;
789 if (fClippingRegion)
790 clippingFrame = _Transform(fClippingRegion->Frame());
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);
807 return _Clipped(bounds);
810 // DrawString
811 BRect
812 Painter::DrawString(const char* utf8String, const escapement_delta* delta)
814 // TODO: to be moved elsewhere
815 return DrawString(utf8String, strlen(utf8String), fPenLocation, delta);
818 // DrawString
819 BRect
820 Painter::DrawString(const char* utf8String, BPoint baseLine,
821 const escapement_delta* delta)
823 // TODO: to be moved elsewhere
824 return DrawString(utf8String, strlen(utf8String), baseLine, delta);
827 // #pragma mark -
829 // DrawBitmap
830 void
831 Painter::DrawBitmap(const BBitmap* bitmap,
832 BRect bitmapRect, BRect viewRect) const
834 if (bitmap && bitmap->IsValid()) {
835 // the native bitmap coordinate system
836 // (can have left top corner offset)
837 BRect actualBitmapRect(bitmap->Bounds());
839 agg::rendering_buffer srcBuffer;
840 srcBuffer.attach((uint8*)bitmap->Bits(),
841 (uint32)actualBitmapRect.IntegerWidth() + 1,
842 (uint32)actualBitmapRect.IntegerHeight() + 1,
843 bitmap->BytesPerRow());
845 _DrawBitmap(srcBuffer, bitmap->ColorSpace(), actualBitmapRect, bitmapRect, viewRect);
849 // DrawBitmap
850 void
851 Painter::DrawBitmap(const ServerBitmap* bitmap,
852 BRect bitmapRect, BRect viewRect) const
854 if (bitmap && bitmap->InitCheck()) {
855 // the native bitmap coordinate system
856 BRect actualBitmapRect(bitmap->Bounds());
858 agg::rendering_buffer srcBuffer;
859 srcBuffer.attach(bitmap->Bits(),
860 bitmap->Width(),
861 bitmap->Height(),
862 bitmap->BytesPerRow());
864 _DrawBitmap(srcBuffer, bitmap->ColorSpace(), actualBitmapRect, bitmapRect, viewRect);
868 // #pragma mark -
870 // FillRegion
871 void
872 Painter::FillRegion(const BRegion* region, const pattern& p = B_SOLID_HIGH) const
874 BRegion copy(*region);
875 int32 count = copy.CountRects();
876 for (int32 i = 0; i < count; i++) {
877 FillRect(copy.RectAt(i), p);
881 // InvertRect
882 void
883 Painter::InvertRect(const BRect& r) const
885 BRegion region(r);
886 if (fClippingRegion) {
887 region.IntersectWith(fClippingRegion);
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);
898 // BoundingBox
899 BRect
900 Painter::BoundingBox(const char* utf8String, uint32 length,
901 const BPoint& baseLine) const
903 Transformable transform;
904 transform.TranslateBy(baseLine);
906 BRect dummy;
907 return fTextRenderer->RenderString(utf8String,
908 length,
909 fFontRendererSolid,
910 fFontRendererBin,
911 transform, dummy, true);
914 // #pragma mark -
916 // _MakeEmpty
917 void
918 Painter::_MakeEmpty()
920 delete fBuffer;
921 fBuffer = NULL;
923 delete fPixelFormat;
924 fPixelFormat = NULL;
926 delete fBaseRenderer;
927 fBaseRenderer = NULL;
929 delete fOutlineRenderer;
930 fOutlineRenderer = NULL;
932 delete fOutlineRasterizer;
933 fOutlineRasterizer = NULL;
935 delete fScanline;
936 fScanline = NULL;
938 delete fRasterizer;
939 fRasterizer = NULL;
941 delete fRenderer;
942 fRenderer = NULL;
944 delete fFontRendererSolid;
945 fFontRendererSolid = NULL;
947 delete fFontRendererBin;
948 fFontRendererBin = NULL;
951 // _Transform
952 void
953 Painter::_Transform(BPoint* point, bool centerOffset) const
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);
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;
974 // _Transform
975 BPoint
976 Painter::_Transform(const BPoint& point, bool centerOffset) const
978 BPoint ret = point;
979 _Transform(&ret, centerOffset);
980 return ret;
983 // _Transform
984 void
985 Painter::_Transform(float* width) const
987 *width *= fScale;
988 if (*width < 1)
989 *width = 1;
992 // _Transform
993 float
994 Painter::_Transform(const float& width) const
996 float w = width * fScale;
997 if (w < 1)
998 w = 1;
999 return w;
1002 // _Transform
1003 void
1004 Painter::_Transform(BRect* rect) const
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--;
1021 // _Transform
1022 BRect
1023 Painter::_Transform(const BRect& rect) const
1025 BRect ret = rect;
1026 _Transform(&ret);
1027 return ret;
1030 // _Clipped
1031 BRect
1032 Painter::_Clipped(const BRect& rect) const
1034 if (rect.IsValid() && fClippingRegion)
1035 return rect & _Transform(fClippingRegion->Frame());
1036 return rect;
1039 // #pragma mark -
1041 // _RebuildClipping
1042 void
1043 Painter::_RebuildClipping()
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));
1080 // _UpdateFont
1081 void
1082 Painter::_UpdateFont()
1084 if (fLastFamilyAndStyle != fFont.GetFamilyAndStyle()) {
1085 fLastFamilyAndStyle = fFont.GetFamilyAndStyle();
1087 bool success = false;
1088 success = fTextRenderer->SetFont(fFont);
1089 if (!success)
1090 fprintf(stderr, "unable to set font\n");
1093 fTextRenderer->SetPointSize(fFont.Size());
1096 // _UpdateLineWidth
1097 void
1098 Painter::_UpdateLineWidth()
1100 float width = fPenSize;
1101 _Transform(&width);
1103 fLineProfile.width(width);
1106 // #pragma mark -
1108 // _DrawTriangle
1109 inline void
1110 Painter::_DrawTriangle(BPoint pt1, BPoint pt2, BPoint pt3,
1111 const pattern& p, bool fill) const
1113 _Transform(&pt1);
1114 _Transform(&pt2);
1115 _Transform(&pt3);
1117 agg::path_storage path;
1119 path.move_to(pt1.x, pt1.y);
1120 path.line_to(pt2.x, pt2.y);
1121 path.line_to(pt3.x, pt3.y);
1123 path.close_polygon();
1125 if (fill)
1126 _FillPath(path, p);
1127 else
1128 _StrokePath(path, p);
1131 // _DrawEllipse
1132 inline void
1133 Painter::_DrawEllipse(BPoint center, float xRadius, float yRadius,
1134 const pattern& p, bool fill) const
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);
1144 float width = fPenSize;
1145 _Transform(&width);
1147 int32 divisions = (int32)max_c(12, ((xRadius + yRadius) * PI) / 2 * (int32)width);
1149 agg::ellipse path(center.x, center.y, xRadius, yRadius, divisions);
1151 if (fill)
1152 _FillPath(path, p);
1153 else
1154 _StrokePath(path, p);
1157 // _DrawShape
1158 inline void
1159 Painter::_DrawShape(/*const */BShape* shape, const pattern& p, bool fill) const
1161 // TODO: untested
1162 agg::path_storage path;
1163 ShapeConverter converter(&path);
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));
1171 converter.Iterate(shape);
1173 if (fill)
1174 _FillPath(path, p);
1175 else
1176 _StrokePath(path, p);
1179 // _DrawPolygon
1180 inline void
1181 Painter::_DrawPolygon(const BPoint* ptArray, int32 numPts,
1182 bool closed, const pattern& p, bool fill) const
1184 if (numPts > 0) {
1186 agg::path_storage path;
1187 BPoint point = _Transform(*ptArray);
1188 path.move_to(point.x, point.y);
1190 for (int32 i = 1; i < numPts; i++) {
1191 ptArray++;
1192 point = _Transform(*ptArray);
1193 path.line_to(point.x, point.y);
1196 if (closed)
1197 path.close_polygon();
1199 if (fill)
1200 _FillPath(path, p);
1201 else
1202 _StrokePath(path, p);
1206 // _DrawBitmap
1207 void
1208 Painter::_DrawBitmap(const agg::rendering_buffer& srcBuffer, color_space format,
1209 BRect actualBitmapRect, BRect bitmapRect, BRect viewRect) const
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));
1239 #endif // __HAIKU__
1240 break;
1244 // _DrawBitmap32
1245 void
1246 Painter::_DrawBitmap32(const agg::rendering_buffer& srcBuffer,
1247 BRect actualBitmapRect, BRect bitmapRect, BRect viewRect) const
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;
1255 if (bitmapRect.IsValid() && bitmapRect.Intersects(actualBitmapRect)
1256 && viewRect.IsValid()) {
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);
1265 // calculate the scaling
1266 double xScale = (viewRect.Width() + 1) / (bitmapRect.Width() + 1);
1267 double yScale = (viewRect.Height() + 1) / (bitmapRect.Height() + 1);
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;
1276 if (bitmapRect.top < actualBitmapRect.top) {
1277 float diff = actualBitmapRect.top - bitmapRect.top;
1278 viewRect.top += diff;
1279 bitmapRect.top = actualBitmapRect.top;
1281 if (bitmapRect.right > actualBitmapRect.right) {
1282 float diff = bitmapRect.right - actualBitmapRect.right;
1283 viewRect.right -= diff;
1284 bitmapRect.right = actualBitmapRect.right;
1286 if (bitmapRect.bottom > actualBitmapRect.bottom) {
1287 float diff = bitmapRect.right - actualBitmapRect.bottom;
1288 viewRect.bottom -= diff;
1289 bitmapRect.bottom = actualBitmapRect.bottom;
1292 float xOffset = viewRect.left - (bitmapRect.left * xScale);
1293 float yOffset = viewRect.top - (bitmapRect.top * yScale);
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);
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();
1307 span_alloc_type sa;
1308 interpolator_type interpolator(imgMatrix);
1310 span_gen_type sg(sa, srcBuffer, agg::rgba(0, 0, 0, 0), interpolator);
1312 image_renderer_type ri(*fBaseRenderer, sg);
1314 agg::rasterizer_scanline_aa<> pf;
1315 agg::scanline_u8 sl;
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();
1325 agg::conv_transform<agg::path_storage> tr(path, srcMatrix);
1327 pf.add_path(tr);
1328 agg::render_scanlines(pf, sl, ri);
1332 // _InvertRect32
1333 void
1334 Painter::_InvertRect32(BRect r) const
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;
1351 // #pragma mark -
1353 template<class VertexSource>
1354 BRect
1355 Painter::_BoundingBox(VertexSource& path) const
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);
1368 // _StrokePath
1369 template<class VertexSource>
1370 BRect
1371 Painter::_StrokePath(VertexSource& path, const pattern& p) const
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);
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);
1385 fRasterizer->add_path(stroke);
1386 agg::render_scanlines(*fRasterizer, *fScanline, *fRenderer);
1387 } else {
1388 fOutlineRasterizer->add_path(path);
1390 #else
1391 fOutlineRasterizer->add_path(path);
1392 #endif
1394 return _Clipped(_BoundingBox(path));
1397 // _FillPath
1398 template<class VertexSource>
1399 BRect
1400 Painter::_FillPath(VertexSource& path, const pattern& p) const
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);
1407 fRasterizer->add_path(path);
1408 agg::render_scanlines(*fRasterizer, *fScanline, *fRenderer);
1410 return _Clipped(_BoundingBox(path));
1413 // _SetPattern
1414 void
1415 Painter::_SetPattern(const pattern& p) const
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);
1439 fPixelFormat->set_drawing_mode(mode);
1443 // _SetRendererColor
1444 void
1445 Painter::_SetRendererColor(const rgb_color& color) const
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));