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 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 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 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 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 144 Painter::DetachFromBuffer() 145 { 146 _MakeEmpty(); 147 } 148 149 // SetDrawData 150 void 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 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 188 Painter::SetHighColor(const rgb_color& color) 189 { 190 fPatternHandler->SetHighColor(color); 191 } 192 193 // SetLowColor 194 void 195 Painter::SetLowColor(const rgb_color& color) 196 { 197 fPatternHandler->SetLowColor(color);; 198 } 199 200 // SetScale 201 void 202 Painter::SetScale(float scale) 203 { 204 if (fScale != scale) { 205 fScale = scale; 206 _RebuildClipping(); 207 _UpdateLineWidth(); 208 } 209 } 210 211 // SetPenSize 212 void 213 Painter::SetPenSize(float size) 214 { 215 if (fPenSize != size) { 216 fPenSize = size; 217 _UpdateLineWidth(); 218 } 219 } 220 221 // SetOrigin 222 void 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 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 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 266 Painter::SetPenLocation(const BPoint& location) 267 { 268 fPenLocation = location; 269 } 270 271 // SetFont 272 void 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 286 Painter::SetFont(const ServerFont& font) 287 { 288 fFont = font; 289 _UpdateFont(); 290 } 291 292 // #pragma mark - 293 294 // StrokeLine 295 BRect 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 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 340 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 405 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 412 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 419 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 427 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 435 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 461 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 487 Painter::StrokeShape(/*const */BShape* shape, const pattern& p) const 488 { 489 _DrawShape(shape, p, false); 490 } 491 492 // FillShape 493 void 494 Painter::FillShape(/*const */BShape* shape, const pattern& p) const 495 { 496 _DrawShape(shape, p, true); 497 } 498 499 // StrokeRect 500 BRect 501 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 539 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 553 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 592 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 626 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(<); 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 646 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(<, 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 672 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 680 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 688 Painter::StrokeArc(BPoint center, float xRadius, float yRadius, 689 float angle, float span, const pattern& p) const 690 { 691 _Transform(¢er); 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 707 Painter::FillArc(BPoint center, float xRadius, float yRadius, 708 float angle, float span, const pattern& p) const 709 { 710 _Transform(¢er); 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 745 Painter::DrawChar(char aChar) 746 { 747 // TODO: to be moved elsewhere 748 return DrawChar(aChar, fPenLocation); 749 } 750 751 // DrawChar 752 BRect 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 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 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 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 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 831 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 851 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 872 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 883 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 900 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 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 953 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 976 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 985 Painter::_Transform(float* width) const 986 { 987 *width *= fScale; 988 if (*width < 1) 989 *width = 1; 990 } 991 992 // _Transform 993 float 994 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 1004 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 1023 Painter::_Transform(const BRect& rect) const 1024 { 1025 BRect ret = rect; 1026 _Transform(&ret); 1027 return ret; 1028 } 1029 1030 // _Clipped 1031 BRect 1032 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 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 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 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 1110 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 1133 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(¢er); 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 1159 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 1181 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 1208 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 1246 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 1334 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 1355 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 1371 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 1400 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 1415 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 1445 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