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