7 #include <GraphicsDefs.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"
38 return (int)floorf(v
+ 0.5);
40 return (int)floorf(v
- 0.5);
48 fOutlineRenderer(NULL
),
49 fOutlineRasterizer(NULL
),
53 fFontRendererSolid(NULL
),
54 fFontRendererBin(NULL
),
56 fSubpixelPrecise(false),
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)
71 fFont
= *fontserver
->GetSystemPlain();
82 delete fClippingRegion
;
83 delete fPatternHandler
;
91 Painter::AttachToBuffer(RenderingBuffer
* buffer
)
93 if (buffer
&& buffer
->InitCheck() >= B_OK
) {
94 // clean up previous stuff
97 fBuffer
= new agg::rendering_buffer();
98 fBuffer
->attach((uint8
*)buffer
->Bits(),
101 buffer
->BytesPerRow());
103 fPixelFormat
= new pixfmt(*fBuffer
, fPatternHandler
);
104 fPixelFormat
->set_drawing_mode(DrawingModeFactory::DrawingModeFor(fDrawingMode
,
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();
115 fOutlineRenderer
= new outline_renderer_type(*fBaseRenderer
);
116 fOutlineRasterizer
= new outline_rasterizer_type(*fOutlineRenderer
);
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
);
124 // the renderer used for filling paths
125 fRenderer
= new renderer_type(*fBaseRenderer
);
126 fRasterizer
= new rasterizer_type();
127 fScanline
= new scanline_type();
130 fRasterizer
->gamma(agg::gamma_threshold(0.5));
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());
144 Painter::DetachFromBuffer()
151 Painter::SetDrawData(const DrawData
* data
)
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
);
163 // if (data->clipReg) {
164 // ConstrainClipping(*data->clipReg);
166 fPatternHandler
->SetPattern(data
->patt
);
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
);
182 *fClippingRegion
= region
;
188 Painter::SetHighColor(const rgb_color
& color
)
190 fPatternHandler
->SetHighColor(color
);
195 Painter::SetLowColor(const rgb_color
& color
)
197 fPatternHandler
->SetLowColor(color
);;
202 Painter::SetScale(float scale
)
204 if (fScale
!= scale
) {
213 Painter::SetPenSize(float size
)
215 if (fPenSize
!= size
) {
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()
237 Painter::SetDrawingMode(drawing_mode mode
)
239 if (fDrawingMode
!= mode
) {
242 fPixelFormat
->set_drawing_mode(DrawingModeFactory::DrawingModeFor(fDrawingMode
,
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
,
266 Painter::SetPenLocation(const BPoint
& location
)
268 fPenLocation
= location
;
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());
286 Painter::SetFont(const ServerFont
& font
)
296 Painter::StrokeLine(BPoint a
, BPoint b
, const pattern
& p
)
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())) {
311 return _Clipped(touched
);
312 } else if (pat
== B_SOLID_LOW
&&
313 StraightLine(a
, b
, fPatternHandler
->LowColor().GetColor32())) {
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
);
327 return _Clipped(touched
);
332 Painter::StrokeLine(BPoint b
, const pattern
& p
)
334 // TODO: move this function elsewhere
335 return StrokeLine(fPenLocation
, b
);
340 Painter::StraightLine(BPoint a
, BPoint b
, const rgb_color
& c
) const
345 uint8
* dst
= fBuffer
->row(0);
346 uint32 bpr
= fBuffer
->stride();
347 int32 x
= (int32
)a
.x
;
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();
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
++) {
366 } while (fBaseRenderer
->next_clip_box());
370 } else if (a
.y
== b
.y
) {
372 uint8
* dst
= fBuffer
->row(0);
373 uint32 bpr
= fBuffer
->stride();
374 int32 y
= (int32
)a
.y
;
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();
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
++) {
393 } while (fBaseRenderer
->next_clip_box());
405 Painter::StrokeTriangle(BPoint pt1
, BPoint pt2
, BPoint pt3
, const pattern
& p
) const
407 _DrawTriangle(pt1
, pt2
, pt3
, p
, false);
412 Painter::FillTriangle(BPoint pt1
, BPoint pt2
, BPoint pt3
, const pattern
& p
) const
414 _DrawTriangle(pt1
, pt2
, pt3
, p
, true);
419 Painter::StrokePolygon(const BPoint
* ptArray
, int32 numPts
,
420 bool closed
, const pattern
& p
) const
422 _DrawPolygon(ptArray
, numPts
, closed
, p
, false);
427 Painter::FillPolygon(const BPoint
* ptArray
, int32 numPts
,
428 bool closed
, const pattern
& p
) const
430 _DrawPolygon(ptArray
, numPts
, closed
, p
, true);
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]);
448 curve
.move_to(p1
.x
, p1
.y
);
449 curve
.curve4(p1
.x
, p1
.y
,
454 agg::conv_curve
<agg::path_storage
> path(curve
);
456 _StrokePath(path
, p
);
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]);
474 curve
.move_to(p1
.x
, p1
.y
);
475 curve
.curve4(p1
.x
, p1
.y
,
478 curve
.close_polygon();
480 agg::conv_curve
<agg::path_storage
> path(curve
);
487 Painter::StrokeShape(/*const */BShape
* shape
, const pattern
& p
) const
489 _DrawShape(shape
, p
, false);
494 Painter::FillShape(/*const */BShape
* shape
, const pattern
& p
) const
496 _DrawShape(shape
, p
, true);
501 Painter::StrokeRect(const BRect
& r
, const pattern
& p
) const
503 BPoint
a(r
.left
, r
.top
);
504 BPoint
b(r
.right
, r
.bottom
);
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
)) {
513 // pattern p = *fPatternHandler->GetR5Pattern();
514 if (p
== B_SOLID_HIGH
) {
517 fPatternHandler
->HighColor().GetColor32());
518 return _Clipped(rect
);
519 } else if (p
== B_SOLID_LOW
) {
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
);
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
);
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
) {
565 FillRect(rect
, fPatternHandler
->HighColor().GetColor32());
566 return _Clipped(rect
);
567 } else if (pat
== B_SOLID_LOW
) {
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
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
);
592 Painter::FillRect(const BRect
& r
, const rgb_color
& c
) const
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();
604 int32 x1
= max_c(fBaseRenderer
->xmin(), left
);
605 int32 x2
= min_c(fBaseRenderer
->xmax(), right
);
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
++) {
620 } while (fBaseRenderer
->next_clip_box());
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
);
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
);
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(<
, 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
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
);
672 Painter::StrokeEllipse(BPoint center
, float xRadius
, float yRadius
,
673 const pattern
& p
) const
675 _DrawEllipse(center
, xRadius
, yRadius
, p
, false);
680 Painter::FillEllipse(BPoint center
, float xRadius
, float yRadius
,
681 const pattern
& p
) const
683 _DrawEllipse(center
, xRadius
, yRadius
, p
, true);
688 Painter::StrokeArc(BPoint center
, float xRadius
, float yRadius
,
689 float angle
, float span
, const pattern
& p
) const
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
);
707 Painter::FillArc(BPoint center
, float xRadius
, float yRadius
,
708 float angle
, float span
, const pattern
& p
) const
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);
730 unsigned cmd
= segmentedArc
.vertex(&x
, &y
);
731 while (!agg::is_stop(cmd
)) {
733 cmd
= segmentedArc
.vertex(&x
, &y
);
736 path
.close_polygon();
745 Painter::DrawChar(char aChar
)
747 // TODO: to be moved elsewhere
748 return DrawChar(aChar
, fPenLocation
);
753 Painter::DrawChar(char aChar
, BPoint baseLine
)
755 // TODO: to be moved elsewhere
759 return DrawString(wrapper
, 1, baseLine
);
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
);
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
);
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
);
790 clippingFrame
= _Transform(fClippingRegion
->Frame());
792 bounds
= fTextRenderer
->RenderString(utf8String
,
800 // pen location is not transformed in quite the same way,
801 // or transformations would add up
803 transform
.RotateBy(B_ORIGIN
, -fFont
.Rotation());
804 transform
.TranslateBy(baseLine
);
805 transform
.Transform(&fPenLocation
);
807 return _Clipped(bounds
);
812 Painter::DrawString(const char* utf8String
, const escapement_delta
* delta
)
814 // TODO: to be moved elsewhere
815 return DrawString(utf8String
, strlen(utf8String
), fPenLocation
, delta
);
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
);
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
);
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(),
862 bitmap
->BytesPerRow());
864 _DrawBitmap(srcBuffer
, bitmap
->ColorSpace(), actualBitmapRect
, bitmapRect
, viewRect
);
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
);
883 Painter::InvertRect(const BRect
& r
) const
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
);
900 Painter::BoundingBox(const char* utf8String
, uint32 length
,
901 const BPoint
& baseLine
) const
903 Transformable transform
;
904 transform
.TranslateBy(baseLine
);
907 return fTextRenderer
->RenderString(utf8String
,
911 transform
, dummy
, true);
918 Painter::_MakeEmpty()
926 delete fBaseRenderer
;
927 fBaseRenderer
= NULL
;
929 delete fOutlineRenderer
;
930 fOutlineRenderer
= NULL
;
932 delete fOutlineRasterizer
;
933 fOutlineRasterizer
= NULL
;
944 delete fFontRendererSolid
;
945 fFontRendererSolid
= NULL
;
947 delete fFontRendererBin
;
948 fFontRendererBin
= NULL
;
953 Painter::_Transform(BPoint
* point
, bool centerOffset
) const
957 if (!fSubpixelPrecise
) {
958 // TODO: validate usage of floor() for values < 0
959 point
->x
= floorf(point
->x
);
960 point
->y
= floorf(point
->y
);
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
976 Painter::_Transform(const BPoint
& point
, bool centerOffset
) const
979 _Transform(&ret
, centerOffset
);
985 Painter::_Transform(float* width
) const
994 Painter::_Transform(const float& width
) const
996 float w
= width
* fScale
;
1004 Painter::_Transform(BRect
* rect
) const
1006 // TODO integrate this function more
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
;
1023 Painter::_Transform(const BRect
& rect
) const
1032 Painter::_Clipped(const BRect
& rect
) const
1034 if (rect
.IsValid() && fClippingRegion
)
1035 return rect
& _Transform(fClippingRegion
->Frame());
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
1065 // undo offset to bottom right corner after transformation
1066 rb
-= BPoint(1.0, 1.0);
1067 // fBaseRenderer->add_clip_box(floorf(lt.x),
1071 fBaseRenderer
->add_clip_box(roundf(lt
.x
),
1082 Painter::_UpdateFont()
1084 if (fLastFamilyAndStyle
!= fFont
.GetFamilyAndStyle()) {
1085 fLastFamilyAndStyle
= fFont
.GetFamilyAndStyle();
1087 bool success
= false;
1088 success
= fTextRenderer
->SetFont(fFont
);
1090 fprintf(stderr
, "unable to set font\n");
1093 fTextRenderer
->SetPointSize(fFont
.Size());
1098 Painter::_UpdateLineWidth()
1100 float width
= fPenSize
;
1103 fLineProfile
.width(width
);
1110 Painter::_DrawTriangle(BPoint pt1
, BPoint pt2
, BPoint pt3
,
1111 const pattern
& p
, bool fill
) const
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();
1128 _StrokePath(path
, p
);
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(¢er
);
1141 _Transform(&xRadius
);
1142 _Transform(&yRadius
);
1144 float width
= fPenSize
;
1147 int32 divisions
= (int32
)max_c(12, ((xRadius
+ yRadius
) * PI
) / 2 * (int32
)width
);
1149 agg::ellipse
path(center
.x
, center
.y
, xRadius
, yRadius
, divisions
);
1154 _StrokePath(path
, p
);
1159 Painter::_DrawShape(/*const */BShape
* shape
, const pattern
& p
, bool fill
) const
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
);
1176 _StrokePath(path
, p
);
1181 Painter::_DrawPolygon(const BPoint
* ptArray
, int32 numPts
,
1182 bool closed
, const pattern
& p
, bool fill
) const
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
++) {
1192 point
= _Transform(*ptArray
);
1193 path
.line_to(point
.x
, point
.y
);
1197 path
.close_polygon();
1202 _StrokePath(path
, p
);
1208 Painter::_DrawBitmap(const agg::rendering_buffer
& srcBuffer
, color_space format
,
1209 BRect actualBitmapRect
, BRect bitmapRect
, BRect viewRect
) const
1214 _DrawBitmap32(srcBuffer
, actualBitmapRect
, bitmapRect
, viewRect
);
1217 fprintf(stderr
, "Painter::_DrawBitmap() - non-native colorspace: %d\n", format
);
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(),
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
);
1237 fprintf(stderr
, "Painter::_DrawBitmap() - colorspace conversion failed: %s\n", strerror(err
));
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
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
);
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
);
1328 agg::render_scanlines(pf
, sl
, ri
);
1334 Painter::_InvertRect32(BRect r
) const
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];
1353 template<class VertexSource
>
1355 Painter::_BoundingBox(VertexSource
& path
) const
1359 double right
= -1.0;
1360 double bottom
= -1.0;
1363 agg::bounding_rect(path
, pathID
, 0, 1, &left
, &top
, &right
, &bottom
);
1364 return BRect(left
, top
, right
, bottom
);
1369 template<class VertexSource
>
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);
1379 float width
= fPenSize
;
1382 agg::conv_stroke
<VertexSource
> stroke(path
);
1383 stroke
.width(width
);
1385 fRasterizer
->add_path(stroke
);
1386 agg::render_scanlines(*fRasterizer
, *fScanline
, *fRenderer
);
1388 fOutlineRasterizer
->add_path(path
);
1391 fOutlineRasterizer
->add_path(path
);
1394 return _Clipped(_BoundingBox(path
));
1398 template<class VertexSource
>
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);
1407 fRasterizer
->add_path(path
);
1408 agg::render_scanlines(*fRasterizer
, *fScanline
, *fRenderer
);
1410 return _Clipped(_BoundingBox(path
));
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
,
1427 } else if (p
== B_SOLID_LOW
) {
1428 _SetRendererColor(fPatternHandler
->LowColor().GetColor32());
1429 mode
= DrawingModeFactory::DrawingModeFor(fDrawingMode
,
1434 mode
= DrawingModeFactory::DrawingModeFor(fDrawingMode
,
1439 fPixelFormat
->set_drawing_mode(mode
);
1443 // _SetRendererColor
1445 Painter::_SetRendererColor(const rgb_color
& color
) const
1448 if (fOutlineRenderer
)
1450 fOutlineRenderer
->line_color(agg::rgba(color
.red
/ 255.0,
1451 color
.green
/ 255.0,
1452 color
.blue
/ 255.0));
1454 fOutlineRenderer
->color(agg::rgba(color
.red
/ 255.0,
1455 color
.green
/ 255.0,
1456 color
.blue
/ 255.0));
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));