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