1 /* 2 * Copyright 2005-2006, Haiku. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Stephan Aßmus <superstippi@gmx.de> 7 */ 8 9 10 #include "HWInterface.h" 11 12 #include "drawing_support.h" 13 14 #include "RenderingBuffer.h" 15 #include "ServerCursor.h" 16 #include "SystemPalette.h" 17 #include "UpdateQueue.h" 18 19 #include <stdio.h> 20 #include <string.h> 21 22 23 // constructor 24 HWInterface::HWInterface(bool doubleBuffered) 25 : MultiLocker("hw interface lock"), 26 fCursorAreaBackup(NULL), 27 fCursor(NULL), 28 fDragBitmap(NULL), 29 fDragBitmapOffset(0, 0), 30 fCursorAndDragBitmap(NULL), 31 fCursorVisible(false), 32 fCursorObscured(false), 33 fCursorLocation(0, 0), 34 fDoubleBuffered(doubleBuffered), 35 // fUpdateExecutor(new UpdateQueue(this)) 36 fUpdateExecutor(NULL) 37 { 38 } 39 40 // destructor 41 HWInterface::~HWInterface() 42 { 43 delete fCursorAreaBackup; 44 45 // The standard cursor doesn't belong us - the drag bitmap might 46 if (fCursor != fCursorAndDragBitmap) 47 delete fCursorAndDragBitmap; 48 49 delete fUpdateExecutor; 50 } 51 52 // Initialize 53 status_t 54 HWInterface::Initialize() 55 { 56 return MultiLocker::InitCheck(); 57 } 58 59 60 status_t 61 HWInterface::GetAccelerantPath(BString &path) 62 { 63 return B_ERROR; 64 } 65 66 67 status_t 68 HWInterface::GetDriverPath(BString &path) 69 { 70 return B_ERROR; 71 } 72 73 74 // SetCursor 75 void 76 HWInterface::SetCursor(ServerCursor* cursor) 77 { 78 if (WriteLock()) { 79 // TODO: if a bitmap is being dragged, it could 80 // be considered iritating to the user to change 81 // cursor shapes while something is dragged. 82 // The disabled code below would do this (except 83 // for the minor annoyance that the cursor is not 84 // updated when the drag is over) 85 // if (fDragBitmap) { 86 // // TODO: like a "+" or "-" sign when dragging some files to indicate 87 // // the current drag mode? 88 // WriteUnlock(); 89 // return; 90 // } 91 if (fCursor != cursor) { 92 BRect oldFrame = _CursorFrame(); 93 94 if (fCursorAndDragBitmap == fCursor) { 95 // make sure _AdoptDragBitmap doesn't delete a real cursor 96 fCursorAndDragBitmap = NULL; 97 } 98 99 if (fCursor) 100 fCursor->Release(); 101 102 fCursor = cursor; 103 104 if (fCursor) 105 fCursor->Acquire(); 106 107 Invalidate(oldFrame); 108 109 _AdoptDragBitmap(fDragBitmap, fDragBitmapOffset); 110 Invalidate(_CursorFrame()); 111 } 112 WriteUnlock(); 113 } 114 } 115 116 // SetCursorVisible 117 void 118 HWInterface::SetCursorVisible(bool visible) 119 { 120 if (WriteLock()) { 121 if (fCursorVisible != visible) { 122 // NOTE: _CursorFrame() will 123 // return an invalid rect if 124 // fCursorVisible == false! 125 if (visible) { 126 fCursorVisible = visible; 127 fCursorObscured = false; 128 BRect r = _CursorFrame(); 129 130 _DrawCursor(r); 131 Invalidate(r); 132 } else { 133 BRect r = _CursorFrame(); 134 fCursorVisible = visible; 135 136 _RestoreCursorArea(); 137 Invalidate(r); 138 } 139 } 140 WriteUnlock(); 141 } 142 } 143 144 // IsCursorVisible 145 bool 146 HWInterface::IsCursorVisible() 147 { 148 bool visible = true; 149 if (ReadLock()) { 150 visible = fCursorVisible; 151 ReadUnlock(); 152 } 153 return visible; 154 } 155 156 // ObscureCursor 157 void 158 HWInterface::ObscureCursor() 159 { 160 if (WriteLock()) { 161 if (!fCursorObscured) { 162 SetCursorVisible(false); 163 fCursorObscured = true; 164 } 165 WriteUnlock(); 166 } 167 } 168 169 // MoveCursorTo 170 void 171 HWInterface::MoveCursorTo(const float& x, const float& y) 172 { 173 if (WriteLock()) { 174 BPoint p(x, y); 175 if (p != fCursorLocation) { 176 // unhide cursor if it is obscured only 177 if (fCursorObscured) { 178 // TODO: causes nested lock, which 179 // the MultiLocker doesn't actually support? 180 SetCursorVisible(true); 181 } 182 BRect oldFrame = _CursorFrame(); 183 fCursorLocation = p; 184 if (fCursorVisible) { 185 // Invalidate and _DrawCursor would not draw 186 // anything if the cursor is hidden 187 // (invalid cursor frame), but explicitly 188 // testing for it here saves us some cycles 189 if (fCursorAreaBackup) { 190 // means we have a software cursor which we need to draw 191 _RestoreCursorArea(); 192 _DrawCursor(_CursorFrame()); 193 } 194 Invalidate(oldFrame); 195 Invalidate(_CursorFrame()); 196 } 197 } 198 WriteUnlock(); 199 } 200 } 201 202 // GetCursorPosition 203 BPoint 204 HWInterface::GetCursorPosition() 205 { 206 BPoint location; 207 if (ReadLock()) { 208 location = fCursorLocation; 209 ReadUnlock(); 210 } 211 return location; 212 } 213 214 // SetDragBitmap 215 void 216 HWInterface::SetDragBitmap(const ServerBitmap* bitmap, 217 const BPoint& offsetFromCursor) 218 { 219 if (WriteLock()) { 220 _AdoptDragBitmap(bitmap, offsetFromCursor); 221 WriteUnlock(); 222 } 223 } 224 225 // DrawingBuffer 226 RenderingBuffer* 227 HWInterface::DrawingBuffer() const 228 { 229 if (IsDoubleBuffered()) 230 return BackBuffer(); 231 return FrontBuffer(); 232 } 233 234 // IsDoubleBuffered 235 bool 236 HWInterface::IsDoubleBuffered() const 237 { 238 return fDoubleBuffered; 239 } 240 241 // Invalidate 242 // * the object needs to be already locked! 243 status_t 244 HWInterface::Invalidate(const BRect& frame) 245 { 246 if (IsDoubleBuffered()) { 247 return CopyBackToFront(frame); 248 249 // TODO: the remaining problem is the immediate wake up of the 250 // thread carrying out the updates, when I enable it, there 251 // seems to be a deadlock, but I didn't figure it out yet. 252 // Maybe the same bug is there without the wakeup, only, triggered 253 // less often.... scarry, huh? 254 /* if (frame.IsValid()) { 255 fUpdateExecutor->AddRect(frame); 256 return B_OK; 257 } 258 return B_BAD_VALUE;*/ 259 } else { 260 // _DrawCursor(frame); 261 } 262 return B_OK; 263 } 264 265 // CopyBackToFront 266 // * the object must already be locked! 267 status_t 268 HWInterface::CopyBackToFront(const BRect& frame) 269 { 270 RenderingBuffer* frontBuffer = FrontBuffer(); 271 RenderingBuffer* backBuffer = BackBuffer(); 272 273 if (!backBuffer || !frontBuffer) 274 return B_NO_INIT; 275 276 // we need to mess with the area, but it is const 277 BRect area(frame); 278 BRect bufferClip(backBuffer->Bounds()); 279 280 if (area.IsValid() && area.Intersects(bufferClip)) { 281 282 // make sure we don't copy out of bounds 283 area = bufferClip & area; 284 285 uint32 srcBPR = backBuffer->BytesPerRow(); 286 uint8* src = (uint8*)backBuffer->Bits(); 287 288 // convert to integer coordinates 289 int32 left = (int32)floorf(area.left); 290 int32 top = (int32)floorf(area.top); 291 int32 right = (int32)ceilf(area.right); 292 int32 bottom = (int32)ceilf(area.bottom); 293 294 // offset to left top pixel in source buffer (always B_RGBA32) 295 src += top * srcBPR + left * 4; 296 297 _CopyToFront(src, srcBPR, left, top, right, bottom); 298 _DrawCursor(area); 299 300 return B_OK; 301 } 302 return B_BAD_VALUE; 303 } 304 305 306 overlay_token 307 HWInterface::AcquireOverlayChannel() 308 { 309 return NULL; 310 } 311 312 313 void 314 HWInterface::ReleaseOverlayChannel(overlay_token token) 315 { 316 } 317 318 319 bool 320 HWInterface::CheckOverlayRestrictions(int32 width, int32 height, color_space colorSpace) 321 { 322 return false; 323 } 324 325 326 const overlay_buffer* 327 HWInterface::AllocateOverlayBuffer(int32 width, int32 height, color_space space) 328 { 329 return NULL; 330 } 331 332 333 void 334 HWInterface::FreeOverlayBuffer(const overlay_buffer* buffer) 335 { 336 } 337 338 339 void 340 HWInterface::ConfigureOverlay(Overlay* overlay) 341 { 342 } 343 344 345 void 346 HWInterface::HideOverlay(Overlay* overlay) 347 { 348 } 349 350 351 // HideSoftwareCursor 352 bool 353 HWInterface::HideSoftwareCursor(const BRect& area) 354 { 355 if (fCursorAreaBackup && !fCursorAreaBackup->cursor_hidden) { 356 BRect backupArea(fCursorAreaBackup->left, 357 fCursorAreaBackup->top, 358 fCursorAreaBackup->right, 359 fCursorAreaBackup->bottom); 360 if (area.Intersects(backupArea)) { 361 _RestoreCursorArea(); 362 return true; 363 } 364 } 365 return false; 366 } 367 368 // HideSoftwareCursor 369 void 370 HWInterface::HideSoftwareCursor() 371 { 372 _RestoreCursorArea(); 373 } 374 375 // ShowSoftwareCursor 376 void 377 HWInterface::ShowSoftwareCursor() 378 { 379 if (fCursorAreaBackup && fCursorAreaBackup->cursor_hidden) { 380 _DrawCursor(_CursorFrame()); 381 } 382 } 383 384 385 // _DrawCursor 386 // * default implementation, can be used as fallback or for 387 // software cursor 388 // * area is where we potentially draw the cursor, the cursor 389 // might be somewhere else, in which case this function does nothing 390 void 391 HWInterface::_DrawCursor(BRect area) const 392 { 393 RenderingBuffer* backBuffer = DrawingBuffer(); 394 if (!backBuffer || !area.IsValid()) 395 return; 396 397 BRect cf = _CursorFrame(); 398 399 // make sure we don't copy out of bounds 400 area = backBuffer->Bounds() & area; 401 402 if (cf.IsValid() && area.Intersects(cf)) { 403 // clip to common area 404 area = area & cf; 405 406 int32 left = (int32)area.left; 407 int32 top = (int32)area.top; 408 int32 right = (int32)area.right; 409 int32 bottom = (int32)area.bottom; 410 int32 width = right - left + 1; 411 int32 height = bottom - top + 1; 412 413 // make a bitmap from the backbuffer 414 // that has the cursor blended on top of it 415 416 // blending buffer 417 uint8* buffer = new uint8[width * height * 4]; 418 419 // offset into back buffer 420 uint8* src = (uint8*)backBuffer->Bits(); 421 uint32 srcBPR = backBuffer->BytesPerRow(); 422 src += top * srcBPR + left * 4; 423 424 // offset into cursor bitmap 425 uint8* crs = (uint8*)fCursorAndDragBitmap->Bits(); 426 uint32 crsBPR = fCursorAndDragBitmap->BytesPerRow(); 427 // since area is clipped to cf, 428 // the diff between top and cf.top is always positive, 429 // same for diff between left and cf.left 430 crs += (top - (int32)floorf(cf.top)) * crsBPR 431 + (left - (int32)floorf(cf.left)) * 4; 432 433 uint8* dst = buffer; 434 435 if (fCursorAreaBackup && fCursorAreaBackup->buffer) { 436 fCursorAreaBackup->cursor_hidden = false; 437 // remember which area the backup contains 438 fCursorAreaBackup->left = left; 439 fCursorAreaBackup->top = top; 440 fCursorAreaBackup->right = right; 441 fCursorAreaBackup->bottom = bottom; 442 uint8* bup = fCursorAreaBackup->buffer; 443 uint32 bupBPR = fCursorAreaBackup->bpr; 444 445 // blending and backup of drawing buffer 446 for (int32 y = top; y <= bottom; y++) { 447 uint8* s = src; 448 uint8* c = crs; 449 uint8* d = dst; 450 uint8* b = bup; 451 452 for (int32 x = left; x <= right; x++) { 453 *(uint32*)b = *(uint32*)s; 454 // assumes backbuffer alpha = 255 455 // assuming pre-multiplied cursor bitmap 456 int a = 255 - c[3]; 457 d[0] = ((int)(b[0] * a + 255) >> 8) + c[0]; 458 d[1] = ((int)(b[1] * a + 255) >> 8) + c[1]; 459 d[2] = ((int)(b[2] * a + 255) >> 8) + c[2]; 460 461 s += 4; 462 c += 4; 463 d += 4; 464 b += 4; 465 } 466 crs += crsBPR; 467 src += srcBPR; 468 dst += width * 4; 469 bup += bupBPR; 470 } 471 } else { 472 // blending 473 for (int32 y = top; y <= bottom; y++) { 474 uint8* s = src; 475 uint8* c = crs; 476 uint8* d = dst; 477 for (int32 x = left; x <= right; x++) { 478 // assumes backbuffer alpha = 255 479 // assuming pre-multiplied cursor bitmap 480 uint8 a = 255 - c[3]; 481 d[0] = ((s[0] * a + 255) >> 8) + c[0]; 482 d[1] = ((s[1] * a + 255) >> 8) + c[1]; 483 d[2] = ((s[2] * a + 255) >> 8) + c[2]; 484 485 s += 4; 486 c += 4; 487 d += 4; 488 } 489 crs += crsBPR; 490 src += srcBPR; 491 dst += width * 4; 492 } 493 } 494 // copy result to front buffer 495 _CopyToFront(buffer, width * 4, left, top, right, bottom); 496 497 delete[] buffer; 498 } 499 } 500 501 // _CopyToFront 502 // 503 // * source is assumed to be already at the right offset 504 // * source is assumed to be in B_RGBA32 format 505 // * location in front buffer is calculated 506 // * conversion from B_RGBA32 to format of front buffer is taken care of 507 void 508 HWInterface::_CopyToFront(uint8* src, uint32 srcBPR, 509 int32 x, int32 y, 510 int32 right, int32 bottom) const 511 { 512 RenderingBuffer* frontBuffer = FrontBuffer(); 513 514 uint8* dst = (uint8*)frontBuffer->Bits(); 515 uint32 dstBPR = frontBuffer->BytesPerRow(); 516 517 // transfer, handle colorspace conversion 518 switch (frontBuffer->ColorSpace()) { 519 case B_RGB32: 520 case B_RGBA32: { 521 int32 bytes = (right - x + 1) * 4; 522 523 if (bytes > 0) { 524 // offset to left top pixel in dest buffer 525 dst += y * dstBPR + x * 4; 526 // copy 527 for (; y <= bottom; y++) { 528 // bytes is guaranteed to be multiple of 4 529 gfxcpy32(dst, src, bytes); 530 dst += dstBPR; 531 src += srcBPR; 532 } 533 } else 534 printf("nothing to copy\n"); 535 break; 536 } 537 // NOTE: on R5, B_RGB24 bitmaps are not supported by DrawBitmap() 538 case B_RGB24: { 539 // offset to left top pixel in dest buffer 540 dst += y * dstBPR + x * 3; 541 int32 left = x; 542 // copy 543 for (; y <= bottom; y++) { 544 uint8* srcHandle = src; 545 uint8* dstHandle = dst; 546 for (x = left; x <= right; x++) { 547 dstHandle[0] = srcHandle[0]; 548 dstHandle[1] = srcHandle[1]; 549 dstHandle[2] = srcHandle[2]; 550 dstHandle += 3; 551 srcHandle += 4; 552 } 553 dst += dstBPR; 554 src += srcBPR; 555 } 556 break; 557 } 558 case B_RGB16: { 559 // offset to left top pixel in dest buffer 560 dst += y * dstBPR + x * 2; 561 int32 left = x; 562 // copy 563 // TODO: assumes BGR order, does this work on big endian as well? 564 for (; y <= bottom; y++) { 565 uint8* srcHandle = src; 566 uint16* dstHandle = (uint16*)dst; 567 for (x = left; x <= right; x++) { 568 *dstHandle = (uint16)(((srcHandle[2] & 0xf8) << 8) | 569 ((srcHandle[1] & 0xfc) << 3) | 570 (srcHandle[0] >> 3)); 571 dstHandle ++; 572 srcHandle += 4; 573 } 574 dst += dstBPR; 575 src += srcBPR; 576 } 577 break; 578 } 579 case B_RGB15: { 580 // offset to left top pixel in dest buffer 581 dst += y * dstBPR + x * 2; 582 int32 left = x; 583 // copy 584 // TODO: assumes BGR order, does this work on big endian as well? 585 for (; y <= bottom; y++) { 586 uint8* srcHandle = src; 587 uint16* dstHandle = (uint16*)dst; 588 for (x = left; x <= right; x++) { 589 *dstHandle = (uint16)(((srcHandle[2] & 0xf8) << 7) | 590 ((srcHandle[1] & 0xf8) << 2) | 591 (srcHandle[0] >> 3)); 592 dstHandle ++; 593 srcHandle += 4; 594 } 595 dst += dstBPR; 596 src += srcBPR; 597 } 598 break; 599 } 600 case B_CMAP8: { 601 const color_map *colorMap = SystemColorMap(); 602 // offset to left top pixel in dest buffer 603 dst += y * dstBPR + x; 604 int32 left = x; 605 uint16 index; 606 // copy 607 // TODO: assumes BGR order again 608 for (; y <= bottom; y++) { 609 uint8* srcHandle = src; 610 uint8* dstHandle = dst; 611 for (x = left; x <= right; x++) { 612 index = ((srcHandle[2] & 0xf8) << 7) | ((srcHandle[1] & 0xf8) << 2) | (srcHandle[0] >> 3); 613 *dstHandle = colorMap->index_map[index]; 614 dstHandle ++; 615 srcHandle += 4; 616 } 617 dst += dstBPR; 618 src += srcBPR; 619 } 620 621 break; 622 } 623 case B_GRAY8: { 624 // offset to left top pixel in dest buffer 625 dst += y * dstBPR + x; 626 int32 left = x; 627 // copy 628 // TODO: assumes BGR order, does this work on big endian as well? 629 for (; y <= bottom; y++) { 630 uint8* srcHandle = src; 631 uint8* dstHandle = dst; 632 for (x = left; x <= right; x++) { 633 *dstHandle = (308 * srcHandle[2] + 600 * srcHandle[1] + 116 * srcHandle[0]) / 1024; 634 dstHandle ++; 635 srcHandle += 4; 636 } 637 dst += dstBPR; 638 src += srcBPR; 639 } 640 break; 641 } 642 default: 643 fprintf(stderr, "HWInterface::CopyBackToFront() - unsupported front buffer format!\n"); 644 break; 645 } 646 } 647 648 649 // _CursorFrame 650 // 651 // PRE: the object must be locked 652 BRect 653 HWInterface::_CursorFrame() const 654 { 655 BRect frame(0.0, 0.0, -1.0, -1.0); 656 if (fCursorAndDragBitmap && fCursorVisible) { 657 frame = fCursorAndDragBitmap->Bounds(); 658 frame.OffsetTo(fCursorLocation - fCursorAndDragBitmap->GetHotSpot()); 659 } 660 return frame; 661 } 662 663 // _RestoreCursorArea 664 void 665 HWInterface::_RestoreCursorArea() const 666 { 667 if (fCursorAreaBackup && !fCursorAreaBackup->cursor_hidden) { 668 _CopyToFront(fCursorAreaBackup->buffer, 669 fCursorAreaBackup->bpr, 670 fCursorAreaBackup->left, 671 fCursorAreaBackup->top, 672 fCursorAreaBackup->right, 673 fCursorAreaBackup->bottom); 674 675 fCursorAreaBackup->cursor_hidden = true; 676 } 677 } 678 679 // _AdoptDragBitmap 680 void 681 HWInterface::_AdoptDragBitmap(const ServerBitmap* bitmap, const BPoint& offset) 682 { 683 // TODO: support other colorspaces/convert bitmap 684 if (bitmap && !(bitmap->ColorSpace() == B_RGB32 685 || bitmap->ColorSpace() == B_RGBA32)) { 686 fprintf(stderr, "HWInterface::_AdoptDragBitmap() - bitmap has yet unsupported colorspace\n"); 687 return; 688 } 689 690 _RestoreCursorArea(); 691 BRect cursorFrame = _CursorFrame(); 692 693 if (fCursorAndDragBitmap && fCursorAndDragBitmap != fCursor) { 694 delete fCursorAndDragBitmap; 695 fCursorAndDragBitmap = NULL; 696 } 697 698 if (bitmap) { 699 BRect bitmapFrame = bitmap->Bounds(); 700 if (fCursor) { 701 // put bitmap frame and cursor frame into the same 702 // coordinate space (the cursor location is the origin) 703 bitmapFrame.OffsetTo(BPoint(-offset.x, -offset.y)); 704 705 BRect cursorFrame(fCursor->Bounds()); 706 BPoint hotspot(fCursor->GetHotSpot()); 707 // the hotspot is at the origin 708 cursorFrame.OffsetTo(-hotspot.x, -hotspot.y); 709 710 BRect combindedBounds = bitmapFrame | cursorFrame; 711 712 BPoint shift; 713 shift.x = -combindedBounds.left; 714 shift.y = -combindedBounds.top; 715 716 combindedBounds.OffsetBy(shift); 717 cursorFrame.OffsetBy(shift); 718 bitmapFrame.OffsetBy(shift); 719 720 fCursorAndDragBitmap = new ServerCursor(combindedBounds, 721 bitmap->ColorSpace(), 0, 722 hotspot + shift); 723 724 // clear the combined buffer 725 uint8* dst = (uint8*)fCursorAndDragBitmap->Bits(); 726 uint32 dstBPR = fCursorAndDragBitmap->BytesPerRow(); 727 728 memset(dst, 0, fCursorAndDragBitmap->BitsLength()); 729 730 // put drag bitmap into combined buffer 731 uint8* src = (uint8*)bitmap->Bits(); 732 uint32 srcBPR = bitmap->BytesPerRow(); 733 734 dst += (int32)bitmapFrame.top * dstBPR + (int32)bitmapFrame.left * 4; 735 736 uint32 width = bitmapFrame.IntegerWidth() + 1; 737 uint32 height = bitmapFrame.IntegerHeight() + 1; 738 739 for (uint32 y = 0; y < height; y++) { 740 memcpy(dst, src, srcBPR); 741 dst += dstBPR; 742 src += srcBPR; 743 } 744 745 // compose cursor into combined buffer 746 dst = (uint8*)fCursorAndDragBitmap->Bits(); 747 dst += (int32)cursorFrame.top * dstBPR + (int32)cursorFrame.left * 4; 748 749 src = (uint8*)fCursor->Bits(); 750 srcBPR = fCursor->BytesPerRow(); 751 752 width = cursorFrame.IntegerWidth() + 1; 753 height = cursorFrame.IntegerHeight() + 1; 754 755 for (uint32 y = 0; y < height; y++) { 756 uint8* d = dst; 757 uint8* s = src; 758 for (uint32 x = 0; x < width; x++) { 759 // takes two semi-transparent pixels 760 // with unassociated alpha (not pre-multiplied) 761 // and stays within non-premultiplied color space 762 if (s[3] > 0) { 763 if (s[3] == 255) { 764 d[0] = s[0]; 765 d[1] = s[1]; 766 d[2] = s[2]; 767 d[3] = 255; 768 } else { 769 uint8 alphaRest = 255 - s[3]; 770 uint32 alphaTemp = (65025 - alphaRest * (255 - d[3])); 771 uint32 alphaDest = d[3] * alphaRest; 772 uint32 alphaSrc = 255 * s[3]; 773 d[0] = (d[0] * alphaDest + s[0] * alphaSrc) / alphaTemp; 774 d[1] = (d[1] * alphaDest + s[1] * alphaSrc) / alphaTemp; 775 d[2] = (d[2] * alphaDest + s[2] * alphaSrc) / alphaTemp; 776 d[3] = alphaTemp / 255; 777 } 778 } 779 // TODO: make sure the alpha is always upside down, 780 // then it doesn't need to be done when drawing the cursor 781 // (see _DrawCursor()) 782 // d[3] = 255 - d[3]; 783 d += 4; 784 s += 4; 785 } 786 dst += dstBPR; 787 src += srcBPR; 788 } 789 790 // handle pre-multiplication with alpha 791 // for faster compositing during cursor drawing 792 width = combindedBounds.IntegerWidth() + 1; 793 height = combindedBounds.IntegerHeight() + 1; 794 795 dst = (uint8*)fCursorAndDragBitmap->Bits(); 796 797 for (uint32 y = 0; y < height; y++) { 798 uint8* d = dst; 799 for (uint32 x = 0; x < width; x++) { 800 d[0] = (d[0] * d[3]) >> 8; 801 d[1] = (d[1] * d[3]) >> 8; 802 d[2] = (d[2] * d[3]) >> 8; 803 d += 4; 804 } 805 dst += dstBPR; 806 } 807 } else { 808 fCursorAndDragBitmap = new ServerCursor(bitmap->Bits(), 809 bitmapFrame.IntegerWidth() + 1, 810 bitmapFrame.IntegerHeight() + 1, 811 bitmap->ColorSpace()); 812 fCursorAndDragBitmap->SetHotSpot(BPoint(-offset.x, -offset.y)); 813 } 814 } else { 815 fCursorAndDragBitmap = fCursor; 816 } 817 818 Invalidate(cursorFrame); 819 820 // NOTE: the EventDispatcher does the reference counting stuff for us 821 // TODO: You can not simply call Release() on a ServerBitmap like you 822 // can for a ServerCursor... it could be changed, but there are linking 823 // troubles with the test environment that need to be solved than. 824 // if (fDragBitmap) 825 // fDragBitmap->Release(); 826 fDragBitmap = bitmap; 827 fDragBitmapOffset = offset; 828 // if (fDragBitmap) 829 // fDragBitmap->Acquire(); 830 831 delete fCursorAreaBackup; 832 fCursorAreaBackup = NULL; 833 834 if (!fCursorAndDragBitmap) 835 return; 836 837 if (fCursorAndDragBitmap && !IsDoubleBuffered()) { 838 BRect cursorBounds = fCursorAndDragBitmap->Bounds(); 839 fCursorAreaBackup = new buffer_clip(cursorBounds.IntegerWidth() + 1, 840 cursorBounds.IntegerHeight() + 1); 841 } 842 _DrawCursor(_CursorFrame()); 843 } 844 845 846 847 848