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