1 /* 2 * Copyright 2001-2009, Haiku Inc. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Ingo Weinhold (bonefish@users.sf.net) 7 * DarkWyrm <bpmagic@columbus.rr.com> 8 * Stephan Aßmus <superstippi@gmx.de> 9 * Axel Dörfler, axeld@pinc-software.de 10 */ 11 12 13 /*! BBitmap objects represent off-screen windows that 14 contain bitmap data. 15 */ 16 17 18 #include <Bitmap.h> 19 20 #include <algorithm> 21 #include <limits.h> 22 #include <new> 23 #include <stdio.h> 24 #include <stdlib.h> 25 #include <string.h> 26 27 #include <Application.h> 28 #include <GraphicsDefs.h> 29 #include <Locker.h> 30 #include <View.h> 31 #include <Window.h> 32 33 #include <ApplicationPrivate.h> 34 #include <AppServerLink.h> 35 #include <Autolock.h> 36 #include <ObjectList.h> 37 #include <ServerMemoryAllocator.h> 38 #include <ServerProtocol.h> 39 40 #include "ColorConversion.h" 41 #include "BitmapPrivate.h" 42 43 44 using namespace BPrivate; 45 46 47 static BObjectList<BBitmap> sBitmapList; 48 static BLocker sBitmapListLock; 49 50 51 void 52 reconnect_bitmaps_to_app_server() 53 { 54 BAutolock _(sBitmapListLock); 55 for (int32 i = 0; i < sBitmapList.CountItems(); i++) { 56 BBitmap::Private bitmap(sBitmapList.ItemAt(i)); 57 bitmap.ReconnectToAppServer(); 58 } 59 } 60 61 62 BBitmap::Private::Private(BBitmap* bitmap) 63 : 64 fBitmap(bitmap) 65 { 66 } 67 68 69 void 70 BBitmap::Private::ReconnectToAppServer() 71 { 72 fBitmap->_ReconnectToAppServer(); 73 } 74 75 76 /*! \brief Returns the number of bytes per row needed to store the actual 77 bitmap data (not including any padding) given a color space and a 78 row width. 79 \param colorSpace The color space. 80 \param width The width. 81 \return The number of bytes per row needed to store data for a row, or 82 0, if the color space is not supported. 83 */ 84 static inline int32 85 get_raw_bytes_per_row(color_space colorSpace, int32 width) 86 { 87 int32 bpr = 0; 88 switch (colorSpace) { 89 // supported 90 case B_RGBA64: case B_RGBA64_BIG: 91 bpr = 8 * width; 92 break; 93 case B_RGB48: case B_RGB48_BIG: 94 bpr = 6 * width; 95 break; 96 case B_RGB32: case B_RGBA32: 97 case B_RGB32_BIG: case B_RGBA32_BIG: 98 case B_UVL32: case B_UVLA32: 99 case B_LAB32: case B_LABA32: 100 case B_HSI32: case B_HSIA32: 101 case B_HSV32: case B_HSVA32: 102 case B_HLS32: case B_HLSA32: 103 case B_CMY32: case B_CMYA32: case B_CMYK32: 104 bpr = 4 * width; 105 break; 106 case B_RGB24: case B_RGB24_BIG: 107 case B_UVL24: case B_LAB24: case B_HSI24: 108 case B_HSV24: case B_HLS24: case B_CMY24: 109 bpr = 3 * width; 110 break; 111 case B_RGB16: case B_RGB15: case B_RGBA15: 112 case B_RGB16_BIG: case B_RGB15_BIG: case B_RGBA15_BIG: 113 bpr = 2 * width; 114 break; 115 case B_CMAP8: case B_GRAY8: 116 bpr = width; 117 break; 118 case B_GRAY1: 119 bpr = (width + 7) / 8; 120 break; 121 case B_YCbCr422: case B_YUV422: 122 bpr = (width + 3) / 4 * 8; 123 break; 124 case B_YCbCr411: case B_YUV411: 125 bpr = (width + 3) / 4 * 6; 126 break; 127 case B_YCbCr444: case B_YUV444: 128 bpr = (width + 3) / 4 * 12; 129 break; 130 case B_YCbCr420: case B_YUV420: 131 bpr = (width + 3) / 4 * 6; 132 break; 133 case B_YUV9: 134 bpr = (width + 15) / 16 * 18; 135 break; 136 // unsupported 137 case B_NO_COLOR_SPACE: 138 case B_YUV12: 139 break; 140 } 141 return bpr; 142 } 143 144 145 namespace BPrivate { 146 147 /*! \brief Returns the number of bytes per row needed to store the bitmap 148 data (including any padding) given a color space and a row width. 149 \param colorSpace The color space. 150 \param width The width. 151 \return The number of bytes per row needed to store data for a row, or 152 0, if the color space is not supported. 153 */ 154 int32 155 get_bytes_per_row(color_space colorSpace, int32 width) 156 { 157 int32 bpr = get_raw_bytes_per_row(colorSpace, width); 158 // align to int32 159 bpr = (bpr + 3) & 0x7ffffffc; 160 return bpr; 161 } 162 163 } // namespace BPrivate 164 165 166 // #pragma mark - 167 168 169 /*! \brief Creates and initializes a BBitmap. 170 \param bounds The bitmap dimensions. 171 \param flags Creation flags. 172 \param colorSpace The bitmap's color space. 173 \param bytesPerRow The number of bytes per row the bitmap should use. 174 \c B_ANY_BYTES_PER_ROW to let the constructor choose an appropriate 175 value. 176 \param screenID ??? 177 */ 178 BBitmap::BBitmap(BRect bounds, uint32 flags, color_space colorSpace, 179 int32 bytesPerRow, screen_id screenID) 180 : 181 fBasePointer(NULL), 182 fSize(0), 183 fColorSpace(B_NO_COLOR_SPACE), 184 fBounds(0, 0, -1, -1), 185 fBytesPerRow(0), 186 fWindow(NULL), 187 fServerToken(-1), 188 fAreaOffset(-1), 189 fArea(-1), 190 fServerArea(-1), 191 fFlags(0), 192 fInitError(B_NO_INIT) 193 { 194 _InitObject(bounds, colorSpace, flags, bytesPerRow, screenID); 195 } 196 197 198 /*! \brief Creates and initializes a BBitmap. 199 \param bounds The bitmap dimensions. 200 \param colorSpace The bitmap's color space. 201 \param acceptsViews \c true, if the bitmap shall accept BViews, i.e. if 202 it shall be possible to attach BView to the bitmap and draw into 203 it. 204 \param needsContiguous If \c true a physically contiguous chunk of memory 205 will be allocated. 206 */ 207 BBitmap::BBitmap(BRect bounds, color_space colorSpace, bool acceptsViews, 208 bool needsContiguous) 209 : 210 fBasePointer(NULL), 211 fSize(0), 212 fColorSpace(B_NO_COLOR_SPACE), 213 fBounds(0, 0, -1, -1), 214 fBytesPerRow(0), 215 fWindow(NULL), 216 fServerToken(-1), 217 fAreaOffset(-1), 218 fArea(-1), 219 fServerArea(-1), 220 fFlags(0), 221 fInitError(B_NO_INIT) 222 { 223 int32 flags = (acceptsViews ? B_BITMAP_ACCEPTS_VIEWS : 0) 224 | (needsContiguous ? B_BITMAP_IS_CONTIGUOUS : 0); 225 _InitObject(bounds, colorSpace, flags, B_ANY_BYTES_PER_ROW, 226 B_MAIN_SCREEN_ID); 227 } 228 229 230 /*! \brief Creates a BBitmap as a clone of another bitmap. 231 \param source The source bitmap. 232 \param acceptsViews \c true, if the bitmap shall accept BViews, i.e. if 233 it shall be possible to attach BView to the bitmap and draw into 234 it. 235 \param needsContiguous If \c true a physically contiguous chunk of memory 236 will be allocated. 237 */ 238 BBitmap::BBitmap(const BBitmap* source, bool acceptsViews, bool needsContiguous) 239 : 240 fBasePointer(NULL), 241 fSize(0), 242 fColorSpace(B_NO_COLOR_SPACE), 243 fBounds(0, 0, -1, -1), 244 fBytesPerRow(0), 245 fWindow(NULL), 246 fServerToken(-1), 247 fAreaOffset(-1), 248 fArea(-1), 249 fServerArea(-1), 250 fFlags(0), 251 fInitError(B_NO_INIT) 252 { 253 if (source && source->IsValid()) { 254 int32 flags = (acceptsViews ? B_BITMAP_ACCEPTS_VIEWS : 0) 255 | (needsContiguous ? B_BITMAP_IS_CONTIGUOUS : 0); 256 _InitObject(source->Bounds(), source->ColorSpace(), flags, 257 source->BytesPerRow(), B_MAIN_SCREEN_ID); 258 if (InitCheck() == B_OK) { 259 memcpy(Bits(), source->Bits(), min_c(BitsLength(), 260 source->BitsLength())); 261 } 262 } 263 } 264 265 266 BBitmap::BBitmap(const BBitmap& source, uint32 flags) 267 : 268 fBasePointer(NULL), 269 fSize(0), 270 fColorSpace(B_NO_COLOR_SPACE), 271 fBounds(0, 0, -1, -1), 272 fBytesPerRow(0), 273 fWindow(NULL), 274 fServerToken(-1), 275 fAreaOffset(-1), 276 fArea(-1), 277 fServerArea(-1), 278 fFlags(0), 279 fInitError(B_NO_INIT) 280 { 281 if (!source.IsValid()) 282 return; 283 284 _InitObject(source.Bounds(), source.ColorSpace(), flags, 285 source.BytesPerRow(), B_MAIN_SCREEN_ID); 286 287 if (InitCheck() == B_OK) 288 memcpy(Bits(), source.Bits(), min_c(BitsLength(), source.BitsLength())); 289 } 290 291 292 BBitmap::BBitmap(const BBitmap& source) 293 : 294 fBasePointer(NULL), 295 fSize(0), 296 fColorSpace(B_NO_COLOR_SPACE), 297 fBounds(0, 0, -1, -1), 298 fBytesPerRow(0), 299 fWindow(NULL), 300 fServerToken(-1), 301 fAreaOffset(-1), 302 fArea(-1), 303 fServerArea(-1), 304 fFlags(0), 305 fInitError(B_NO_INIT) 306 { 307 *this = source; 308 } 309 310 311 BBitmap::BBitmap(area_id area, ptrdiff_t areaOffset, BRect bounds, 312 uint32 flags, color_space colorSpace, int32 bytesPerRow, 313 screen_id screenID) 314 : 315 fBasePointer(NULL), 316 fSize(0), 317 fColorSpace(B_NO_COLOR_SPACE), 318 fBounds(0, 0, -1, -1), 319 fBytesPerRow(0), 320 fWindow(NULL), 321 fServerToken(-1), 322 fAreaOffset(-1), 323 fArea(-1), 324 fServerArea(-1), 325 fFlags(0), 326 fInitError(B_NO_INIT) 327 { 328 _InitObject(bounds, colorSpace, flags, 329 bytesPerRow, screenID, area, areaOffset); 330 } 331 332 333 /*! \brief Frees all resources associated with this object. 334 */ 335 BBitmap::~BBitmap() 336 { 337 _CleanUp(); 338 } 339 340 341 /*! \brief Unarchives a bitmap from a BMessage. 342 \param data The archive. 343 */ 344 BBitmap::BBitmap(BMessage* data) 345 : 346 BArchivable(data), 347 fBasePointer(NULL), 348 fSize(0), 349 fColorSpace(B_NO_COLOR_SPACE), 350 fBounds(0, 0, -1, -1), 351 fBytesPerRow(0), 352 fWindow(NULL), 353 fServerToken(-1), 354 fAreaOffset(-1), 355 fArea(-1), 356 fServerArea(-1), 357 fFlags(0), 358 fInitError(B_NO_INIT) 359 { 360 int32 flags; 361 if (data->FindInt32("_bmflags", &flags) != B_OK) { 362 // this bitmap is archived in some archaic format 363 flags = 0; 364 365 bool acceptsViews; 366 if (data->FindBool("_view_ok", &acceptsViews) == B_OK && acceptsViews) 367 flags |= B_BITMAP_ACCEPTS_VIEWS; 368 369 bool contiguous; 370 if (data->FindBool("_contiguous", &contiguous) == B_OK && contiguous) 371 flags |= B_BITMAP_IS_CONTIGUOUS; 372 } 373 374 int32 rowBytes; 375 if (data->FindInt32("_rowbytes", &rowBytes) != B_OK) { 376 rowBytes = -1; 377 // bytes per row are computed in InitObject(), then 378 } 379 380 BRect bounds; 381 color_space cspace; 382 if (data->FindRect("_frame", &bounds) == B_OK 383 && data->FindInt32("_cspace", (int32*)&cspace) == B_OK) { 384 _InitObject(bounds, cspace, flags, rowBytes, B_MAIN_SCREEN_ID); 385 } 386 387 if (InitCheck() == B_OK) { 388 ssize_t size; 389 const void* buffer; 390 if (data->FindData("_data", B_RAW_TYPE, &buffer, &size) == B_OK) { 391 if (size == BitsLength()) { 392 _AssertPointer(); 393 memcpy(fBasePointer, buffer, size); 394 } 395 } 396 } 397 398 if ((fFlags & B_BITMAP_ACCEPTS_VIEWS) != 0) { 399 BMessage message; 400 int32 i = 0; 401 402 while (data->FindMessage("_views", i++, &message) == B_OK) { 403 if (BView* view 404 = dynamic_cast<BView*>(instantiate_object(&message))) 405 AddChild(view); 406 } 407 } 408 } 409 410 411 /*! \brief Instantiates a BBitmap from an archive. 412 \param data The archive. 413 \return A bitmap reconstructed from the archive or \c NULL, if an error 414 occured. 415 */ 416 BArchivable* 417 BBitmap::Instantiate(BMessage* data) 418 { 419 if (validate_instantiation(data, "BBitmap")) 420 return new BBitmap(data); 421 422 return NULL; 423 } 424 425 426 /*! \brief Archives the BBitmap object. 427 \param data The archive. 428 \param deep \c true, if child object shall be archived as well, \c false 429 otherwise. 430 \return \c B_OK, if everything went fine, an error code otherwise. 431 */ 432 status_t 433 BBitmap::Archive(BMessage* data, bool deep) const 434 { 435 status_t ret = BArchivable::Archive(data, deep); 436 437 if (ret == B_OK) 438 ret = data->AddRect("_frame", fBounds); 439 440 if (ret == B_OK) 441 ret = data->AddInt32("_cspace", (int32)fColorSpace); 442 443 if (ret == B_OK) 444 ret = data->AddInt32("_bmflags", fFlags); 445 446 if (ret == B_OK) 447 ret = data->AddInt32("_rowbytes", fBytesPerRow); 448 449 if (ret == B_OK && deep) { 450 if ((fFlags & B_BITMAP_ACCEPTS_VIEWS) != 0) { 451 BMessage views; 452 for (int32 i = 0; i < CountChildren(); i++) { 453 if (ChildAt(i)->Archive(&views, deep)) 454 ret = data->AddMessage("_views", &views); 455 views.MakeEmpty(); 456 if (ret < B_OK) 457 break; 458 } 459 } 460 } 461 // Note: R5 does not archive the data if B_BITMAP_IS_CONTIGUOUS is 462 // true and it does save all formats as B_RAW_TYPE and it does save 463 // the data even if B_BITMAP_ACCEPTS_VIEWS is set (as opposed to 464 // the BeBook) 465 if (ret == B_OK) { 466 const_cast<BBitmap*>(this)->_AssertPointer(); 467 ret = data->AddData("_data", B_RAW_TYPE, fBasePointer, fSize); 468 } 469 return ret; 470 } 471 472 473 /*! \brief Returns the result from the construction. 474 \return \c B_OK, if the object is properly initialized, an error code 475 otherwise. 476 */ 477 status_t 478 BBitmap::InitCheck() const 479 { 480 return fInitError; 481 } 482 483 484 /*! \brief Returns whether or not the BBitmap object is valid. 485 \return \c true, if the object is properly initialized, \c false otherwise. 486 */ 487 bool 488 BBitmap::IsValid() const 489 { 490 return InitCheck() == B_OK; 491 } 492 493 494 /*! \brief Locks the bitmap bits so that they cannot be relocated. 495 496 This is currently only used for overlay bitmaps - whenever you 497 need to access their Bits(), you have to lock them first. 498 On resolution change overlay bitmaps can be relocated in memory; 499 using this call prevents you from accessing an invalid pointer 500 and clobbering memory that doesn't belong you. 501 */ 502 status_t 503 BBitmap::LockBits(uint32* state) 504 { 505 // TODO: how do we fill the "state"? 506 // It would be more or less useful to report what kind of bitmap 507 // we got (ie. overlay, placeholder, or non-overlay) 508 if ((fFlags & B_BITMAP_WILL_OVERLAY) != 0) { 509 overlay_client_data* data = (overlay_client_data*)fBasePointer; 510 511 status_t status; 512 do { 513 status = acquire_sem(data->lock); 514 } while (status == B_INTERRUPTED); 515 516 if (data->buffer == NULL) { 517 // the app_server does not grant us access to the frame buffer 518 // right now - let's release the lock and fail 519 release_sem_etc(data->lock, 1, B_DO_NOT_RESCHEDULE); 520 return B_BUSY; 521 } 522 return status; 523 } 524 525 // NOTE: maybe this is used to prevent the app_server from 526 // drawing the bitmap yet? 527 // axeld: you mean for non overlays? 528 529 return B_OK; 530 } 531 532 533 /*! \brief Unlocks the bitmap's buffer again. 534 Counterpart to LockBits(), see there for comments. 535 */ 536 void 537 BBitmap::UnlockBits() 538 { 539 if ((fFlags & B_BITMAP_WILL_OVERLAY) == 0) 540 return; 541 542 overlay_client_data* data = (overlay_client_data*)fBasePointer; 543 release_sem_etc(data->lock, 1, B_DO_NOT_RESCHEDULE); 544 } 545 546 547 /*! \brief Returns the ID of the area the bitmap data reside in. 548 \return The ID of the area the bitmap data reside in. 549 */ 550 area_id 551 BBitmap::Area() const 552 { 553 const_cast<BBitmap*>(this)->_AssertPointer(); 554 return fArea; 555 } 556 557 558 /*! \brief Returns the pointer to the bitmap data. 559 \return The pointer to the bitmap data. 560 */ 561 void* 562 BBitmap::Bits() const 563 { 564 const_cast<BBitmap*>(this)->_AssertPointer(); 565 566 if ((fFlags & B_BITMAP_WILL_OVERLAY) != 0) { 567 overlay_client_data* data = (overlay_client_data*)fBasePointer; 568 return data->buffer; 569 } 570 571 return (void*)fBasePointer; 572 } 573 574 575 /*! \brief Returns the size of the bitmap data. 576 \return The size of the bitmap data. 577 */ 578 int32 579 BBitmap::BitsLength() const 580 { 581 return fSize; 582 } 583 584 585 /*! \brief Returns the number of bytes used to store a row of bitmap data. 586 \return The number of bytes used to store a row of bitmap data. 587 */ 588 int32 589 BBitmap::BytesPerRow() const 590 { 591 return fBytesPerRow; 592 } 593 594 595 /*! \brief Returns the bitmap's color space. 596 \return The bitmap's color space. 597 */ 598 color_space 599 BBitmap::ColorSpace() const 600 { 601 return fColorSpace; 602 } 603 604 605 /*! \brief Returns the bitmap's dimensions. 606 \return The bitmap's dimensions. 607 */ 608 BRect 609 BBitmap::Bounds() const 610 { 611 return fBounds; 612 } 613 614 615 /*! \brief Returns the bitmap's creating flags. 616 617 This method informs about which flags have been used to create the 618 bitmap. It would for example tell you whether this is an overlay 619 bitmap. If bitmap creation succeeded, all flags are fulfilled. 620 621 \return The bitmap's creation flags. 622 */ 623 uint32 624 BBitmap::Flags() const 625 { 626 return fFlags; 627 } 628 629 630 /*! \brief Assigns data to the bitmap. 631 632 Data are directly written into the bitmap's data buffer, being converted 633 beforehand, if necessary. Some conversions work rather unintuitively: 634 - \c B_RGB32: The source buffer is supposed to contain \c B_RGB24_BIG 635 data without padding at the end of the rows. 636 - \c B_RGB32: The source buffer is supposed to contain \c B_CMAP8 637 data without padding at the end of the rows. 638 - other color spaces: The source buffer is supposed to contain data 639 according to the specified color space being rowwise padded to int32. 640 641 The currently supported source/target color spaces are 642 \c B_RGB{32,24,16,15}[_BIG], \c B_CMAP8 and \c B_GRAY{8,1}. 643 644 \note As this methods is apparently a bit strange to use, Haiku introduces 645 ImportBits() methods, which are recommended to be used instead. 646 647 \param data The data to be copied. 648 \param length The length in bytes of the data to be copied. 649 \param offset The offset (in bytes) relative to beginning of the bitmap 650 data specifying the position at which the source data shall be 651 written. 652 \param colorSpace Color space of the source data. 653 */ 654 void 655 BBitmap::SetBits(const void* data, int32 length, int32 offset, 656 color_space colorSpace) 657 { 658 status_t error = (InitCheck() == B_OK ? B_OK : B_NO_INIT); 659 // check params 660 if (error == B_OK && (data == NULL || offset > fSize || length < 0)) 661 error = B_BAD_VALUE; 662 int32 width = 0; 663 if (error == B_OK) 664 width = fBounds.IntegerWidth() + 1; 665 int32 inBPR = -1; 666 // tweaks to mimic R5 behavior 667 if (error == B_OK) { 668 if (colorSpace == B_RGB32) { 669 // B_RGB32 means actually unpadded B_RGB24_BIG 670 colorSpace = B_RGB24_BIG; 671 inBPR = width * 3; 672 } else if (colorSpace == B_CMAP8 && fColorSpace != B_CMAP8) { 673 // If in color space is B_CMAP8, but the bitmap's is another one, 674 // ignore source data row padding. 675 inBPR = width; 676 } 677 678 // call the sane method, which does the actual work 679 error = ImportBits(data, length, inBPR, offset, colorSpace); 680 } 681 } 682 683 684 /*! \brief Assigns data to the bitmap. 685 686 Data are directly written into the bitmap's data buffer, being converted 687 beforehand, if necessary. Unlike for SetBits(), the meaning of 688 \a colorSpace is exactly the expected one here, i.e. the source buffer 689 is supposed to contain data of that color space. \a bpr specifies how 690 many bytes the source contains per row. \c B_ANY_BYTES_PER_ROW can be 691 supplied, if standard padding to int32 is used. 692 693 The currently supported source/target color spaces are 694 \c B_RGB{32,24,16,15}[_BIG], \c B_CMAP8 and \c B_GRAY{8,1}. 695 696 \param data The data to be copied. 697 \param length The length in bytes of the data to be copied. 698 \param bpr The number of bytes per row in the source data. 699 \param offset The offset (in bytes) relative to beginning of the bitmap 700 data specifying the position at which the source data shall be 701 written. 702 \param colorSpace Color space of the source data. 703 \return 704 - \c B_OK: Everything went fine. 705 - \c B_BAD_VALUE: \c NULL \a data, invalid \a bpr or \a offset, or 706 unsupported \a colorSpace. 707 */ 708 status_t 709 BBitmap::ImportBits(const void* data, int32 length, int32 bpr, int32 offset, 710 color_space colorSpace) 711 { 712 _AssertPointer(); 713 714 if (InitCheck() != B_OK) 715 return B_NO_INIT; 716 717 if (!data || offset > fSize || length < 0) 718 return B_BAD_VALUE; 719 720 int32 width = fBounds.IntegerWidth() + 1; 721 if (bpr <= 0) { 722 if (bpr == B_ANY_BYTES_PER_ROW) 723 bpr = get_bytes_per_row(colorSpace, width); 724 else 725 return B_BAD_VALUE; 726 } 727 728 return BPrivate::ConvertBits(data, (uint8*)fBasePointer + offset, length, 729 fSize - offset, bpr, fBytesPerRow, colorSpace, fColorSpace, width, 730 fBounds.IntegerHeight() + 1); 731 } 732 733 734 /*! \brief Assigns data to the bitmap. 735 736 Allows for a BPoint offset in the source and in the bitmap. The region 737 of the source at \a from extending \a width and \a height is assigned 738 (and converted if necessary) to the bitmap at \a to. 739 740 The currently supported source/target color spaces are 741 \c B_RGB{32,24,16,15}[_BIG], \c B_CMAP8 and \c B_GRAY{8,1}. 742 743 \param data The data to be copied. 744 \param length The length in bytes of the data to be copied. 745 \param bpr The number of bytes per row in the source data. 746 \param colorSpace Color space of the source data. 747 \param from The offset in the source where reading should begin. 748 \param to The offset in the bitmap where the source should be written. 749 \param size The size (in pixels) to be imported. 750 \return 751 - \c B_OK: Everything went fine. 752 - \c B_BAD_VALUE: \c NULL \a data, invalid \a bpr, unsupported 753 \a colorSpace or invalid width/height. 754 */ 755 status_t 756 BBitmap::ImportBits(const void* data, int32 length, int32 bpr, 757 color_space colorSpace, BPoint from, BPoint to, BSize size) 758 { 759 _AssertPointer(); 760 761 if (InitCheck() != B_OK) 762 return B_NO_INIT; 763 764 if (!data || length < 0 || size.IntegerWidth() < 0 || size.IntegerHeight() < 0) 765 return B_BAD_VALUE; 766 767 if (bpr <= 0) { 768 if (bpr == B_ANY_BYTES_PER_ROW) 769 bpr = get_bytes_per_row(colorSpace, fBounds.IntegerWidth() + 1); 770 else 771 return B_BAD_VALUE; 772 } 773 774 return BPrivate::ConvertBits(data, fBasePointer, length, fSize, bpr, 775 fBytesPerRow, colorSpace, fColorSpace, from, to, 776 size.IntegerWidth() + 1, size.IntegerHeight() + 1); 777 } 778 779 780 status_t 781 BBitmap::ImportBits(const void* data, int32 length, int32 bpr, 782 color_space colorSpace, BPoint from, BPoint to, int32 width, int32 height) 783 { 784 return ImportBits(data, length, bpr, colorSpace, from, to, BSize(width - 1, height - 1)); 785 } 786 787 788 /*! \brief Assigns another bitmap's data to this bitmap. 789 790 The supplied bitmap must have the exactly same dimensions as this bitmap. 791 Its data is converted to the color space of this bitmap. 792 793 The currently supported source/target color spaces are 794 \c B_RGB{32,24,16,15}[_BIG], \c B_CMAP8 and \c B_GRAY{8,1}. 795 796 \param bitmap The source bitmap. 797 \return 798 - \c B_OK: Everything went fine. 799 - \c B_BAD_VALUE: \c NULL \a bitmap, or \a bitmap has other dimensions, 800 or the conversion from or to one of the color spaces is not supported. 801 */ 802 status_t 803 BBitmap::ImportBits(const BBitmap* bitmap) 804 { 805 if (InitCheck() != B_OK) 806 return B_NO_INIT; 807 808 if (!bitmap || bitmap->InitCheck() != B_OK || bitmap->Bounds() != fBounds) 809 return B_BAD_VALUE; 810 811 return ImportBits(bitmap->Bits(), bitmap->BitsLength(), 812 bitmap->BytesPerRow(), 0, bitmap->ColorSpace()); 813 } 814 815 816 /*! \brief Assigns data to the bitmap. 817 818 Allows for a BPoint offset in the source and in the bitmap. The region 819 of the source at \a from extending \a width and \a height is assigned 820 (and converted if necessary) to the bitmap at \a to. The source bitmap is 821 clipped to the bitmap and they don't need to have the same dimensions. 822 823 The currently supported source/target color spaces are 824 \c B_RGB{32,24,16,15}[_BIG], \c B_CMAP8 and \c B_GRAY{8,1}. 825 826 \param bitmap The source bitmap. 827 \param from The offset in the source where reading should begin. 828 \param to The offset in the bitmap where the source should be written. 829 \param size The size (in pixels) to be imported. 830 - \c B_OK: Everything went fine. 831 - \c B_BAD_VALUE: \c NULL \a bitmap, the conversion from or to one of 832 the color spaces is not supported, or invalid width/height. 833 */ 834 status_t 835 BBitmap::ImportBits(const BBitmap* bitmap, BPoint from, BPoint to, BSize size) 836 { 837 if (InitCheck() != B_OK) 838 return B_NO_INIT; 839 840 if (!bitmap || bitmap->InitCheck() != B_OK) 841 return B_BAD_VALUE; 842 843 return ImportBits(bitmap->Bits(), bitmap->BitsLength(), 844 bitmap->BytesPerRow(), bitmap->ColorSpace(), from, to, size); 845 } 846 847 848 status_t 849 BBitmap::ImportBits(const BBitmap* bitmap, BPoint from, BPoint to, int32 width, int32 height) 850 { 851 return ImportBits(bitmap, from, to, BSize(width - 1, height - 1)); 852 } 853 854 855 /*! \brief Returns the overlay_restrictions structure for this bitmap 856 */ 857 status_t 858 BBitmap::GetOverlayRestrictions(overlay_restrictions* restrictions) const 859 { 860 if ((fFlags & B_BITMAP_WILL_OVERLAY) == 0) 861 return B_BAD_TYPE; 862 863 BPrivate::AppServerLink link; 864 865 link.StartMessage(AS_GET_BITMAP_OVERLAY_RESTRICTIONS); 866 link.Attach<int32>(fServerToken); 867 868 status_t status; 869 if (link.FlushWithReply(status) < B_OK) 870 return status; 871 872 link.Read(restrictions, sizeof(overlay_restrictions)); 873 return B_OK; 874 } 875 876 877 /*! \brief Adds a BView to the bitmap's view hierarchy. 878 879 The bitmap must accept views and the supplied view must not be child of 880 another parent. 881 882 \param view The view to be added. 883 */ 884 void 885 BBitmap::AddChild(BView* view) 886 { 887 if (fWindow != NULL) 888 fWindow->AddChild(view); 889 } 890 891 892 /*! \brief Removes a BView from the bitmap's view hierarchy. 893 \param view The view to be removed. 894 */ 895 bool 896 BBitmap::RemoveChild(BView* view) 897 { 898 return fWindow != NULL ? fWindow->RemoveChild(view) : false; 899 } 900 901 902 /*! \brief Returns the number of BViews currently belonging to the bitmap. 903 \return The number of BViews currently belonging to the bitmap. 904 */ 905 int32 906 BBitmap::CountChildren() const 907 { 908 return fWindow != NULL ? fWindow->CountChildren() : 0; 909 } 910 911 912 /*! \brief Returns the BView at a certain index in the bitmap's list of views. 913 \param index The index of the BView to be returned. 914 \return The BView at index \a index or \c NULL, if the index is out of 915 range. 916 */ 917 BView* 918 BBitmap::ChildAt(int32 index) const 919 { 920 return fWindow != NULL ? fWindow->ChildAt(index) : NULL; 921 } 922 923 924 /*! \brief Returns a bitmap's BView with a certain name. 925 \param name The name of the BView to be returned. 926 \return The BView with the name \a name or \c NULL, if the bitmap doesn't 927 know a view with that name. 928 */ 929 BView* 930 BBitmap::FindView(const char* viewName) const 931 { 932 return fWindow != NULL ? fWindow->FindView(viewName) : NULL; 933 } 934 935 936 /*! \brief Returns a bitmap's BView at a certain location. 937 \param point The location. 938 \return The BView with located at \a point or \c NULL, if the bitmap 939 doesn't know a view at this location. 940 */ 941 BView* 942 BBitmap::FindView(BPoint point) const 943 { 944 return fWindow != NULL ? fWindow->FindView(point) : NULL; 945 } 946 947 948 /*! \brief Locks the off-screen window that belongs to the bitmap. 949 950 The bitmap must accept views, if locking should work. 951 952 \return \c true, if the lock was acquired successfully, \c false 953 otherwise. 954 */ 955 bool 956 BBitmap::Lock() 957 { 958 return fWindow != NULL ? fWindow->Lock() : false; 959 } 960 961 962 /*! \brief Unlocks the off-screen window that belongs to the bitmap. 963 964 The bitmap must accept views, if locking should work. 965 */ 966 void 967 BBitmap::Unlock() 968 { 969 if (fWindow != NULL) 970 fWindow->Unlock(); 971 } 972 973 974 /*! \brief Returns whether or not the bitmap's off-screen window is locked. 975 976 The bitmap must accept views, if locking should work. 977 978 \return \c true, if the caller owns a lock , \c false otherwise. 979 */ 980 bool 981 BBitmap::IsLocked() const 982 { 983 return fWindow != NULL ? fWindow->IsLocked() : false; 984 } 985 986 987 BBitmap& 988 BBitmap::operator=(const BBitmap& source) 989 { 990 _CleanUp(); 991 fInitError = B_NO_INIT; 992 993 if (!source.IsValid()) 994 return *this; 995 996 _InitObject(source.Bounds(), source.ColorSpace(), source.Flags(), 997 source.BytesPerRow(), B_MAIN_SCREEN_ID); 998 if (InitCheck() == B_OK) 999 memcpy(Bits(), source.Bits(), min_c(BitsLength(), source.BitsLength())); 1000 1001 return *this; 1002 } 1003 1004 1005 status_t 1006 BBitmap::Perform(perform_code d, void* arg) 1007 { 1008 return BArchivable::Perform(d, arg); 1009 } 1010 1011 // FBC 1012 void BBitmap::_ReservedBitmap1() {} 1013 void BBitmap::_ReservedBitmap2() {} 1014 void BBitmap::_ReservedBitmap3() {} 1015 1016 1017 #if 0 1018 // get_shared_pointer 1019 /*! \brief ??? 1020 */ 1021 char* 1022 BBitmap::get_shared_pointer() const 1023 { 1024 return NULL; // not implemented 1025 } 1026 #endif 1027 1028 int32 1029 BBitmap::_ServerToken() const 1030 { 1031 return fServerToken; 1032 } 1033 1034 1035 /*! \brief Initializes the bitmap. 1036 \param bounds The bitmap dimensions. 1037 \param colorSpace The bitmap's color space. 1038 \param flags Creation flags. 1039 \param bytesPerRow The number of bytes per row the bitmap should use. 1040 \c B_ANY_BYTES_PER_ROW to let the constructor choose an appropriate 1041 value. 1042 \param screenID ??? 1043 */ 1044 void 1045 BBitmap::_InitObject(BRect bounds, color_space colorSpace, uint32 flags, 1046 int32 bytesPerRow, screen_id screenID, area_id area, ptrdiff_t areaOffset) 1047 { 1048 //printf("BBitmap::InitObject(bounds: BRect(%.1f, %.1f, %.1f, %.1f), format: %ld, flags: %ld, bpr: %ld\n", 1049 // bounds.left, bounds.top, bounds.right, bounds.bottom, colorSpace, flags, bytesPerRow); 1050 1051 // TODO: Should we handle rounding of the "bounds" here? How does R5 behave? 1052 1053 status_t error = B_OK; 1054 1055 #ifdef RUN_WITHOUT_APP_SERVER 1056 flags |= B_BITMAP_NO_SERVER_LINK; 1057 #endif // RUN_WITHOUT_APP_SERVER 1058 1059 _CleanUp(); 1060 1061 // check params 1062 if (!bounds.IsValid() || !bitmaps_support_space(colorSpace, NULL)) { 1063 error = B_BAD_VALUE; 1064 } else { 1065 // bounds is in floats and might be valid but much larger than what we 1066 // can handle the size could not be expressed in int32 1067 double realSize = bounds.Width() * bounds.Height(); 1068 if (realSize > (double)(INT_MAX / 4)) { 1069 fprintf(stderr, "bitmap bounds is much too large: " 1070 "BRect(%.1f, %.1f, %.1f, %.1f)\n", 1071 bounds.left, bounds.top, bounds.right, bounds.bottom); 1072 error = B_BAD_VALUE; 1073 } 1074 } 1075 if (error == B_OK) { 1076 int32 bpr = get_bytes_per_row(colorSpace, bounds.IntegerWidth() + 1); 1077 if (bytesPerRow < 0) 1078 bytesPerRow = bpr; 1079 else if (bytesPerRow < bpr) 1080 // NOTE: How does R5 behave? 1081 error = B_BAD_VALUE; 1082 } 1083 // allocate the bitmap buffer 1084 if (error == B_OK) { 1085 // TODO: Let the app_server return the size when it allocated the bitmap 1086 int32 size = bytesPerRow * (bounds.IntegerHeight() + 1); 1087 1088 if ((flags & B_BITMAP_NO_SERVER_LINK) != 0) { 1089 fBasePointer = (uint8*)malloc(size); 1090 if (fBasePointer) { 1091 fSize = size; 1092 fColorSpace = colorSpace; 1093 fBounds = bounds; 1094 fBytesPerRow = bytesPerRow; 1095 fFlags = flags; 1096 } else 1097 error = B_NO_MEMORY; 1098 } else { 1099 BPrivate::AppServerLink link; 1100 1101 if (area >= B_OK) { 1102 // Use area provided by client 1103 1104 area_info info; 1105 get_area_info(area, &info); 1106 1107 // Area should be owned by current team. Client should clone area if needed. 1108 if (info.team != getpid()) 1109 error = B_BAD_VALUE; 1110 else { 1111 link.StartMessage(AS_RECONNECT_BITMAP); 1112 link.Attach<BRect>(bounds); 1113 link.Attach<color_space>(colorSpace); 1114 link.Attach<uint32>(flags); 1115 link.Attach<int32>(bytesPerRow); 1116 link.Attach<int32>(0); 1117 link.Attach<int32>(area); 1118 link.Attach<int32>(areaOffset); 1119 1120 if (link.FlushWithReply(error) == B_OK && error == B_OK) { 1121 link.Read<int32>(&fServerToken); 1122 link.Read<area_id>(&fServerArea); 1123 1124 if (fServerArea >= B_OK) { 1125 fSize = size; 1126 fColorSpace = colorSpace; 1127 fBounds = bounds; 1128 fBytesPerRow = bytesPerRow; 1129 fFlags = flags; 1130 fArea = area; 1131 fAreaOffset = areaOffset; 1132 1133 fBasePointer = (uint8*)info.address + areaOffset; 1134 } else 1135 error = fServerArea; 1136 } 1137 } 1138 } else { 1139 // Ask the server (via our owning application) to create a bitmap. 1140 1141 // Attach Data: 1142 // 1) BRect bounds 1143 // 2) color_space space 1144 // 3) int32 bitmap_flags 1145 // 4) int32 bytes_per_row 1146 // 5) int32 screen_id::id 1147 link.StartMessage(AS_CREATE_BITMAP); 1148 link.Attach<BRect>(bounds); 1149 link.Attach<color_space>(colorSpace); 1150 link.Attach<uint32>(flags); 1151 link.Attach<int32>(bytesPerRow); 1152 link.Attach<int32>(screenID.id); 1153 1154 if (link.FlushWithReply(error) == B_OK && error == B_OK) { 1155 // server side success 1156 // Get token 1157 link.Read<int32>(&fServerToken); 1158 1159 uint8 allocationFlags; 1160 link.Read<uint8>(&allocationFlags); 1161 link.Read<area_id>(&fServerArea); 1162 link.Read<int32>(&fAreaOffset); 1163 1164 BPrivate::ServerMemoryAllocator* allocator 1165 = BApplication::Private::ServerAllocator(); 1166 1167 if ((allocationFlags & kNewAllocatorArea) != 0) { 1168 error = allocator->AddArea(fServerArea, fArea, 1169 fBasePointer, size); 1170 } else { 1171 error = allocator->AreaAndBaseFor(fServerArea, fArea, 1172 fBasePointer); 1173 if (error == B_OK) 1174 fBasePointer += fAreaOffset; 1175 } 1176 1177 if ((allocationFlags & kFramebuffer) != 0) { 1178 // The base pointer will now point to an overlay_client_data 1179 // structure bytes per row might be modified to match 1180 // hardware constraints 1181 link.Read<int32>(&bytesPerRow); 1182 size = bytesPerRow * (bounds.IntegerHeight() + 1); 1183 } 1184 1185 if (fServerArea >= B_OK) { 1186 fSize = size; 1187 fColorSpace = colorSpace; 1188 fBounds = bounds; 1189 fBytesPerRow = bytesPerRow; 1190 fFlags = flags; 1191 } else 1192 error = fServerArea; 1193 } 1194 } 1195 1196 1197 if (error < B_OK) { 1198 fBasePointer = NULL; 1199 fServerToken = -1; 1200 fArea = -1; 1201 fServerArea = -1; 1202 fAreaOffset = -1; 1203 // NOTE: why not "0" in case of error? 1204 fFlags = flags; 1205 } else { 1206 BAutolock _(sBitmapListLock); 1207 sBitmapList.AddItem(this); 1208 } 1209 } 1210 fWindow = NULL; 1211 } 1212 1213 fInitError = error; 1214 1215 if (fInitError == B_OK) { 1216 // clear to white if the flags say so. 1217 if (flags & B_BITMAP_CLEAR_TO_WHITE) { 1218 if (fColorSpace == B_CMAP8) { 1219 // "255" is the "transparent magic" index for B_CMAP8 bitmaps 1220 // use the correct index for "white" 1221 memset(fBasePointer, 65, fSize); 1222 } else { 1223 // should work for most colorspaces 1224 memset(fBasePointer, 0xff, fSize); 1225 } 1226 } 1227 // TODO: Creating an offscreen window with a non32 bit bitmap 1228 // copies the current content of the bitmap to a back buffer. 1229 // So at this point the bitmap has to be already cleared to white. 1230 // Better move the above code to the server so the problem looks more 1231 // clear. 1232 if (flags & B_BITMAP_ACCEPTS_VIEWS) { 1233 fWindow = new(std::nothrow) BWindow(Bounds(), fServerToken); 1234 if (fWindow) { 1235 // A BWindow starts life locked and is unlocked 1236 // in Show(), but this window is never shown and 1237 // it's message loop is never started. 1238 fWindow->Unlock(); 1239 } else 1240 fInitError = B_NO_MEMORY; 1241 } 1242 } 1243 } 1244 1245 1246 /*! \brief Cleans up any memory allocated by the bitmap and 1247 informs the server to do so as well (if needed). 1248 */ 1249 void 1250 BBitmap::_CleanUp() 1251 { 1252 if (fWindow != NULL) { 1253 if (fWindow->Lock()) 1254 delete fWindow; 1255 fWindow = NULL; 1256 // this will leak fWindow if it couldn't be locked 1257 } 1258 1259 if (fBasePointer == NULL) 1260 return; 1261 1262 if ((fFlags & B_BITMAP_NO_SERVER_LINK) != 0) { 1263 free(fBasePointer); 1264 } else if (fServerToken != -1) { 1265 BPrivate::AppServerLink link; 1266 // AS_DELETE_BITMAP: 1267 // Attached Data: 1268 // 1) int32 server token 1269 link.StartMessage(AS_DELETE_BITMAP); 1270 link.Attach<int32>(fServerToken); 1271 link.Flush(); 1272 1273 // The server areas are deleted via kMsgDeleteServerMemoryArea message 1274 1275 fArea = -1; 1276 fServerToken = -1; 1277 fAreaOffset = -1; 1278 1279 BAutolock _(sBitmapListLock); 1280 sBitmapList.RemoveItem(this); 1281 } 1282 fBasePointer = NULL; 1283 } 1284 1285 1286 void 1287 BBitmap::_AssertPointer() 1288 { 1289 if (fBasePointer == NULL && fServerArea >= B_OK && fAreaOffset == -1) { 1290 // We lazily clone our own areas - if the bitmap is part of the usual 1291 // server memory area, or is a B_BITMAP_NO_SERVER_LINK bitmap, it 1292 // already has its data. 1293 fArea = clone_area("shared bitmap area", (void**)&fBasePointer, 1294 B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA, fServerArea); 1295 } 1296 } 1297 1298 1299 void 1300 BBitmap::_ReconnectToAppServer() 1301 { 1302 BPrivate::AppServerLink link; 1303 1304 link.StartMessage(AS_RECONNECT_BITMAP); 1305 link.Attach<BRect>(fBounds); 1306 link.Attach<color_space>(fColorSpace); 1307 link.Attach<uint32>(fFlags); 1308 link.Attach<int32>(fBytesPerRow); 1309 link.Attach<int32>(0); 1310 link.Attach<int32>(fArea); 1311 link.Attach<int32>(fAreaOffset); 1312 1313 status_t error; 1314 if (link.FlushWithReply(error) == B_OK && error == B_OK) { 1315 // server side success 1316 // Get token 1317 link.Read<int32>(&fServerToken); 1318 1319 link.Read<area_id>(&fServerArea); 1320 } 1321 } 1322