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 67using 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 109static uint32 detect_simd(); 110 111uint32 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*/ 117static uint32 118detect_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. 181class SolidPatternGuard { 182public: 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 196private: 197 Painter* fPainter; 198 pattern fPattern; 199}; 200 201 202// #pragma mark - 203 204 205Painter::Painter() 206 : 207 fSubpixelPrecise(false), 208 fValidClipping(false), 209 fAttached(false), 210 211 fPenSize(1.0), 212 fClippingRegion(NULL), 213 fDrawingMode(B_OP_COPY), 214 fAlphaSrcMode(B_PIXEL_ALPHA), 215 fAlphaFncMode(B_ALPHA_OVERLAY), 216 fLineCapMode(B_BUTT_CAP), 217 fLineJoinMode(B_MITER_JOIN), 218 fMiterLimit(B_DEFAULT_MITER_LIMIT), 219 220 fPatternHandler(), 221 fTextRenderer(fSubpixRenderer, fRenderer, fRendererBin, fUnpackedScanline, 222 fSubpixUnpackedScanline, fSubpixRasterizer, fMaskedUnpackedScanline, 223 fTransform), 224 fInternal(fPatternHandler) 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 236Painter::~Painter() 237{ 238} 239 240 241// #pragma mark - 242 243 244// AttachToBuffer 245void 246Painter::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 272void 273Painter::DetachFromBuffer() 274{ 275 fBuffer.attach(NULL, 0, 0, 0); 276 fAttached = false; 277 fValidClipping = false; 278} 279 280 281// Bounds 282BRect 283Painter::Bounds() const 284{ 285 return BRect(0, 0, fBuffer.width() - 1, fBuffer.height() - 1); 286} 287 288 289// #pragma mark - 290 291 292// SetDrawState 293void 294Painter::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 356void 357Painter::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 371void 372Painter::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 387void 388Painter::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 399void 400Painter::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 409void 410Painter::SetDrawingMode(drawing_mode mode) 411{ 412 if (fDrawingMode != mode) { 413 fDrawingMode = mode; 414 _UpdateDrawingMode(); 415 } 416} 417 418 419// SetBlendingMode 420void 421Painter::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 433void 434Painter::SetPenSize(float size) 435{ 436 fPenSize = size; 437} 438 439 440// SetStrokeMode 441void 442Painter::SetStrokeMode(cap_mode lineCap, join_mode joinMode, float miterLimit) 443{ 444 fLineCapMode = lineCap; 445 fLineJoinMode = joinMode; 446 fMiterLimit = miterLimit; 447} 448 449 450void 451Painter::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 462void 463Painter::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 482void 483Painter::SetFont(const ServerFont& font) 484{ 485 fTextRenderer.SetFont(font); 486 fTextRenderer.SetAntialiasing(!(font.Flags() & B_DISABLE_ANTIALIASING)); 487} 488 489 490// SetFont 491void 492Painter::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 504void 505Painter::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 570bool 571Painter::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 645BRect 646Painter::StrokeTriangle(BPoint pt1, BPoint pt2, BPoint pt3) const 647{ 648 return _DrawTriangle(pt1, pt2, pt3, false); 649} 650 651 652// FillTriangle 653BRect 654Painter::FillTriangle(BPoint pt1, BPoint pt2, BPoint pt3) const 655{ 656 return _DrawTriangle(pt1, pt2, pt3, true); 657} 658 659 660// FillTriangle 661BRect 662Painter::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 684BRect 685Painter::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 717BRect 718Painter::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 745BRect 746Painter::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 770BRect 771Painter::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 791BRect 792Painter::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 809BRect 810Painter::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 824BRect 825Painter::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 875void 876Painter::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 886BRect 887Painter::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 946BRect 947Painter::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 992void 993Painter::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 1032void 1033Painter::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 1085void 1086Painter::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 1113BRect 1114Painter::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 1133BRect 1134Painter::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 1158BRect 1159Painter::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 1184void 1185Painter::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 1202BRect 1203Painter::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 1229BRect 1230Painter::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 1253BRect 1254Painter::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 1274BRect 1275Painter::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 1311BRect 1312Painter::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 1351BRect 1352Painter::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 1375BRect 1376Painter::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 1396BRect 1397Painter::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 1413BRect 1414Painter::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 1427float 1428Painter::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 1439BRect 1440Painter::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 1460BRect 1461Painter::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 1476BRect 1477Painter::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 1492BRect 1493Painter::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 1509void 1510Painter::SetRendererOffset(int32 offsetX, int32 offsetY) 1511{ 1512 fBaseRenderer.set_offset(offsetX, offsetY); 1513} 1514 1515 1516// #pragma mark - private 1517 1518 1519inline float 1520Painter::_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 1536inline void 1537Painter::_Align(BPoint* point, bool centerOffset) const 1538{ 1539 _Align(point, !fSubpixelPrecise, centerOffset); 1540} 1541 1542 1543inline void 1544Painter::_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 1551inline BPoint 1552Painter::_Align(const BPoint& point, bool centerOffset) const 1553{ 1554 BPoint ret(point); 1555 _Align(&ret, centerOffset); 1556 return ret; 1557} 1558 1559 1560// _Clipped 1561BRect 1562Painter::_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 1572void 1573Painter::_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 1592void 1593Painter::_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 1609inline BRect 1610Painter::_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 1633void 1634Painter::_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 1701void 1702Painter::_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 1719void 1720Painter::_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 1756template<class VertexSource> 1757BRect 1758Painter::_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 1772inline agg::line_cap_e 1773agg_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 1788inline agg::line_join_e 1789agg_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 1805template<class VertexSource> 1806BRect 1807Painter::_StrokePath(VertexSource& path) const 1808{ 1809 return _StrokePath(path, fLineCapMode); 1810} 1811 1812 1813template<class VertexSource> 1814BRect 1815Painter::_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 1836template<class VertexSource> 1837BRect 1838Painter::_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 1849template<class VertexSource> 1850BRect 1851Painter::_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 1875template<class VertexSource> 1876BRect 1877Painter::_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 1888template<class VertexSource> 1889BRect 1890Painter::_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 1965void 1966Painter::_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 1981void 1982Painter::_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 1992void 1993Painter::_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 2071template<class Array> 2072void 2073Painter::_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 2102template<class VertexSource, typename GradientFunction> 2103void 2104Painter::_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