1 /* 2 * Copyright 2009, Christian Packmann. 3 * Copyright 2008, Andrej Spielmann <andrej.spielmann@seh.ox.ac.uk>. 4 * Copyright 2005-2014, Stephan Aßmus <superstippi@gmx.de>. 5 * Copyright 2015, Julian Harnath <julian.harnath@rwth-aachen.de> 6 * All rights reserved. Distributed under the terms of the MIT License. 7 */ 8 9 10 /*! API to the Anti-Grain Geometry based "Painter" drawing backend. Manages 11 rendering pipe-lines for stroke, fills, bitmap and text rendering. 12 */ 13 14 15 #include "Painter.h" 16 17 #include <new> 18 19 #include <stdio.h> 20 #include <string.h> 21 22 #include <Bitmap.h> 23 #include <GraphicsDefs.h> 24 #include <Region.h> 25 #include <String.h> 26 #include <GradientLinear.h> 27 #include <GradientRadial.h> 28 #include <GradientRadialFocus.h> 29 #include <GradientDiamond.h> 30 #include <GradientConic.h> 31 32 #include <ShapePrivate.h> 33 34 #include <agg_bezier_arc.h> 35 #include <agg_bounding_rect.h> 36 #include <agg_conv_clip_polygon.h> 37 #include <agg_conv_curve.h> 38 #include <agg_conv_stroke.h> 39 #include <agg_ellipse.h> 40 #include <agg_image_accessors.h> 41 #include <agg_path_storage.h> 42 #include <agg_pixfmt_rgba.h> 43 #include <agg_rounded_rect.h> 44 #include <agg_span_allocator.h> 45 #include <agg_span_image_filter_rgba.h> 46 #include <agg_span_interpolator_linear.h> 47 48 #include "drawing_support.h" 49 50 #include "DrawState.h" 51 52 #include <AutoDeleter.h> 53 #include <View.h> 54 55 #include "AlphaMask.h" 56 #include "BitmapPainter.h" 57 #include "DrawingMode.h" 58 #include "GlobalSubpixelSettings.h" 59 #include "PatternHandler.h" 60 #include "RenderingBuffer.h" 61 #include "ServerBitmap.h" 62 #include "ServerFont.h" 63 #include "SystemPalette.h" 64 65 #include "AppServer.h" 66 67 using std::nothrow; 68 69 #undef TRACE 70 // #define TRACE_PAINTER 71 #ifdef TRACE_PAINTER 72 # define TRACE(x...) printf(x) 73 #else 74 # define TRACE(x...) 75 #endif 76 77 //#define TRACE_GRADIENTS 78 #ifdef TRACE_GRADIENTS 79 # include <OS.h> 80 # define GTRACE(x...) debug_printf(x) 81 #else 82 # define GTRACE(x...) 83 #endif 84 85 86 #define CHECK_CLIPPING if (!fValidClipping) return BRect(0, 0, -1, -1); 87 #define CHECK_CLIPPING_NO_RETURN if (!fValidClipping) return; 88 89 90 // Shortcuts for accessing internal data 91 #define fBuffer fInternal.fBuffer 92 #define fPixelFormat fInternal.fPixelFormat 93 #define fBaseRenderer fInternal.fBaseRenderer 94 #define fUnpackedScanline fInternal.fUnpackedScanline 95 #define fPackedScanline fInternal.fPackedScanline 96 #define fRasterizer fInternal.fRasterizer 97 #define fRenderer fInternal.fRenderer 98 #define fRendererBin fInternal.fRendererBin 99 #define fSubpixPackedScanline fInternal.fSubpixPackedScanline 100 #define fSubpixUnpackedScanline fInternal.fSubpixUnpackedScanline 101 #define fSubpixRasterizer fInternal.fSubpixRasterizer 102 #define fSubpixRenderer fInternal.fSubpixRenderer 103 #define fMaskedUnpackedScanline fInternal.fMaskedUnpackedScanline 104 #define fClippedAlphaMask fInternal.fClippedAlphaMask 105 #define fPath fInternal.fPath 106 #define fCurve fInternal.fCurve 107 108 109 static uint32 detect_simd(); 110 111 uint32 gSIMDFlags = detect_simd(); 112 113 114 /*! Detect SIMD flags for use in AppServer. Checks all CPUs in the system 115 and chooses the minimum supported set of instructions. 116 */ 117 static uint32 118 detect_simd() 119 { 120 #if __i386__ 121 // Only scan CPUs for which we are certain the SIMD flags are properly 122 // defined. 123 const char* vendorNames[] = { 124 "GenuineIntel", 125 "AuthenticAMD", 126 "CentaurHauls", // Via CPUs, MMX and SSE support 127 "RiseRiseRise", // should be MMX-only 128 "CyrixInstead", // MMX-only, but custom MMX extensions 129 "GenuineTMx86", // MMX and SSE 130 0 131 }; 132 133 system_info systemInfo; 134 if (get_system_info(&systemInfo) != B_OK) 135 return 0; 136 137 // We start out with all flags set and end up with only those flags 138 // supported across all CPUs found. 139 uint32 systemSIMD = 0xffffffff; 140 141 for (uint32 cpu = 0; cpu < systemInfo.cpu_count; cpu++) { 142 cpuid_info cpuInfo; 143 get_cpuid(&cpuInfo, 0, cpu); 144 145 // Get the vendor string and terminate it manually 146 char vendor[13]; 147 memcpy(vendor, cpuInfo.eax_0.vendor_id, 12); 148 vendor[12] = 0; 149 150 bool vendorFound = false; 151 for (uint32 i = 0; vendorNames[i] != 0; i++) { 152 if (strcmp(vendor, vendorNames[i]) == 0) 153 vendorFound = true; 154 } 155 156 uint32 cpuSIMD = 0; 157 uint32 maxStdFunc = cpuInfo.regs.eax; 158 if (vendorFound && maxStdFunc >= 1) { 159 get_cpuid(&cpuInfo, 1, 0); 160 uint32 edx = cpuInfo.regs.edx; 161 if (edx & (1 << 23)) 162 cpuSIMD |= APPSERVER_SIMD_MMX; 163 if (edx & (1 << 25)) 164 cpuSIMD |= APPSERVER_SIMD_SSE; 165 } else { 166 // no flags can be identified 167 cpuSIMD = 0; 168 } 169 systemSIMD &= cpuSIMD; 170 } 171 return systemSIMD; 172 #else // !__i386__ 173 return 0; 174 #endif 175 } 176 177 178 // Gradients and strings don't use patterns, but we want the special handling 179 // we have for solid patterns in certain modes to get the expected results for 180 // border antialiasing. 181 class SolidPatternGuard { 182 public: 183 SolidPatternGuard(Painter* painter) 184 : 185 fPainter(painter), 186 fPattern(fPainter->Pattern()) 187 { 188 fPainter->SetPattern(B_SOLID_HIGH); 189 } 190 191 ~SolidPatternGuard() 192 { 193 fPainter->SetPattern(fPattern); 194 } 195 196 private: 197 Painter* fPainter; 198 pattern fPattern; 199 }; 200 201 202 // #pragma mark - 203 204 205 Painter::Painter() 206 : 207 fInternal(fPatternHandler), 208 fSubpixelPrecise(false), 209 fValidClipping(false), 210 fAttached(false), 211 212 fPenSize(1.0), 213 fClippingRegion(NULL), 214 fDrawingMode(B_OP_COPY), 215 fAlphaSrcMode(B_PIXEL_ALPHA), 216 fAlphaFncMode(B_ALPHA_OVERLAY), 217 fLineCapMode(B_BUTT_CAP), 218 fLineJoinMode(B_MITER_JOIN), 219 fMiterLimit(B_DEFAULT_MITER_LIMIT), 220 221 fPatternHandler(), 222 fTextRenderer(fSubpixRenderer, fRenderer, fRendererBin, fUnpackedScanline, 223 fSubpixUnpackedScanline, fSubpixRasterizer, fMaskedUnpackedScanline, 224 fTransform) 225 { 226 fPixelFormat.SetDrawingMode(fDrawingMode, fAlphaSrcMode, fAlphaFncMode); 227 228 #if ALIASED_DRAWING 229 fRasterizer.gamma(agg::gamma_threshold(0.5)); 230 fSubpixRasterizer.gamma(agg:gamma_threshold(0.5)); 231 #endif 232 } 233 234 235 // destructor 236 Painter::~Painter() 237 { 238 } 239 240 241 // #pragma mark - 242 243 244 // AttachToBuffer 245 void 246 Painter::AttachToBuffer(RenderingBuffer* buffer) 247 { 248 if (buffer && buffer->InitCheck() >= B_OK 249 && (buffer->ColorSpace() == B_RGBA32 250 || buffer->ColorSpace() == B_RGB32)) { 251 // TODO: implement drawing on B_RGB24, B_RGB15, B_RGB16, 252 // B_CMAP8 and B_GRAY8 :-[ 253 // (if ever we want to support some devices where this gives 254 // a great speed up, right now it seems fine, even in emulation) 255 256 fBuffer.attach((uint8*)buffer->Bits(), 257 buffer->Width(), buffer->Height(), buffer->BytesPerRow()); 258 259 fAttached = true; 260 fValidClipping = fClippingRegion != NULL 261 && fClippingRegion->Frame().IsValid(); 262 263 // These are the AGG renderes and rasterizes which 264 // will be used for stroking paths 265 266 _SetRendererColor(fPatternHandler.HighColor()); 267 } 268 } 269 270 271 // DetachFromBuffer 272 void 273 Painter::DetachFromBuffer() 274 { 275 fBuffer.attach(NULL, 0, 0, 0); 276 fAttached = false; 277 fValidClipping = false; 278 } 279 280 281 // Bounds 282 BRect 283 Painter::Bounds() const 284 { 285 return BRect(0, 0, fBuffer.width() - 1, fBuffer.height() - 1); 286 } 287 288 289 // #pragma mark - 290 291 292 // SetDrawState 293 void 294 Painter::SetDrawState(const DrawState* state, int32 xOffset, int32 yOffset) 295 { 296 // NOTE: The custom clipping in "state" is ignored, because it has already 297 // been taken into account elsewhere 298 299 // NOTE: Usually this function is only used when the "current view" 300 // is switched in the ServerWindow and after the decorator has drawn 301 // and messed up the state. For other graphics state changes, the 302 // Painter methods are used directly, so this function is much less 303 // speed critical than it used to be. 304 305 SetTransform(state->CombinedTransform(), xOffset, yOffset); 306 307 SetPenSize(state->PenSize()); 308 309 SetFont(state); 310 311 fSubpixelPrecise = state->SubPixelPrecise(); 312 313 if (state->GetAlphaMask() != NULL) { 314 fMaskedUnpackedScanline = state->GetAlphaMask()->Scanline(); 315 fClippedAlphaMask = state->GetAlphaMask()->Mask(); 316 } else { 317 fMaskedUnpackedScanline = NULL; 318 fClippedAlphaMask = NULL; 319 } 320 321 // any of these conditions means we need to use a different drawing 322 // mode instance, but when the pattern changes it is already changed 323 // from SetPattern 324 bool updateDrawingMode 325 = state->GetPattern() == fPatternHandler.GetPattern() 326 && (state->GetDrawingMode() != fDrawingMode 327 || (state->GetDrawingMode() == B_OP_ALPHA 328 && (state->AlphaSrcMode() != fAlphaSrcMode 329 || state->AlphaFncMode() != fAlphaFncMode))); 330 331 fDrawingMode = state->GetDrawingMode(); 332 fAlphaSrcMode = state->AlphaSrcMode(); 333 fAlphaFncMode = state->AlphaFncMode(); 334 SetPattern(state->GetPattern().GetPattern()); 335 fPatternHandler.SetOffsets(xOffset, yOffset); 336 fLineCapMode = state->LineCapMode(); 337 fLineJoinMode = state->LineJoinMode(); 338 fMiterLimit = state->MiterLimit(); 339 340 SetFillRule(state->FillRule()); 341 342 // adopt the color *after* the pattern is set 343 // to set the renderers to the correct color 344 SetHighColor(state->HighColor()); 345 SetLowColor(state->LowColor()); 346 347 if (updateDrawingMode) 348 _UpdateDrawingMode(); 349 } 350 351 352 // #pragma mark - state 353 354 355 // ConstrainClipping 356 void 357 Painter::ConstrainClipping(const BRegion* region) 358 { 359 fClippingRegion = region; 360 fBaseRenderer.set_clipping_region(const_cast<BRegion*>(region)); 361 fValidClipping = region->Frame().IsValid() && fAttached; 362 363 if (fValidClipping) { 364 clipping_rect cb = fClippingRegion->FrameInt(); 365 fRasterizer.clip_box(cb.left, cb.top, cb.right + 1, cb.bottom + 1); 366 fSubpixRasterizer.clip_box(cb.left, cb.top, cb.right + 1, cb.bottom + 1); 367 } 368 } 369 370 371 void 372 Painter::SetTransform(BAffineTransform transform, int32 xOffset, int32 yOffset) 373 { 374 fIdentityTransform = transform.IsIdentity(); 375 if (!fIdentityTransform) { 376 fTransform = agg::trans_affine_translation(-xOffset, -yOffset); 377 fTransform *= agg::trans_affine(transform.sx, transform.shy, 378 transform.shx, transform.sy, transform.tx, transform.ty); 379 fTransform *= agg::trans_affine_translation(xOffset, yOffset); 380 } else { 381 fTransform.reset(); 382 } 383 } 384 385 386 // SetHighColor 387 void 388 Painter::SetHighColor(const rgb_color& color) 389 { 390 if (fPatternHandler.HighColor() == color) 391 return; 392 fPatternHandler.SetHighColor(color); 393 if (*(fPatternHandler.GetR5Pattern()) == B_SOLID_HIGH) 394 _SetRendererColor(color); 395 } 396 397 398 // SetLowColor 399 void 400 Painter::SetLowColor(const rgb_color& color) 401 { 402 fPatternHandler.SetLowColor(color); 403 if (*(fPatternHandler.GetR5Pattern()) == B_SOLID_LOW) 404 _SetRendererColor(color); 405 } 406 407 408 // SetDrawingMode 409 void 410 Painter::SetDrawingMode(drawing_mode mode) 411 { 412 if (fDrawingMode != mode) { 413 fDrawingMode = mode; 414 _UpdateDrawingMode(); 415 } 416 } 417 418 419 // SetBlendingMode 420 void 421 Painter::SetBlendingMode(source_alpha srcAlpha, alpha_function alphaFunc) 422 { 423 if (fAlphaSrcMode != srcAlpha || fAlphaFncMode != alphaFunc) { 424 fAlphaSrcMode = srcAlpha; 425 fAlphaFncMode = alphaFunc; 426 if (fDrawingMode == B_OP_ALPHA) 427 _UpdateDrawingMode(); 428 } 429 } 430 431 432 // SetPenSize 433 void 434 Painter::SetPenSize(float size) 435 { 436 fPenSize = size; 437 } 438 439 440 // SetStrokeMode 441 void 442 Painter::SetStrokeMode(cap_mode lineCap, join_mode joinMode, float miterLimit) 443 { 444 fLineCapMode = lineCap; 445 fLineJoinMode = joinMode; 446 fMiterLimit = miterLimit; 447 } 448 449 450 void 451 Painter::SetFillRule(int32 fillRule) 452 { 453 agg::filling_rule_e aggFillRule = fillRule == B_EVEN_ODD 454 ? agg::fill_even_odd : agg::fill_non_zero; 455 456 fRasterizer.filling_rule(aggFillRule); 457 fSubpixRasterizer.filling_rule(aggFillRule); 458 } 459 460 461 // SetPattern 462 void 463 Painter::SetPattern(const pattern& p) 464 { 465 if (p != *fPatternHandler.GetR5Pattern()) { 466 fPatternHandler.SetPattern(p); 467 _UpdateDrawingMode(); 468 469 // update renderer color if necessary 470 if (fPatternHandler.IsSolidHigh()) { 471 // pattern was not solid high before 472 _SetRendererColor(fPatternHandler.HighColor()); 473 } else if (fPatternHandler.IsSolidLow()) { 474 // pattern was not solid low before 475 _SetRendererColor(fPatternHandler.LowColor()); 476 } 477 } 478 } 479 480 481 // SetFont 482 void 483 Painter::SetFont(const ServerFont& font) 484 { 485 fTextRenderer.SetFont(font); 486 fTextRenderer.SetAntialiasing(!(font.Flags() & B_DISABLE_ANTIALIASING)); 487 } 488 489 490 // SetFont 491 void 492 Painter::SetFont(const DrawState* state) 493 { 494 fTextRenderer.SetFont(state->Font()); 495 fTextRenderer.SetAntialiasing(!state->ForceFontAliasing() 496 && (state->Font().Flags() & B_DISABLE_ANTIALIASING) == 0); 497 } 498 499 500 // #pragma mark - drawing 501 502 503 // StrokeLine 504 void 505 Painter::StrokeLine(BPoint a, BPoint b) 506 { 507 CHECK_CLIPPING_NO_RETURN 508 509 // "false" means not to do the pixel center offset, 510 // because it would mess up our optimized versions 511 _Align(&a, false); 512 _Align(&b, false); 513 514 // first, try an optimized version 515 if (fPenSize == 1.0 && fIdentityTransform 516 && (fDrawingMode == B_OP_COPY || fDrawingMode == B_OP_OVER) 517 && fMaskedUnpackedScanline == NULL) { 518 pattern pat = *fPatternHandler.GetR5Pattern(); 519 if (pat == B_SOLID_HIGH 520 && StraightLine(a, b, fPatternHandler.HighColor())) { 521 return; 522 } else if (pat == B_SOLID_LOW 523 && StraightLine(a, b, fPatternHandler.LowColor())) { 524 return; 525 } 526 } 527 528 fPath.remove_all(); 529 530 if (a == b) { 531 // special case dots 532 if (fPenSize == 1.0 && !fSubpixelPrecise && fIdentityTransform) { 533 if (fClippingRegion->Contains(a)) { 534 int dotX = (int)a.x; 535 int dotY = (int)a.y; 536 fBaseRenderer.translate_to_base_ren(dotX, dotY); 537 fPixelFormat.blend_pixel(dotX, dotY, fRenderer.color(), 538 255); 539 } 540 } else { 541 fPath.move_to(a.x, a.y); 542 fPath.line_to(a.x + 1, a.y); 543 fPath.line_to(a.x + 1, a.y + 1); 544 fPath.line_to(a.x, a.y + 1); 545 546 _FillPath(fPath); 547 } 548 } else { 549 // Do the pixel center offset here 550 if (!fSubpixelPrecise && fmodf(fPenSize, 2.0) != 0.0) { 551 _Align(&a, true); 552 _Align(&b, true); 553 } 554 555 fPath.move_to(a.x, a.y); 556 fPath.line_to(b.x, b.y); 557 558 if (!fSubpixelPrecise && fPenSize == 1.0f) { 559 // Tweak ends to "include" the pixel at the index, 560 // we need to do this in order to produce results like R5, 561 // where coordinates were inclusive 562 _StrokePath(fPath, B_SQUARE_CAP); 563 } else 564 _StrokePath(fPath); 565 } 566 } 567 568 569 // StraightLine 570 bool 571 Painter::StraightLine(BPoint a, BPoint b, const rgb_color& c) const 572 { 573 if (!fValidClipping) 574 return false; 575 576 if (a.x == b.x) { 577 // vertical 578 uint8* dst = fBuffer.row_ptr(0); 579 uint32 bpr = fBuffer.stride(); 580 int32 x = (int32)a.x; 581 dst += x * 4; 582 int32 y1 = (int32)min_c(a.y, b.y); 583 int32 y2 = (int32)max_c(a.y, b.y); 584 pixel32 color; 585 color.data8[0] = c.blue; 586 color.data8[1] = c.green; 587 color.data8[2] = c.red; 588 color.data8[3] = 255; 589 // draw a line, iterate over clipping boxes 590 fBaseRenderer.first_clip_box(); 591 do { 592 if (fBaseRenderer.xmin() <= x && 593 fBaseRenderer.xmax() >= x) { 594 int32 i = max_c(fBaseRenderer.ymin(), y1); 595 int32 end = min_c(fBaseRenderer.ymax(), y2); 596 uint8* handle = dst + i * bpr; 597 for (; i <= end; i++) { 598 *(uint32*)handle = color.data32; 599 handle += bpr; 600 } 601 } 602 } while (fBaseRenderer.next_clip_box()); 603 604 return true; 605 } 606 607 if (a.y == b.y) { 608 // horizontal 609 int32 y = (int32)a.y; 610 if (y < 0 || y >= (int32)fBuffer.height()) 611 return true; 612 613 uint8* dst = fBuffer.row_ptr(y); 614 int32 x1 = (int32)min_c(a.x, b.x); 615 int32 x2 = (int32)max_c(a.x, b.x); 616 pixel32 color; 617 color.data8[0] = c.blue; 618 color.data8[1] = c.green; 619 color.data8[2] = c.red; 620 color.data8[3] = 255; 621 // draw a line, iterate over clipping boxes 622 fBaseRenderer.first_clip_box(); 623 do { 624 if (fBaseRenderer.ymin() <= y && 625 fBaseRenderer.ymax() >= y) { 626 int32 i = max_c(fBaseRenderer.xmin(), x1); 627 int32 end = min_c(fBaseRenderer.xmax(), x2); 628 uint32* handle = (uint32*)(dst + i * 4); 629 for (; i <= end; i++) { 630 *handle++ = color.data32; 631 } 632 } 633 } while (fBaseRenderer.next_clip_box()); 634 635 return true; 636 } 637 return false; 638 } 639 640 641 // #pragma mark - 642 643 644 // StrokeTriangle 645 BRect 646 Painter::StrokeTriangle(BPoint pt1, BPoint pt2, BPoint pt3) const 647 { 648 return _DrawTriangle(pt1, pt2, pt3, false); 649 } 650 651 652 // FillTriangle 653 BRect 654 Painter::FillTriangle(BPoint pt1, BPoint pt2, BPoint pt3) const 655 { 656 return _DrawTriangle(pt1, pt2, pt3, true); 657 } 658 659 660 // FillTriangle 661 BRect 662 Painter::FillTriangle(BPoint pt1, BPoint pt2, BPoint pt3, 663 const BGradient& gradient) 664 { 665 CHECK_CLIPPING 666 667 _Align(&pt1); 668 _Align(&pt2); 669 _Align(&pt3); 670 671 fPath.remove_all(); 672 673 fPath.move_to(pt1.x, pt1.y); 674 fPath.line_to(pt2.x, pt2.y); 675 fPath.line_to(pt3.x, pt3.y); 676 677 fPath.close_polygon(); 678 679 return _FillPath(fPath, gradient); 680 } 681 682 683 // DrawPolygon 684 BRect 685 Painter::DrawPolygon(BPoint* p, int32 numPts, bool filled, bool closed) const 686 { 687 CHECK_CLIPPING 688 689 if (numPts == 0) 690 return BRect(0.0, 0.0, -1.0, -1.0); 691 692 bool centerOffset = !filled && fIdentityTransform 693 && fmodf(fPenSize, 2.0) != 0.0; 694 695 fPath.remove_all(); 696 697 _Align(p, centerOffset); 698 fPath.move_to(p->x, p->y); 699 700 for (int32 i = 1; i < numPts; i++) { 701 p++; 702 _Align(p, centerOffset); 703 fPath.line_to(p->x, p->y); 704 } 705 706 if (closed) 707 fPath.close_polygon(); 708 709 if (filled) 710 return _FillPath(fPath); 711 712 return _StrokePath(fPath); 713 } 714 715 716 // FillPolygon 717 BRect 718 Painter::FillPolygon(BPoint* p, int32 numPts, const BGradient& gradient, 719 bool closed) 720 { 721 CHECK_CLIPPING 722 723 if (numPts > 0) { 724 fPath.remove_all(); 725 726 _Align(p); 727 fPath.move_to(p->x, p->y); 728 729 for (int32 i = 1; i < numPts; i++) { 730 p++; 731 _Align(p); 732 fPath.line_to(p->x, p->y); 733 } 734 735 if (closed) 736 fPath.close_polygon(); 737 738 return _FillPath(fPath, gradient); 739 } 740 return BRect(0.0, 0.0, -1.0, -1.0); 741 } 742 743 744 // DrawBezier 745 BRect 746 Painter::DrawBezier(BPoint* p, bool filled) const 747 { 748 CHECK_CLIPPING 749 750 fPath.remove_all(); 751 752 _Align(&(p[0])); 753 _Align(&(p[1])); 754 _Align(&(p[2])); 755 _Align(&(p[3])); 756 757 fPath.move_to(p[0].x, p[0].y); 758 fPath.curve4(p[1].x, p[1].y, p[2].x, p[2].y, p[3].x, p[3].y); 759 760 if (filled) { 761 fPath.close_polygon(); 762 return _FillPath(fCurve); 763 } 764 765 return _StrokePath(fCurve); 766 } 767 768 769 // FillBezier 770 BRect 771 Painter::FillBezier(BPoint* p, const BGradient& gradient) 772 { 773 CHECK_CLIPPING 774 775 fPath.remove_all(); 776 777 _Align(&(p[0])); 778 _Align(&(p[1])); 779 _Align(&(p[2])); 780 _Align(&(p[3])); 781 782 fPath.move_to(p[0].x, p[0].y); 783 fPath.curve4(p[1].x, p[1].y, p[2].x, p[2].y, p[3].x, p[3].y); 784 785 fPath.close_polygon(); 786 return _FillPath(fCurve, gradient); 787 } 788 789 790 // DrawShape 791 BRect 792 Painter::DrawShape(const int32& opCount, const uint32* opList, 793 const int32& ptCount, const BPoint* points, bool filled, 794 const BPoint& viewToScreenOffset, float viewScale) const 795 { 796 CHECK_CLIPPING 797 798 _IterateShapeData(opCount, opList, ptCount, points, viewToScreenOffset, 799 viewScale); 800 801 if (filled) 802 return _FillPath(fCurve); 803 804 return _StrokePath(fCurve); 805 } 806 807 808 // FillShape 809 BRect 810 Painter::FillShape(const int32& opCount, const uint32* opList, 811 const int32& ptCount, const BPoint* points, const BGradient& gradient, 812 const BPoint& viewToScreenOffset, float viewScale) 813 { 814 CHECK_CLIPPING 815 816 _IterateShapeData(opCount, opList, ptCount, points, viewToScreenOffset, 817 viewScale); 818 819 return _FillPath(fCurve, gradient); 820 } 821 822 823 // StrokeRect 824 BRect 825 Painter::StrokeRect(const BRect& r) const 826 { 827 CHECK_CLIPPING 828 829 BPoint a(r.left, r.top); 830 BPoint b(r.right, r.bottom); 831 _Align(&a, false); 832 _Align(&b, false); 833 834 // first, try an optimized version 835 if (fPenSize == 1.0 && fIdentityTransform 836 && (fDrawingMode == B_OP_COPY || fDrawingMode == B_OP_OVER) 837 && fMaskedUnpackedScanline == NULL) { 838 pattern p = *fPatternHandler.GetR5Pattern(); 839 if (p == B_SOLID_HIGH) { 840 BRect rect(a, b); 841 StrokeRect(rect, fPatternHandler.HighColor()); 842 return _Clipped(rect); 843 } else if (p == B_SOLID_LOW) { 844 BRect rect(a, b); 845 StrokeRect(rect, fPatternHandler.LowColor()); 846 return _Clipped(rect); 847 } 848 } 849 850 if (fIdentityTransform && fmodf(fPenSize, 2.0) != 0.0) { 851 // shift coords to center of pixels 852 a.x += 0.5; 853 a.y += 0.5; 854 b.x += 0.5; 855 b.y += 0.5; 856 } 857 858 fPath.remove_all(); 859 fPath.move_to(a.x, a.y); 860 if (a.x == b.x || a.y == b.y) { 861 // special case rects with one pixel height or width 862 fPath.line_to(b.x, b.y); 863 } else { 864 fPath.line_to(b.x, a.y); 865 fPath.line_to(b.x, b.y); 866 fPath.line_to(a.x, b.y); 867 } 868 fPath.close_polygon(); 869 870 return _StrokePath(fPath); 871 } 872 873 874 // StrokeRect 875 void 876 Painter::StrokeRect(const BRect& r, const rgb_color& c) const 877 { 878 StraightLine(BPoint(r.left, r.top), BPoint(r.right - 1, r.top), c); 879 StraightLine(BPoint(r.right, r.top), BPoint(r.right, r.bottom - 1), c); 880 StraightLine(BPoint(r.right, r.bottom), BPoint(r.left + 1, r.bottom), c); 881 StraightLine(BPoint(r.left, r.bottom), BPoint(r.left, r.top + 1), c); 882 } 883 884 885 // FillRect 886 BRect 887 Painter::FillRect(const BRect& r) const 888 { 889 CHECK_CLIPPING 890 891 // support invalid rects 892 BPoint a(min_c(r.left, r.right), min_c(r.top, r.bottom)); 893 BPoint b(max_c(r.left, r.right), max_c(r.top, r.bottom)); 894 _Align(&a, true, false); 895 _Align(&b, true, false); 896 897 // first, try an optimized version 898 if ((fDrawingMode == B_OP_COPY || fDrawingMode == B_OP_OVER) 899 && fMaskedUnpackedScanline == NULL && fIdentityTransform) { 900 pattern p = *fPatternHandler.GetR5Pattern(); 901 if (p == B_SOLID_HIGH) { 902 BRect rect(a, b); 903 FillRect(rect, fPatternHandler.HighColor()); 904 return _Clipped(rect); 905 } else if (p == B_SOLID_LOW) { 906 BRect rect(a, b); 907 FillRect(rect, fPatternHandler.LowColor()); 908 return _Clipped(rect); 909 } 910 } 911 if (fDrawingMode == B_OP_ALPHA && fAlphaFncMode == B_ALPHA_OVERLAY 912 && fMaskedUnpackedScanline == NULL && fIdentityTransform) { 913 pattern p = *fPatternHandler.GetR5Pattern(); 914 if (p == B_SOLID_HIGH) { 915 BRect rect(a, b); 916 _BlendRect32(rect, fPatternHandler.HighColor()); 917 return _Clipped(rect); 918 } else if (p == B_SOLID_LOW) { 919 rgb_color c = fPatternHandler.LowColor(); 920 if (fAlphaSrcMode == B_CONSTANT_ALPHA) 921 c.alpha = fPatternHandler.HighColor().alpha; 922 BRect rect(a, b); 923 _BlendRect32(rect, c); 924 return _Clipped(rect); 925 } 926 } 927 928 // account for stricter interpretation of coordinates in AGG 929 // the rectangle ranges from the top-left (.0, .0) 930 // to the bottom-right (.9999, .9999) corner of pixels 931 b.x += 1.0; 932 b.y += 1.0; 933 934 fPath.remove_all(); 935 fPath.move_to(a.x, a.y); 936 fPath.line_to(b.x, a.y); 937 fPath.line_to(b.x, b.y); 938 fPath.line_to(a.x, b.y); 939 fPath.close_polygon(); 940 941 return _FillPath(fPath); 942 } 943 944 945 // FillRect 946 BRect 947 Painter::FillRect(const BRect& r, const BGradient& gradient) 948 { 949 CHECK_CLIPPING 950 951 // support invalid rects 952 BPoint a(min_c(r.left, r.right), min_c(r.top, r.bottom)); 953 BPoint b(max_c(r.left, r.right), max_c(r.top, r.bottom)); 954 _Align(&a, true, false); 955 _Align(&b, true, false); 956 957 // first, try an optimized version 958 if (gradient.GetType() == BGradient::TYPE_LINEAR 959 && (fDrawingMode == B_OP_COPY || fDrawingMode == B_OP_OVER) 960 && fMaskedUnpackedScanline == NULL && fIdentityTransform) { 961 const BGradientLinear* linearGradient 962 = dynamic_cast<const BGradientLinear*>(&gradient); 963 if (linearGradient->Start().x == linearGradient->End().x 964 // TODO: Remove this second check once the optimized method 965 // handled "upside down" gradients as well... 966 && linearGradient->Start().y <= linearGradient->End().y) { 967 // a vertical gradient 968 BRect rect(a, b); 969 FillRectVerticalGradient(rect, *linearGradient); 970 return _Clipped(rect); 971 } 972 } 973 974 // account for stricter interpretation of coordinates in AGG 975 // the rectangle ranges from the top-left (.0, .0) 976 // to the bottom-right (.9999, .9999) corner of pixels 977 b.x += 1.0; 978 b.y += 1.0; 979 980 fPath.remove_all(); 981 fPath.move_to(a.x, a.y); 982 fPath.line_to(b.x, a.y); 983 fPath.line_to(b.x, b.y); 984 fPath.line_to(a.x, b.y); 985 fPath.close_polygon(); 986 987 return _FillPath(fPath, gradient); 988 } 989 990 991 // FillRect 992 void 993 Painter::FillRect(const BRect& r, const rgb_color& c) const 994 { 995 if (!fValidClipping) 996 return; 997 998 uint8* dst = fBuffer.row_ptr(0); 999 uint32 bpr = fBuffer.stride(); 1000 int32 left = (int32)r.left; 1001 int32 top = (int32)r.top; 1002 int32 right = (int32)r.right; 1003 int32 bottom = (int32)r.bottom; 1004 // get a 32 bit pixel ready with the color 1005 pixel32 color; 1006 color.data8[0] = c.blue; 1007 color.data8[1] = c.green; 1008 color.data8[2] = c.red; 1009 color.data8[3] = c.alpha; 1010 // fill rects, iterate over clipping boxes 1011 fBaseRenderer.first_clip_box(); 1012 do { 1013 int32 x1 = max_c(fBaseRenderer.xmin(), left); 1014 int32 x2 = min_c(fBaseRenderer.xmax(), right); 1015 if (x1 <= x2) { 1016 int32 y1 = max_c(fBaseRenderer.ymin(), top); 1017 int32 y2 = min_c(fBaseRenderer.ymax(), bottom); 1018 uint8* offset = dst + x1 * 4; 1019 for (; y1 <= y2; y1++) { 1020 // uint32* handle = (uint32*)(offset + y1 * bpr); 1021 // for (int32 x = x1; x <= x2; x++) { 1022 // *handle++ = color.data32; 1023 // } 1024 gfxset32(offset + y1 * bpr, color.data32, (x2 - x1 + 1) * 4); 1025 } 1026 } 1027 } while (fBaseRenderer.next_clip_box()); 1028 } 1029 1030 1031 // FillRectVerticalGradient 1032 void 1033 Painter::FillRectVerticalGradient(BRect r, 1034 const BGradientLinear& gradient) const 1035 { 1036 if (!fValidClipping) 1037 return; 1038 1039 // Make sure the color array is no larger than the screen height. 1040 r = r & fClippingRegion->Frame(); 1041 1042 int32 gradientArraySize = r.IntegerHeight() + 1; 1043 uint32 gradientArray[gradientArraySize]; 1044 int32 gradientTop = (int32)gradient.Start().y; 1045 int32 gradientBottom = (int32)gradient.End().y; 1046 int32 colorCount = gradientBottom - gradientTop + 1; 1047 if (colorCount < 0) { 1048 // Gradient is upside down. That's currently not supported by this 1049 // method. 1050 return; 1051 } 1052 1053 _MakeGradient(gradient, colorCount, gradientArray, 1054 gradientTop - (int32)r.top, gradientArraySize); 1055 1056 uint8* dst = fBuffer.row_ptr(0); 1057 uint32 bpr = fBuffer.stride(); 1058 int32 left = (int32)r.left; 1059 int32 top = (int32)r.top; 1060 int32 right = (int32)r.right; 1061 int32 bottom = (int32)r.bottom; 1062 // fill rects, iterate over clipping boxes 1063 fBaseRenderer.first_clip_box(); 1064 do { 1065 int32 x1 = max_c(fBaseRenderer.xmin(), left); 1066 int32 x2 = min_c(fBaseRenderer.xmax(), right); 1067 if (x1 <= x2) { 1068 int32 y1 = max_c(fBaseRenderer.ymin(), top); 1069 int32 y2 = min_c(fBaseRenderer.ymax(), bottom); 1070 uint8* offset = dst + x1 * 4; 1071 for (; y1 <= y2; y1++) { 1072 // uint32* handle = (uint32*)(offset + y1 * bpr); 1073 // for (int32 x = x1; x <= x2; x++) { 1074 // *handle++ = gradientArray[y1 - top]; 1075 // } 1076 gfxset32(offset + y1 * bpr, gradientArray[y1 - top], 1077 (x2 - x1 + 1) * 4); 1078 } 1079 } 1080 } while (fBaseRenderer.next_clip_box()); 1081 } 1082 1083 1084 // FillRectNoClipping 1085 void 1086 Painter::FillRectNoClipping(const clipping_rect& r, const rgb_color& c) const 1087 { 1088 int32 y = (int32)r.top; 1089 1090 uint8* dst = fBuffer.row_ptr(y) + r.left * 4; 1091 uint32 bpr = fBuffer.stride(); 1092 int32 bytes = (r.right - r.left + 1) * 4; 1093 1094 // get a 32 bit pixel ready with the color 1095 pixel32 color; 1096 color.data8[0] = c.blue; 1097 color.data8[1] = c.green; 1098 color.data8[2] = c.red; 1099 color.data8[3] = c.alpha; 1100 1101 for (; y <= r.bottom; y++) { 1102 // uint32* handle = (uint32*)dst; 1103 // for (int32 x = left; x <= right; x++) { 1104 // *handle++ = color.data32; 1105 // } 1106 gfxset32(dst, color.data32, bytes); 1107 dst += bpr; 1108 } 1109 } 1110 1111 1112 // StrokeRoundRect 1113 BRect 1114 Painter::StrokeRoundRect(const BRect& r, float xRadius, float yRadius) const 1115 { 1116 CHECK_CLIPPING 1117 1118 BPoint lt(r.left, r.top); 1119 BPoint rb(r.right, r.bottom); 1120 bool centerOffset = fmodf(fPenSize, 2.0) != 0.0; 1121 _Align(<, centerOffset); 1122 _Align(&rb, centerOffset); 1123 1124 agg::rounded_rect rect; 1125 rect.rect(lt.x, lt.y, rb.x, rb.y); 1126 rect.radius(xRadius, yRadius); 1127 1128 return _StrokePath(rect); 1129 } 1130 1131 1132 // FillRoundRect 1133 BRect 1134 Painter::FillRoundRect(const BRect& r, float xRadius, float yRadius) const 1135 { 1136 CHECK_CLIPPING 1137 1138 BPoint lt(r.left, r.top); 1139 BPoint rb(r.right, r.bottom); 1140 _Align(<, false); 1141 _Align(&rb, false); 1142 1143 // account for stricter interpretation of coordinates in AGG 1144 // the rectangle ranges from the top-left (.0, .0) 1145 // to the bottom-right (.9999, .9999) corner of pixels 1146 rb.x += 1.0; 1147 rb.y += 1.0; 1148 1149 agg::rounded_rect rect; 1150 rect.rect(lt.x, lt.y, rb.x, rb.y); 1151 rect.radius(xRadius, yRadius); 1152 1153 return _FillPath(rect); 1154 } 1155 1156 1157 // FillRoundRect 1158 BRect 1159 Painter::FillRoundRect(const BRect& r, float xRadius, float yRadius, 1160 const BGradient& gradient) 1161 { 1162 CHECK_CLIPPING 1163 1164 BPoint lt(r.left, r.top); 1165 BPoint rb(r.right, r.bottom); 1166 _Align(<, false); 1167 _Align(&rb, false); 1168 1169 // account for stricter interpretation of coordinates in AGG 1170 // the rectangle ranges from the top-left (.0, .0) 1171 // to the bottom-right (.9999, .9999) corner of pixels 1172 rb.x += 1.0; 1173 rb.y += 1.0; 1174 1175 agg::rounded_rect rect; 1176 rect.rect(lt.x, lt.y, rb.x, rb.y); 1177 rect.radius(xRadius, yRadius); 1178 1179 return _FillPath(rect, gradient); 1180 } 1181 1182 1183 // AlignEllipseRect 1184 void 1185 Painter::AlignEllipseRect(BRect* rect, bool filled) const 1186 { 1187 if (!fSubpixelPrecise) { 1188 // align rect to pixels 1189 align_rect_to_pixels(rect); 1190 // account for "pixel index" versus "pixel area" 1191 rect->right++; 1192 rect->bottom++; 1193 if (!filled && fmodf(fPenSize, 2.0) != 0.0) { 1194 // align the stroke 1195 rect->InsetBy(0.5, 0.5); 1196 } 1197 } 1198 } 1199 1200 1201 // DrawEllipse 1202 BRect 1203 Painter::DrawEllipse(BRect r, bool fill) const 1204 { 1205 CHECK_CLIPPING 1206 1207 AlignEllipseRect(&r, fill); 1208 1209 float xRadius = r.Width() / 2.0; 1210 float yRadius = r.Height() / 2.0; 1211 BPoint center(r.left + xRadius, r.top + yRadius); 1212 1213 int32 divisions = (int32)((xRadius + yRadius + 2 * fPenSize) * M_PI / 2); 1214 if (divisions < 12) 1215 divisions = 12; 1216 if (divisions > 4096) 1217 divisions = 4096; 1218 1219 agg::ellipse path(center.x, center.y, xRadius, yRadius, divisions); 1220 1221 if (fill) 1222 return _FillPath(path); 1223 else 1224 return _StrokePath(path); 1225 } 1226 1227 1228 // FillEllipse 1229 BRect 1230 Painter::FillEllipse(BRect r, const BGradient& gradient) 1231 { 1232 CHECK_CLIPPING 1233 1234 AlignEllipseRect(&r, true); 1235 1236 float xRadius = r.Width() / 2.0; 1237 float yRadius = r.Height() / 2.0; 1238 BPoint center(r.left + xRadius, r.top + yRadius); 1239 1240 int32 divisions = (int32)((xRadius + yRadius + 2 * fPenSize) * M_PI / 2); 1241 if (divisions < 12) 1242 divisions = 12; 1243 if (divisions > 4096) 1244 divisions = 4096; 1245 1246 agg::ellipse path(center.x, center.y, xRadius, yRadius, divisions); 1247 1248 return _FillPath(path, gradient); 1249 } 1250 1251 1252 // StrokeArc 1253 BRect 1254 Painter::StrokeArc(BPoint center, float xRadius, float yRadius, float angle, 1255 float span) const 1256 { 1257 CHECK_CLIPPING 1258 1259 _Align(¢er); 1260 1261 double angleRad = (angle * M_PI) / 180.0; 1262 double spanRad = (span * M_PI) / 180.0; 1263 agg::bezier_arc arc(center.x, center.y, xRadius, yRadius, -angleRad, 1264 -spanRad); 1265 1266 agg::conv_curve<agg::bezier_arc> path(arc); 1267 path.approximation_scale(2.0); 1268 1269 return _StrokePath(path); 1270 } 1271 1272 1273 // FillArc 1274 BRect 1275 Painter::FillArc(BPoint center, float xRadius, float yRadius, float angle, 1276 float span) const 1277 { 1278 CHECK_CLIPPING 1279 1280 _Align(¢er); 1281 1282 double angleRad = (angle * M_PI) / 180.0; 1283 double spanRad = (span * M_PI) / 180.0; 1284 agg::bezier_arc arc(center.x, center.y, xRadius, yRadius, -angleRad, 1285 -spanRad); 1286 1287 agg::conv_curve<agg::bezier_arc> segmentedArc(arc); 1288 1289 fPath.remove_all(); 1290 1291 // build a new path by starting at the center point, 1292 // then traversing the arc, then going back to the center 1293 fPath.move_to(center.x, center.y); 1294 1295 segmentedArc.rewind(0); 1296 double x; 1297 double y; 1298 unsigned cmd = segmentedArc.vertex(&x, &y); 1299 while (!agg::is_stop(cmd)) { 1300 fPath.line_to(x, y); 1301 cmd = segmentedArc.vertex(&x, &y); 1302 } 1303 1304 fPath.close_polygon(); 1305 1306 return _FillPath(fPath); 1307 } 1308 1309 1310 // FillArc 1311 BRect 1312 Painter::FillArc(BPoint center, float xRadius, float yRadius, float angle, 1313 float span, const BGradient& gradient) 1314 { 1315 CHECK_CLIPPING 1316 1317 _Align(¢er); 1318 1319 double angleRad = (angle * M_PI) / 180.0; 1320 double spanRad = (span * M_PI) / 180.0; 1321 agg::bezier_arc arc(center.x, center.y, xRadius, yRadius, -angleRad, 1322 -spanRad); 1323 1324 agg::conv_curve<agg::bezier_arc> segmentedArc(arc); 1325 1326 fPath.remove_all(); 1327 1328 // build a new path by starting at the center point, 1329 // then traversing the arc, then going back to the center 1330 fPath.move_to(center.x, center.y); 1331 1332 segmentedArc.rewind(0); 1333 double x; 1334 double y; 1335 unsigned cmd = segmentedArc.vertex(&x, &y); 1336 while (!agg::is_stop(cmd)) { 1337 fPath.line_to(x, y); 1338 cmd = segmentedArc.vertex(&x, &y); 1339 } 1340 1341 fPath.close_polygon(); 1342 1343 return _FillPath(fPath, gradient); 1344 } 1345 1346 1347 // #pragma mark - 1348 1349 1350 // DrawString 1351 BRect 1352 Painter::DrawString(const char* utf8String, uint32 length, BPoint baseLine, 1353 const escapement_delta* delta, FontCacheReference* cacheReference) 1354 { 1355 CHECK_CLIPPING 1356 1357 if (!fSubpixelPrecise) { 1358 baseLine.x = roundf(baseLine.x); 1359 baseLine.y = roundf(baseLine.y); 1360 } 1361 1362 BRect bounds; 1363 1364 SolidPatternGuard _(this); 1365 1366 bounds = fTextRenderer.RenderString(utf8String, length, 1367 baseLine, fClippingRegion->Frame(), false, NULL, delta, 1368 cacheReference); 1369 1370 return _Clipped(bounds); 1371 } 1372 1373 1374 // DrawString 1375 BRect 1376 Painter::DrawString(const char* utf8String, uint32 length, 1377 const BPoint* offsets, FontCacheReference* cacheReference) 1378 { 1379 CHECK_CLIPPING 1380 1381 // TODO: Round offsets to device pixel grid if !fSubpixelPrecise? 1382 1383 BRect bounds; 1384 1385 SolidPatternGuard _(this); 1386 1387 bounds = fTextRenderer.RenderString(utf8String, length, 1388 offsets, fClippingRegion->Frame(), false, NULL, 1389 cacheReference); 1390 1391 return _Clipped(bounds); 1392 } 1393 1394 1395 // BoundingBox 1396 BRect 1397 Painter::BoundingBox(const char* utf8String, uint32 length, BPoint baseLine, 1398 BPoint* penLocation, const escapement_delta* delta, 1399 FontCacheReference* cacheReference) const 1400 { 1401 if (!fSubpixelPrecise) { 1402 baseLine.x = roundf(baseLine.x); 1403 baseLine.y = roundf(baseLine.y); 1404 } 1405 1406 static BRect dummy; 1407 return fTextRenderer.RenderString(utf8String, length, 1408 baseLine, dummy, true, penLocation, delta, cacheReference); 1409 } 1410 1411 1412 // BoundingBox 1413 BRect 1414 Painter::BoundingBox(const char* utf8String, uint32 length, 1415 const BPoint* offsets, BPoint* penLocation, 1416 FontCacheReference* cacheReference) const 1417 { 1418 // TODO: Round offsets to device pixel grid if !fSubpixelPrecise? 1419 1420 static BRect dummy; 1421 return fTextRenderer.RenderString(utf8String, length, 1422 offsets, dummy, true, penLocation, cacheReference); 1423 } 1424 1425 1426 // StringWidth 1427 float 1428 Painter::StringWidth(const char* utf8String, uint32 length, 1429 const escapement_delta* delta) 1430 { 1431 return Font().StringWidth(utf8String, length, delta); 1432 } 1433 1434 1435 // #pragma mark - 1436 1437 1438 // DrawBitmap 1439 BRect 1440 Painter::DrawBitmap(const ServerBitmap* bitmap, BRect bitmapRect, 1441 BRect viewRect, uint32 options) const 1442 { 1443 CHECK_CLIPPING 1444 1445 BRect touched = TransformAlignAndClipRect(viewRect); 1446 1447 if (touched.IsValid()) { 1448 BitmapPainter bitmapPainter(this, bitmap, options); 1449 bitmapPainter.Draw(bitmapRect, viewRect); 1450 } 1451 1452 return touched; 1453 } 1454 1455 1456 // #pragma mark - 1457 1458 1459 // FillRegion 1460 BRect 1461 Painter::FillRegion(const BRegion* region) const 1462 { 1463 CHECK_CLIPPING 1464 1465 BRegion copy(*region); 1466 int32 count = copy.CountRects(); 1467 BRect touched = FillRect(copy.RectAt(0)); 1468 for (int32 i = 1; i < count; i++) { 1469 touched = touched | FillRect(copy.RectAt(i)); 1470 } 1471 return touched; 1472 } 1473 1474 1475 // FillRegion 1476 BRect 1477 Painter::FillRegion(const BRegion* region, const BGradient& gradient) 1478 { 1479 CHECK_CLIPPING 1480 1481 BRegion copy(*region); 1482 int32 count = copy.CountRects(); 1483 BRect touched = FillRect(copy.RectAt(0), gradient); 1484 for (int32 i = 1; i < count; i++) { 1485 touched = touched | FillRect(copy.RectAt(i), gradient); 1486 } 1487 return touched; 1488 } 1489 1490 1491 // InvertRect 1492 BRect 1493 Painter::InvertRect(const BRect& r) const 1494 { 1495 CHECK_CLIPPING 1496 1497 BRegion region(r); 1498 region.IntersectWith(fClippingRegion); 1499 1500 // implementation only for B_RGB32 at the moment 1501 int32 count = region.CountRects(); 1502 for (int32 i = 0; i < count; i++) 1503 _InvertRect32(region.RectAt(i)); 1504 1505 return _Clipped(r); 1506 } 1507 1508 1509 void 1510 Painter::SetRendererOffset(int32 offsetX, int32 offsetY) 1511 { 1512 fBaseRenderer.set_offset(offsetX, offsetY); 1513 } 1514 1515 1516 // #pragma mark - private 1517 1518 1519 inline float 1520 Painter::_Align(float coord, bool round, bool centerOffset) const 1521 { 1522 // rounding 1523 if (round) 1524 coord = (int32)coord; 1525 1526 // This code is supposed to move coordinates to the center of pixels, 1527 // as AGG considers (0,0) to be the "upper left corner" of a pixel, 1528 // but BViews are less strict on those details 1529 if (centerOffset) 1530 coord += 0.5; 1531 1532 return coord; 1533 } 1534 1535 1536 inline void 1537 Painter::_Align(BPoint* point, bool centerOffset) const 1538 { 1539 _Align(point, !fSubpixelPrecise, centerOffset); 1540 } 1541 1542 1543 inline void 1544 Painter::_Align(BPoint* point, bool round, bool centerOffset) const 1545 { 1546 point->x = _Align(point->x, round, centerOffset); 1547 point->y = _Align(point->y, round, centerOffset); 1548 } 1549 1550 1551 inline BPoint 1552 Painter::_Align(const BPoint& point, bool centerOffset) const 1553 { 1554 BPoint ret(point); 1555 _Align(&ret, centerOffset); 1556 return ret; 1557 } 1558 1559 1560 // _Clipped 1561 BRect 1562 Painter::_Clipped(const BRect& rect) const 1563 { 1564 if (rect.IsValid()) 1565 return BRect(rect & fClippingRegion->Frame()); 1566 1567 return BRect(rect); 1568 } 1569 1570 1571 // _UpdateDrawingMode 1572 void 1573 Painter::_UpdateDrawingMode() 1574 { 1575 // The AGG renderers have their own color setting, however 1576 // almost all drawing mode classes ignore the color given 1577 // by the AGG renderer and use the colors from the PatternHandler 1578 // instead. If we have a B_SOLID_* pattern, we can actually use 1579 // the color in the renderer and special versions of drawing modes 1580 // that don't use PatternHandler and are more efficient. This 1581 // has been implemented for B_OP_COPY and a couple others (the 1582 // DrawingMode*Solid ones) as of now. The PixelFormat knows the 1583 // PatternHandler and makes its decision based on the pattern. 1584 // When a solid pattern is used, _SetRendererColor() 1585 // has to be called so that all internal colors in the renderes 1586 // are up to date for use by the solid drawing mode version. 1587 fPixelFormat.SetDrawingMode(fDrawingMode, fAlphaSrcMode, fAlphaFncMode); 1588 } 1589 1590 1591 // _SetRendererColor 1592 void 1593 Painter::_SetRendererColor(const rgb_color& color) const 1594 { 1595 fRenderer.color(agg::rgba(color.red / 255.0, color.green / 255.0, 1596 color.blue / 255.0, color.alpha / 255.0)); 1597 fSubpixRenderer.color(agg::rgba(color.red / 255.0, color.green / 255.0, 1598 color.blue / 255.0, color.alpha / 255.0)); 1599 // TODO: bitmap fonts not yet correctly setup in AGGTextRenderer 1600 // fRendererBin.color(agg::rgba(color.red / 255.0, color.green / 255.0, 1601 // color.blue / 255.0, color.alpha / 255.0)); 1602 } 1603 1604 1605 // #pragma mark - 1606 1607 1608 // _DrawTriangle 1609 inline BRect 1610 Painter::_DrawTriangle(BPoint pt1, BPoint pt2, BPoint pt3, bool fill) const 1611 { 1612 CHECK_CLIPPING 1613 1614 _Align(&pt1); 1615 _Align(&pt2); 1616 _Align(&pt3); 1617 1618 fPath.remove_all(); 1619 1620 fPath.move_to(pt1.x, pt1.y); 1621 fPath.line_to(pt2.x, pt2.y); 1622 fPath.line_to(pt3.x, pt3.y); 1623 1624 fPath.close_polygon(); 1625 1626 if (fill) 1627 return _FillPath(fPath); 1628 1629 return _StrokePath(fPath); 1630 } 1631 1632 1633 void 1634 Painter::_IterateShapeData(const int32& opCount, const uint32* opList, 1635 const int32& ptCount, const BPoint* points, 1636 const BPoint& viewToScreenOffset, float viewScale) const 1637 { 1638 // TODO: if shapes are ever used more heavily in Haiku, 1639 // it would be nice to use BShape data directly (write 1640 // an AGG "VertexSource" adaptor) 1641 fPath.remove_all(); 1642 for (int32 i = 0; i < opCount; i++) { 1643 uint32 op = opList[i] & 0xFF000000; 1644 if ((op & OP_MOVETO) != 0) { 1645 fPath.move_to( 1646 points->x * viewScale + viewToScreenOffset.x, 1647 points->y * viewScale + viewToScreenOffset.y); 1648 points++; 1649 } 1650 1651 if ((op & OP_LINETO) != 0) { 1652 int32 count = opList[i] & 0x00FFFFFF; 1653 while (count--) { 1654 fPath.line_to( 1655 points->x * viewScale + viewToScreenOffset.x, 1656 points->y * viewScale + viewToScreenOffset.y); 1657 points++; 1658 } 1659 } 1660 1661 if ((op & OP_BEZIERTO) != 0) { 1662 int32 count = opList[i] & 0x00FFFFFF; 1663 while (count) { 1664 fPath.curve4( 1665 points[0].x * viewScale + viewToScreenOffset.x, 1666 points[0].y * viewScale + viewToScreenOffset.y, 1667 points[1].x * viewScale + viewToScreenOffset.x, 1668 points[1].y * viewScale + viewToScreenOffset.y, 1669 points[2].x * viewScale + viewToScreenOffset.x, 1670 points[2].y * viewScale + viewToScreenOffset.y); 1671 points += 3; 1672 count -= 3; 1673 } 1674 } 1675 1676 if ((op & OP_LARGE_ARC_TO_CW) != 0 || (op & OP_LARGE_ARC_TO_CCW) != 0 1677 || (op & OP_SMALL_ARC_TO_CW) != 0 1678 || (op & OP_SMALL_ARC_TO_CCW) != 0) { 1679 int32 count = opList[i] & 0x00FFFFFF; 1680 while (count > 0) { 1681 fPath.arc_to( 1682 points[0].x * viewScale, 1683 points[0].y * viewScale, 1684 points[1].x, 1685 op & (OP_LARGE_ARC_TO_CW | OP_LARGE_ARC_TO_CCW), 1686 op & (OP_SMALL_ARC_TO_CW | OP_LARGE_ARC_TO_CW), 1687 points[2].x * viewScale + viewToScreenOffset.x, 1688 points[2].y * viewScale + viewToScreenOffset.y); 1689 points += 3; 1690 count -= 3; 1691 } 1692 } 1693 1694 if ((op & OP_CLOSE) != 0) 1695 fPath.close_polygon(); 1696 } 1697 } 1698 1699 1700 // _InvertRect32 1701 void 1702 Painter::_InvertRect32(BRect r) const 1703 { 1704 int32 width = r.IntegerWidth() + 1; 1705 for (int32 y = (int32)r.top; y <= (int32)r.bottom; y++) { 1706 uint8* dst = fBuffer.row_ptr(y); 1707 dst += (int32)r.left * 4; 1708 for (int32 i = 0; i < width; i++) { 1709 dst[0] = 255 - dst[0]; 1710 dst[1] = 255 - dst[1]; 1711 dst[2] = 255 - dst[2]; 1712 dst += 4; 1713 } 1714 } 1715 } 1716 1717 1718 // _BlendRect32 1719 void 1720 Painter::_BlendRect32(const BRect& r, const rgb_color& c) const 1721 { 1722 if (!fValidClipping) 1723 return; 1724 1725 uint8* dst = fBuffer.row_ptr(0); 1726 uint32 bpr = fBuffer.stride(); 1727 1728 int32 left = (int32)r.left; 1729 int32 top = (int32)r.top; 1730 int32 right = (int32)r.right; 1731 int32 bottom = (int32)r.bottom; 1732 1733 // fill rects, iterate over clipping boxes 1734 fBaseRenderer.first_clip_box(); 1735 do { 1736 int32 x1 = max_c(fBaseRenderer.xmin(), left); 1737 int32 x2 = min_c(fBaseRenderer.xmax(), right); 1738 if (x1 <= x2) { 1739 int32 y1 = max_c(fBaseRenderer.ymin(), top); 1740 int32 y2 = min_c(fBaseRenderer.ymax(), bottom); 1741 1742 uint8* offset = dst + x1 * 4 + y1 * bpr; 1743 for (; y1 <= y2; y1++) { 1744 blend_line32(offset, x2 - x1 + 1, c.red, c.green, c.blue, 1745 c.alpha); 1746 offset += bpr; 1747 } 1748 } 1749 } while (fBaseRenderer.next_clip_box()); 1750 } 1751 1752 1753 // #pragma mark - 1754 1755 1756 template<class VertexSource> 1757 BRect 1758 Painter::_BoundingBox(VertexSource& path) const 1759 { 1760 double left = 0.0; 1761 double top = 0.0; 1762 double right = -1.0; 1763 double bottom = -1.0; 1764 uint32 pathID[1]; 1765 pathID[0] = 0; 1766 agg::bounding_rect(path, pathID, 0, 1, &left, &top, &right, &bottom); 1767 return BRect(left, top, right, bottom); 1768 } 1769 1770 1771 // agg_line_cap_mode_for 1772 inline agg::line_cap_e 1773 agg_line_cap_mode_for(cap_mode mode) 1774 { 1775 switch (mode) { 1776 case B_BUTT_CAP: 1777 return agg::butt_cap; 1778 case B_SQUARE_CAP: 1779 return agg::square_cap; 1780 case B_ROUND_CAP: 1781 return agg::round_cap; 1782 } 1783 return agg::butt_cap; 1784 } 1785 1786 1787 // agg_line_join_mode_for 1788 inline agg::line_join_e 1789 agg_line_join_mode_for(join_mode mode) 1790 { 1791 switch (mode) { 1792 case B_MITER_JOIN: 1793 return agg::miter_join; 1794 case B_ROUND_JOIN: 1795 return agg::round_join; 1796 case B_BEVEL_JOIN: 1797 case B_BUTT_JOIN: // ?? 1798 case B_SQUARE_JOIN: // ?? 1799 return agg::bevel_join; 1800 } 1801 return agg::miter_join; 1802 } 1803 1804 1805 template<class VertexSource> 1806 BRect 1807 Painter::_StrokePath(VertexSource& path) const 1808 { 1809 return _StrokePath(path, fLineCapMode); 1810 } 1811 1812 1813 template<class VertexSource> 1814 BRect 1815 Painter::_StrokePath(VertexSource& path, cap_mode capMode) const 1816 { 1817 agg::conv_stroke<VertexSource> stroke(path); 1818 stroke.width(fPenSize); 1819 1820 stroke.line_cap(agg_line_cap_mode_for(capMode)); 1821 stroke.line_join(agg_line_join_mode_for(fLineJoinMode)); 1822 stroke.miter_limit(fMiterLimit); 1823 1824 if (fIdentityTransform) 1825 return _RasterizePath(stroke); 1826 1827 stroke.approximation_scale(fTransform.scale()); 1828 1829 agg::conv_transform<agg::conv_stroke<VertexSource> > transformedStroke( 1830 stroke, fTransform); 1831 return _RasterizePath(transformedStroke); 1832 } 1833 1834 1835 // _FillPath 1836 template<class VertexSource> 1837 BRect 1838 Painter::_FillPath(VertexSource& path) const 1839 { 1840 if (fIdentityTransform) 1841 return _RasterizePath(path); 1842 1843 agg::conv_transform<VertexSource> transformedPath(path, fTransform); 1844 return _RasterizePath(transformedPath); 1845 } 1846 1847 1848 // _RasterizePath 1849 template<class VertexSource> 1850 BRect 1851 Painter::_RasterizePath(VertexSource& path) const 1852 { 1853 if (fMaskedUnpackedScanline != NULL) { 1854 // TODO: we can't do both alpha-masking and subpixel AA. 1855 fRasterizer.reset(); 1856 fRasterizer.add_path(path); 1857 agg::render_scanlines(fRasterizer, *fMaskedUnpackedScanline, 1858 fRenderer); 1859 } else if (gSubpixelAntialiasing) { 1860 fSubpixRasterizer.reset(); 1861 fSubpixRasterizer.add_path(path); 1862 agg::render_scanlines(fSubpixRasterizer, 1863 fSubpixPackedScanline, fSubpixRenderer); 1864 } else { 1865 fRasterizer.reset(); 1866 fRasterizer.add_path(path); 1867 agg::render_scanlines(fRasterizer, fPackedScanline, fRenderer); 1868 } 1869 1870 return _Clipped(_BoundingBox(path)); 1871 } 1872 1873 1874 // _FillPath 1875 template<class VertexSource> 1876 BRect 1877 Painter::_FillPath(VertexSource& path, const BGradient& gradient) 1878 { 1879 if (fIdentityTransform) 1880 return _RasterizePath(path, gradient); 1881 1882 agg::conv_transform<VertexSource> transformedPath(path, fTransform); 1883 return _RasterizePath(transformedPath, gradient); 1884 } 1885 1886 1887 // _FillPath 1888 template<class VertexSource> 1889 BRect 1890 Painter::_RasterizePath(VertexSource& path, const BGradient& gradient) 1891 { 1892 GTRACE("Painter::_RasterizePath\n"); 1893 1894 agg::trans_affine gradientTransform; 1895 1896 switch (gradient.GetType()) { 1897 case BGradient::TYPE_LINEAR: 1898 { 1899 GTRACE(("Painter::_FillPath> type == TYPE_LINEAR\n")); 1900 const BGradientLinear& linearGradient 1901 = (const BGradientLinear&) gradient; 1902 agg::gradient_x gradientFunction; 1903 _CalcLinearGradientTransform(linearGradient.Start(), 1904 linearGradient.End(), gradientTransform); 1905 _RasterizePath(path, gradient, gradientFunction, gradientTransform); 1906 break; 1907 } 1908 case BGradient::TYPE_RADIAL: 1909 { 1910 GTRACE(("Painter::_FillPathGradient> type == TYPE_RADIAL\n")); 1911 const BGradientRadial& radialGradient 1912 = (const BGradientRadial&) gradient; 1913 agg::gradient_radial gradientFunction; 1914 _CalcRadialGradientTransform(radialGradient.Center(), 1915 gradientTransform); 1916 _RasterizePath(path, gradient, gradientFunction, gradientTransform, 1917 radialGradient.Radius()); 1918 break; 1919 } 1920 case BGradient::TYPE_RADIAL_FOCUS: 1921 { 1922 GTRACE(("Painter::_FillPathGradient> type == TYPE_RADIAL_FOCUS\n")); 1923 const BGradientRadialFocus& radialGradient 1924 = (const BGradientRadialFocus&) gradient; 1925 agg::gradient_radial_focus gradientFunction; 1926 _CalcRadialGradientTransform(radialGradient.Center(), 1927 gradientTransform); 1928 _RasterizePath(path, gradient, gradientFunction, gradientTransform, 1929 radialGradient.Radius()); 1930 break; 1931 } 1932 case BGradient::TYPE_DIAMOND: 1933 { 1934 GTRACE(("Painter::_FillPathGradient> type == TYPE_DIAMOND\n")); 1935 const BGradientDiamond& diamontGradient 1936 = (const BGradientDiamond&) gradient; 1937 agg::gradient_diamond gradientFunction; 1938 _CalcRadialGradientTransform(diamontGradient.Center(), 1939 gradientTransform); 1940 _RasterizePath(path, gradient, gradientFunction, gradientTransform); 1941 break; 1942 } 1943 case BGradient::TYPE_CONIC: 1944 { 1945 GTRACE(("Painter::_FillPathGradient> type == TYPE_CONIC\n")); 1946 const BGradientConic& conicGradient 1947 = (const BGradientConic&) gradient; 1948 agg::gradient_conic gradientFunction; 1949 _CalcRadialGradientTransform(conicGradient.Center(), 1950 gradientTransform); 1951 _RasterizePath(path, gradient, gradientFunction, gradientTransform); 1952 break; 1953 } 1954 1955 default: 1956 case BGradient::TYPE_NONE: 1957 GTRACE(("Painter::_FillPathGradient> type == TYPE_NONE/unkown\n")); 1958 break; 1959 } 1960 1961 return _Clipped(_BoundingBox(path)); 1962 } 1963 1964 1965 void 1966 Painter::_CalcLinearGradientTransform(BPoint startPoint, BPoint endPoint, 1967 agg::trans_affine& matrix, float gradient_d2) const 1968 { 1969 float dx = endPoint.x - startPoint.x; 1970 float dy = endPoint.y - startPoint.y; 1971 1972 matrix.reset(); 1973 matrix *= agg::trans_affine_scaling(sqrt(dx * dx + dy * dy) / gradient_d2); 1974 matrix *= agg::trans_affine_rotation(atan2(dy, dx)); 1975 matrix *= agg::trans_affine_translation(startPoint.x, startPoint.y); 1976 matrix *= fTransform; 1977 matrix.invert(); 1978 } 1979 1980 1981 void 1982 Painter::_CalcRadialGradientTransform(BPoint center, 1983 agg::trans_affine& matrix, float gradient_d2) const 1984 { 1985 matrix.reset(); 1986 matrix *= agg::trans_affine_translation(center.x, center.y); 1987 matrix *= fTransform; 1988 matrix.invert(); 1989 } 1990 1991 1992 void 1993 Painter::_MakeGradient(const BGradient& gradient, int32 colorCount, 1994 uint32* colors, int32 arrayOffset, int32 arraySize) const 1995 { 1996 BGradient::ColorStop* from = gradient.ColorStopAt(0); 1997 1998 if (!from) 1999 return; 2000 2001 // current index into "colors" array 2002 // int32 index = (int32)floorf(colorCount * from->offset + 0.5) 2003 // + arrayOffset; 2004 int32 index = (int32)floorf(colorCount * from->offset / 255 + 0.5) 2005 + arrayOffset; 2006 if (index > arraySize) 2007 index = arraySize; 2008 // Make sure we fill the entire array in case the gradient is outside. 2009 if (index > 0) { 2010 uint8* c = (uint8*)&colors[0]; 2011 for (int32 i = 0; i < index; i++) { 2012 c[0] = from->color.blue; 2013 c[1] = from->color.green; 2014 c[2] = from->color.red; 2015 c[3] = from->color.alpha; 2016 c += 4; 2017 } 2018 } 2019 2020 // interpolate "from" to "to" 2021 int32 stopCount = gradient.CountColorStops(); 2022 for (int32 i = 1; i < stopCount; i++) { 2023 // find the step with the next offset 2024 BGradient::ColorStop* to = gradient.ColorStopAtFast(i); 2025 2026 // interpolate 2027 // int32 offset = (int32)floorf((colorCount - 1) * to->offset + 0.5); 2028 int32 offset = (int32)floorf((colorCount - 1) 2029 * to->offset / 255 + 0.5); 2030 if (offset > colorCount - 1) 2031 offset = colorCount - 1; 2032 offset += arrayOffset; 2033 int32 dist = offset - index; 2034 if (dist >= 0) { 2035 int32 startIndex = max_c(index, 0); 2036 int32 stopIndex = min_c(offset, arraySize - 1); 2037 uint8* c = (uint8*)&colors[startIndex]; 2038 for (int32 i = startIndex; i <= stopIndex; i++) { 2039 float f = (float)(offset - i) / (float)(dist + 1); 2040 float t = 1.0 - f; 2041 c[0] = (uint8)floorf(from->color.blue * f 2042 + to->color.blue * t + 0.5); 2043 c[1] = (uint8)floorf(from->color.green * f 2044 + to->color.green * t + 0.5); 2045 c[2] = (uint8)floorf(from->color.red * f 2046 + to->color.red * t + 0.5); 2047 c[3] = (uint8)floorf(from->color.alpha * f 2048 + to->color.alpha * t + 0.5); 2049 c += 4; 2050 } 2051 } 2052 index = offset + 1; 2053 // the current "to" will be the "from" in the next interpolation 2054 from = to; 2055 } 2056 // make sure we fill the entire array 2057 if (index < arraySize) { 2058 int32 startIndex = max_c(index, 0); 2059 uint8* c = (uint8*)&colors[startIndex]; 2060 for (int32 i = startIndex; i < arraySize; i++) { 2061 c[0] = from->color.blue; 2062 c[1] = from->color.green; 2063 c[2] = from->color.red; 2064 c[3] = from->color.alpha; 2065 c += 4; 2066 } 2067 } 2068 } 2069 2070 2071 template<class Array> 2072 void 2073 Painter::_MakeGradient(Array& array, const BGradient& gradient) const 2074 { 2075 for (int i = 0; i < gradient.CountColorStops() - 1; i++) { 2076 BGradient::ColorStop* from = gradient.ColorStopAtFast(i); 2077 BGradient::ColorStop* to = gradient.ColorStopAtFast(i + 1); 2078 agg::rgba8 fromColor(from->color.red, from->color.green, 2079 from->color.blue, from->color.alpha); 2080 agg::rgba8 toColor(to->color.red, to->color.green, 2081 to->color.blue, to->color.alpha); 2082 GTRACE("Painter::_MakeGradient> fromColor(%d, %d, %d, %d) offset = %f\n", 2083 fromColor.r, fromColor.g, fromColor.b, fromColor.a, 2084 from->offset); 2085 GTRACE("Painter::_MakeGradient> toColor(%d, %d, %d %d) offset = %f\n", 2086 toColor.r, toColor.g, toColor.b, toColor.a, to->offset); 2087 float dist = to->offset - from->offset; 2088 GTRACE("Painter::_MakeGradient> dist = %f\n", dist); 2089 // TODO: Review this... offset should better be on [0..1] 2090 if (dist > 0) { 2091 for (int j = (int)from->offset; j <= (int)to->offset; j++) { 2092 float f = (float)(to->offset - j) / (float)(dist + 1); 2093 array[j] = toColor.gradient(fromColor, f); 2094 GTRACE("Painter::_MakeGradient> array[%d](%d, %d, %d, %d)\n", 2095 j, array[j].r, array[j].g, array[j].b, array[j].a); 2096 } 2097 } 2098 } 2099 } 2100 2101 2102 template<class VertexSource, typename GradientFunction> 2103 void 2104 Painter::_RasterizePath(VertexSource& path, const BGradient& gradient, 2105 GradientFunction function, agg::trans_affine& gradientTransform, 2106 int gradientStop) 2107 { 2108 GTRACE("Painter::_RasterizePath\n"); 2109 2110 typedef agg::span_interpolator_linear<> interpolator_type; 2111 typedef agg::pod_auto_array<agg::rgba8, 256> color_array_type; 2112 typedef agg::span_allocator<agg::rgba8> span_allocator_type; 2113 typedef agg::span_gradient<agg::rgba8, interpolator_type, 2114 GradientFunction, color_array_type> span_gradient_type; 2115 typedef agg::renderer_scanline_aa<renderer_base, span_allocator_type, 2116 span_gradient_type> renderer_gradient_type; 2117 2118 SolidPatternGuard _(this); 2119 2120 interpolator_type spanInterpolator(gradientTransform); 2121 span_allocator_type spanAllocator; 2122 color_array_type colorArray; 2123 2124 _MakeGradient(colorArray, gradient); 2125 2126 span_gradient_type spanGradient(spanInterpolator, function, colorArray, 2127 0, gradientStop); 2128 2129 renderer_gradient_type gradientRenderer(fBaseRenderer, spanAllocator, 2130 spanGradient); 2131 2132 fRasterizer.reset(); 2133 fRasterizer.add_path(path); 2134 if (fMaskedUnpackedScanline == NULL) 2135 agg::render_scanlines(fRasterizer, fUnpackedScanline, gradientRenderer); 2136 else { 2137 agg::render_scanlines(fRasterizer, *fMaskedUnpackedScanline, 2138 gradientRenderer); 2139 } 2140 } 2141