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