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 /*! \brief Frees all resources associated with this object. 312 */ 313 BBitmap::~BBitmap() 314 { 315 _CleanUp(); 316 } 317 318 319 /*! \brief Unarchives a bitmap from a BMessage. 320 \param data The archive. 321 */ 322 BBitmap::BBitmap(BMessage* data) 323 : 324 BArchivable(data), 325 fBasePointer(NULL), 326 fSize(0), 327 fColorSpace(B_NO_COLOR_SPACE), 328 fBounds(0, 0, -1, -1), 329 fBytesPerRow(0), 330 fWindow(NULL), 331 fServerToken(-1), 332 fAreaOffset(-1), 333 fArea(-1), 334 fServerArea(-1), 335 fFlags(0), 336 fInitError(B_NO_INIT) 337 { 338 int32 flags; 339 if (data->FindInt32("_bmflags", &flags) != B_OK) { 340 // this bitmap is archived in some archaic format 341 flags = 0; 342 343 bool acceptsViews; 344 if (data->FindBool("_view_ok", &acceptsViews) == B_OK && acceptsViews) 345 flags |= B_BITMAP_ACCEPTS_VIEWS; 346 347 bool contiguous; 348 if (data->FindBool("_contiguous", &contiguous) == B_OK && contiguous) 349 flags |= B_BITMAP_IS_CONTIGUOUS; 350 } 351 352 int32 rowBytes; 353 if (data->FindInt32("_rowbytes", &rowBytes) != B_OK) { 354 rowBytes = -1; 355 // bytes per row are computed in InitObject(), then 356 } 357 358 BRect bounds; 359 color_space cspace; 360 if (data->FindRect("_frame", &bounds) == B_OK 361 && data->FindInt32("_cspace", (int32*)&cspace) == B_OK) { 362 _InitObject(bounds, cspace, flags, rowBytes, B_MAIN_SCREEN_ID); 363 } 364 365 if (InitCheck() == B_OK) { 366 ssize_t size; 367 const void* buffer; 368 if (data->FindData("_data", B_RAW_TYPE, &buffer, &size) == B_OK) { 369 if (size == BitsLength()) { 370 _AssertPointer(); 371 memcpy(fBasePointer, buffer, size); 372 } 373 } 374 } 375 376 if ((fFlags & B_BITMAP_ACCEPTS_VIEWS) != 0) { 377 BMessage message; 378 int32 i = 0; 379 380 while (data->FindMessage("_views", i++, &message) == B_OK) { 381 if (BView* view 382 = dynamic_cast<BView*>(instantiate_object(&message))) 383 AddChild(view); 384 } 385 } 386 } 387 388 389 /*! \brief Instantiates a BBitmap from an archive. 390 \param data The archive. 391 \return A bitmap reconstructed from the archive or \c NULL, if an error 392 occured. 393 */ 394 BArchivable* 395 BBitmap::Instantiate(BMessage* data) 396 { 397 if (validate_instantiation(data, "BBitmap")) 398 return new BBitmap(data); 399 400 return NULL; 401 } 402 403 404 /*! \brief Archives the BBitmap object. 405 \param data The archive. 406 \param deep \c true, if child object shall be archived as well, \c false 407 otherwise. 408 \return \c B_OK, if everything went fine, an error code otherwise. 409 */ 410 status_t 411 BBitmap::Archive(BMessage* data, bool deep) const 412 { 413 status_t ret = BArchivable::Archive(data, deep); 414 415 if (ret == B_OK) 416 ret = data->AddRect("_frame", fBounds); 417 418 if (ret == B_OK) 419 ret = data->AddInt32("_cspace", (int32)fColorSpace); 420 421 if (ret == B_OK) 422 ret = data->AddInt32("_bmflags", fFlags); 423 424 if (ret == B_OK) 425 ret = data->AddInt32("_rowbytes", fBytesPerRow); 426 427 if (ret == B_OK && deep) { 428 if ((fFlags & B_BITMAP_ACCEPTS_VIEWS) != 0) { 429 BMessage views; 430 for (int32 i = 0; i < CountChildren(); i++) { 431 if (ChildAt(i)->Archive(&views, deep)) 432 ret = data->AddMessage("_views", &views); 433 views.MakeEmpty(); 434 if (ret < B_OK) 435 break; 436 } 437 } 438 } 439 // Note: R5 does not archive the data if B_BITMAP_IS_CONTIGUOUS is 440 // true and it does save all formats as B_RAW_TYPE and it does save 441 // the data even if B_BITMAP_ACCEPTS_VIEWS is set (as opposed to 442 // the BeBook) 443 if (ret == B_OK) { 444 const_cast<BBitmap*>(this)->_AssertPointer(); 445 ret = data->AddData("_data", B_RAW_TYPE, fBasePointer, fSize); 446 } 447 return ret; 448 } 449 450 451 /*! \brief Returns the result from the construction. 452 \return \c B_OK, if the object is properly initialized, an error code 453 otherwise. 454 */ 455 status_t 456 BBitmap::InitCheck() const 457 { 458 return fInitError; 459 } 460 461 462 /*! \brief Returns whether or not the BBitmap object is valid. 463 \return \c true, if the object is properly initialized, \c false otherwise. 464 */ 465 bool 466 BBitmap::IsValid() const 467 { 468 return InitCheck() == B_OK; 469 } 470 471 472 /*! \brief Locks the bitmap bits so that they cannot be relocated. 473 474 This is currently only used for overlay bitmaps - whenever you 475 need to access their Bits(), you have to lock them first. 476 On resolution change overlay bitmaps can be relocated in memory; 477 using this call prevents you from accessing an invalid pointer 478 and clobbering memory that doesn't belong you. 479 */ 480 status_t 481 BBitmap::LockBits(uint32* state) 482 { 483 // TODO: how do we fill the "state"? 484 // It would be more or less useful to report what kind of bitmap 485 // we got (ie. overlay, placeholder, or non-overlay) 486 if ((fFlags & B_BITMAP_WILL_OVERLAY) != 0) { 487 overlay_client_data* data = (overlay_client_data*)fBasePointer; 488 489 status_t status; 490 do { 491 status = acquire_sem(data->lock); 492 } while (status == B_INTERRUPTED); 493 494 if (data->buffer == NULL) { 495 // the app_server does not grant us access to the frame buffer 496 // right now - let's release the lock and fail 497 release_sem_etc(data->lock, 1, B_DO_NOT_RESCHEDULE); 498 return B_BUSY; 499 } 500 return status; 501 } 502 503 // NOTE: maybe this is used to prevent the app_server from 504 // drawing the bitmap yet? 505 // axeld: you mean for non overlays? 506 507 return B_OK; 508 } 509 510 511 /*! \brief Unlocks the bitmap's buffer again. 512 Counterpart to LockBits(), see there for comments. 513 */ 514 void 515 BBitmap::UnlockBits() 516 { 517 if ((fFlags & B_BITMAP_WILL_OVERLAY) == 0) 518 return; 519 520 overlay_client_data* data = (overlay_client_data*)fBasePointer; 521 release_sem_etc(data->lock, 1, B_DO_NOT_RESCHEDULE); 522 } 523 524 525 /*! \brief Returns the ID of the area the bitmap data reside in. 526 \return The ID of the area the bitmap data reside in. 527 */ 528 area_id 529 BBitmap::Area() const 530 { 531 const_cast<BBitmap*>(this)->_AssertPointer(); 532 return fArea; 533 } 534 535 536 /*! \brief Returns the pointer to the bitmap data. 537 \return The pointer to the bitmap data. 538 */ 539 void* 540 BBitmap::Bits() const 541 { 542 const_cast<BBitmap*>(this)->_AssertPointer(); 543 544 if ((fFlags & B_BITMAP_WILL_OVERLAY) != 0) { 545 overlay_client_data* data = (overlay_client_data*)fBasePointer; 546 return data->buffer; 547 } 548 549 return (void*)fBasePointer; 550 } 551 552 553 /*! \brief Returns the size of the bitmap data. 554 \return The size of the bitmap data. 555 */ 556 int32 557 BBitmap::BitsLength() const 558 { 559 return fSize; 560 } 561 562 563 /*! \brief Returns the number of bytes used to store a row of bitmap data. 564 \return The number of bytes used to store a row of bitmap data. 565 */ 566 int32 567 BBitmap::BytesPerRow() const 568 { 569 return fBytesPerRow; 570 } 571 572 573 /*! \brief Returns the bitmap's color space. 574 \return The bitmap's color space. 575 */ 576 color_space 577 BBitmap::ColorSpace() const 578 { 579 return fColorSpace; 580 } 581 582 583 /*! \brief Returns the bitmap's dimensions. 584 \return The bitmap's dimensions. 585 */ 586 BRect 587 BBitmap::Bounds() const 588 { 589 return fBounds; 590 } 591 592 593 /*! \brief Returns the bitmap's creating flags. 594 595 This method informs about which flags have been used to create the 596 bitmap. It would for example tell you whether this is an overlay 597 bitmap. If bitmap creation succeeded, all flags are fulfilled. 598 599 \return The bitmap's creation flags. 600 */ 601 uint32 602 BBitmap::Flags() const 603 { 604 return fFlags; 605 } 606 607 608 /*! \brief Assigns data to the bitmap. 609 610 Data are directly written into the bitmap's data buffer, being converted 611 beforehand, if necessary. Some conversions work rather unintuitively: 612 - \c B_RGB32: The source buffer is supposed to contain \c B_RGB24_BIG 613 data without padding at the end of the rows. 614 - \c B_RGB32: The source buffer is supposed to contain \c B_CMAP8 615 data without padding at the end of the rows. 616 - other color spaces: The source buffer is supposed to contain data 617 according to the specified color space being rowwise padded to int32. 618 619 The currently supported source/target color spaces are 620 \c B_RGB{32,24,16,15}[_BIG], \c B_CMAP8 and \c B_GRAY{8,1}. 621 622 \note As this methods is apparently a bit strange to use, Haiku introduces 623 ImportBits() methods, which are recommended to be used instead. 624 625 \param data The data to be copied. 626 \param length The length in bytes of the data to be copied. 627 \param offset The offset (in bytes) relative to beginning of the bitmap 628 data specifying the position at which the source data shall be 629 written. 630 \param colorSpace Color space of the source data. 631 */ 632 void 633 BBitmap::SetBits(const void* data, int32 length, int32 offset, 634 color_space colorSpace) 635 { 636 status_t error = (InitCheck() == B_OK ? B_OK : B_NO_INIT); 637 // check params 638 if (error == B_OK && (data == NULL || offset > fSize || length < 0)) 639 error = B_BAD_VALUE; 640 int32 width = 0; 641 if (error == B_OK) 642 width = fBounds.IntegerWidth() + 1; 643 int32 inBPR = -1; 644 // tweaks to mimic R5 behavior 645 if (error == B_OK) { 646 if (colorSpace == B_CMAP8 && fColorSpace != B_CMAP8) { 647 // If in color space is B_CMAP8, but the bitmap's is another one, 648 // ignore source data row padding. 649 inBPR = width; 650 } 651 652 // call the sane method, which does the actual work 653 error = ImportBits(data, length, inBPR, offset, colorSpace); 654 } 655 } 656 657 658 /*! \brief Assigns data to the bitmap. 659 660 Data are directly written into the bitmap's data buffer, being converted 661 beforehand, if necessary. Unlike for SetBits(), the meaning of 662 \a colorSpace is exactly the expected one here, i.e. the source buffer 663 is supposed to contain data of that color space. \a bpr specifies how 664 many bytes the source contains per row. \c B_ANY_BYTES_PER_ROW can be 665 supplied, if standard padding to int32 is used. 666 667 The currently supported source/target color spaces are 668 \c B_RGB{32,24,16,15}[_BIG], \c B_CMAP8 and \c B_GRAY{8,1}. 669 670 \param data The data to be copied. 671 \param length The length in bytes of the data to be copied. 672 \param bpr The number of bytes per row in the source data. 673 \param offset The offset (in bytes) relative to beginning of the bitmap 674 data specifying the position at which the source data shall be 675 written. 676 \param colorSpace Color space of the source data. 677 \return 678 - \c B_OK: Everything went fine. 679 - \c B_BAD_VALUE: \c NULL \a data, invalid \a bpr or \a offset, or 680 unsupported \a colorSpace. 681 */ 682 status_t 683 BBitmap::ImportBits(const void* data, int32 length, int32 bpr, int32 offset, 684 color_space colorSpace) 685 { 686 _AssertPointer(); 687 688 if (InitCheck() != B_OK) 689 return B_NO_INIT; 690 691 if (!data || offset > fSize || length < 0) 692 return B_BAD_VALUE; 693 694 int32 width = fBounds.IntegerWidth() + 1; 695 if (bpr <= 0) { 696 if (bpr == B_ANY_BYTES_PER_ROW) 697 bpr = get_bytes_per_row(colorSpace, width); 698 else 699 return B_BAD_VALUE; 700 } 701 702 return BPrivate::ConvertBits(data, (uint8*)fBasePointer + offset, length, 703 fSize - offset, bpr, fBytesPerRow, colorSpace, fColorSpace, width, 704 fBounds.IntegerHeight() + 1); 705 } 706 707 708 /*! \brief Assigns data to the bitmap. 709 710 Allows for a BPoint offset in the source and in the bitmap. The region 711 of the source at \a from extending \a width and \a height is assigned 712 (and converted if necessary) to the bitmap at \a to. 713 714 The currently supported source/target color spaces are 715 \c B_RGB{32,24,16,15}[_BIG], \c B_CMAP8 and \c B_GRAY{8,1}. 716 717 \param data The data to be copied. 718 \param length The length in bytes of the data to be copied. 719 \param bpr The number of bytes per row in the source data. 720 \param colorSpace Color space of the source data. 721 \param from The offset in the source where reading should begin. 722 \param to The offset in the bitmap where the source should be written. 723 \param size The size (in pixels) to be imported. 724 \return 725 - \c B_OK: Everything went fine. 726 - \c B_BAD_VALUE: \c NULL \a data, invalid \a bpr, unsupported 727 \a colorSpace or invalid width/height. 728 */ 729 status_t 730 BBitmap::ImportBits(const void* data, int32 length, int32 bpr, 731 color_space colorSpace, BPoint from, BPoint to, BSize size) 732 { 733 _AssertPointer(); 734 735 if (InitCheck() != B_OK) 736 return B_NO_INIT; 737 738 if (!data || length < 0 || size.IntegerWidth() < 0 || size.IntegerHeight() < 0) 739 return B_BAD_VALUE; 740 741 if (bpr <= 0) { 742 if (bpr == B_ANY_BYTES_PER_ROW) 743 bpr = get_bytes_per_row(colorSpace, fBounds.IntegerWidth() + 1); 744 else 745 return B_BAD_VALUE; 746 } 747 748 return BPrivate::ConvertBits(data, fBasePointer, length, fSize, bpr, 749 fBytesPerRow, colorSpace, fColorSpace, from, to, 750 size.IntegerWidth() + 1, size.IntegerHeight() + 1); 751 } 752 753 754 status_t 755 BBitmap::ImportBits(const void* data, int32 length, int32 bpr, 756 color_space colorSpace, BPoint from, BPoint to, int32 width, int32 height) 757 { 758 return ImportBits(data, length, bpr, colorSpace, from, to, BSize(width - 1, height - 1)); 759 } 760 761 762 /*! \brief Assigns another bitmap's data to this bitmap. 763 764 The supplied bitmap must have the exactly same dimensions as this bitmap. 765 Its data is converted to the color space of this bitmap. 766 767 The currently supported source/target color spaces are 768 \c B_RGB{32,24,16,15}[_BIG], \c B_CMAP8 and \c B_GRAY{8,1}. 769 770 \param bitmap The source bitmap. 771 \return 772 - \c B_OK: Everything went fine. 773 - \c B_BAD_VALUE: \c NULL \a bitmap, or \a bitmap has other dimensions, 774 or the conversion from or to one of the color spaces is not supported. 775 */ 776 status_t 777 BBitmap::ImportBits(const BBitmap* bitmap) 778 { 779 if (InitCheck() != B_OK) 780 return B_NO_INIT; 781 782 if (!bitmap || bitmap->InitCheck() != B_OK || bitmap->Bounds() != fBounds) 783 return B_BAD_VALUE; 784 785 return ImportBits(bitmap->Bits(), bitmap->BitsLength(), 786 bitmap->BytesPerRow(), 0, bitmap->ColorSpace()); 787 } 788 789 790 /*! \brief Assigns data to the bitmap. 791 792 Allows for a BPoint offset in the source and in the bitmap. The region 793 of the source at \a from extending \a width and \a height is assigned 794 (and converted if necessary) to the bitmap at \a to. The source bitmap is 795 clipped to the bitmap and they don't need to have the same dimensions. 796 797 The currently supported source/target color spaces are 798 \c B_RGB{32,24,16,15}[_BIG], \c B_CMAP8 and \c B_GRAY{8,1}. 799 800 \param bitmap The source bitmap. 801 \param from The offset in the source where reading should begin. 802 \param to The offset in the bitmap where the source should be written. 803 \param size The size (in pixels) to be imported. 804 - \c B_OK: Everything went fine. 805 - \c B_BAD_VALUE: \c NULL \a bitmap, the conversion from or to one of 806 the color spaces is not supported, or invalid width/height. 807 */ 808 status_t 809 BBitmap::ImportBits(const BBitmap* bitmap, BPoint from, BPoint to, BSize size) 810 { 811 if (InitCheck() != B_OK) 812 return B_NO_INIT; 813 814 if (!bitmap || bitmap->InitCheck() != B_OK) 815 return B_BAD_VALUE; 816 817 return ImportBits(bitmap->Bits(), bitmap->BitsLength(), 818 bitmap->BytesPerRow(), bitmap->ColorSpace(), from, to, size); 819 } 820 821 822 status_t 823 BBitmap::ImportBits(const BBitmap* bitmap, BPoint from, BPoint to, int32 width, int32 height) 824 { 825 return ImportBits(bitmap, from, to, BSize(width - 1, height - 1)); 826 } 827 828 829 /*! \brief Returns the overlay_restrictions structure for this bitmap 830 */ 831 status_t 832 BBitmap::GetOverlayRestrictions(overlay_restrictions* restrictions) const 833 { 834 if ((fFlags & B_BITMAP_WILL_OVERLAY) == 0) 835 return B_BAD_TYPE; 836 837 BPrivate::AppServerLink link; 838 839 link.StartMessage(AS_GET_BITMAP_OVERLAY_RESTRICTIONS); 840 link.Attach<int32>(fServerToken); 841 842 status_t status; 843 if (link.FlushWithReply(status) < B_OK) 844 return status; 845 846 link.Read(restrictions, sizeof(overlay_restrictions)); 847 return B_OK; 848 } 849 850 851 /*! \brief Adds a BView to the bitmap's view hierarchy. 852 853 The bitmap must accept views and the supplied view must not be child of 854 another parent. 855 856 \param view The view to be added. 857 */ 858 void 859 BBitmap::AddChild(BView* view) 860 { 861 if (fWindow != NULL) 862 fWindow->AddChild(view); 863 } 864 865 866 /*! \brief Removes a BView from the bitmap's view hierarchy. 867 \param view The view to be removed. 868 */ 869 bool 870 BBitmap::RemoveChild(BView* view) 871 { 872 return fWindow != NULL ? fWindow->RemoveChild(view) : false; 873 } 874 875 876 /*! \brief Returns the number of BViews currently belonging to the bitmap. 877 \return The number of BViews currently belonging to the bitmap. 878 */ 879 int32 880 BBitmap::CountChildren() const 881 { 882 return fWindow != NULL ? fWindow->CountChildren() : 0; 883 } 884 885 886 /*! \brief Returns the BView at a certain index in the bitmap's list of views. 887 \param index The index of the BView to be returned. 888 \return The BView at index \a index or \c NULL, if the index is out of 889 range. 890 */ 891 BView* 892 BBitmap::ChildAt(int32 index) const 893 { 894 return fWindow != NULL ? fWindow->ChildAt(index) : NULL; 895 } 896 897 898 /*! \brief Returns a bitmap's BView with a certain name. 899 \param name The name of the BView to be returned. 900 \return The BView with the name \a name or \c NULL, if the bitmap doesn't 901 know a view with that name. 902 */ 903 BView* 904 BBitmap::FindView(const char* viewName) const 905 { 906 return fWindow != NULL ? fWindow->FindView(viewName) : NULL; 907 } 908 909 910 /*! \brief Returns a bitmap's BView at a certain location. 911 \param point The location. 912 \return The BView with located at \a point or \c NULL, if the bitmap 913 doesn't know a view at this location. 914 */ 915 BView* 916 BBitmap::FindView(BPoint point) const 917 { 918 return fWindow != NULL ? fWindow->FindView(point) : NULL; 919 } 920 921 922 /*! \brief Locks the off-screen window that belongs to the bitmap. 923 924 The bitmap must accept views, if locking should work. 925 926 \return \c true, if the lock was acquired successfully, \c false 927 otherwise. 928 */ 929 bool 930 BBitmap::Lock() 931 { 932 return fWindow != NULL ? fWindow->Lock() : false; 933 } 934 935 936 /*! \brief Unlocks the off-screen window that belongs to the bitmap. 937 938 The bitmap must accept views, if locking should work. 939 */ 940 void 941 BBitmap::Unlock() 942 { 943 if (fWindow != NULL) 944 fWindow->Unlock(); 945 } 946 947 948 /*! \brief Returns whether or not the bitmap's off-screen window is locked. 949 950 The bitmap must accept views, if locking should work. 951 952 \return \c true, if the caller owns a lock , \c false otherwise. 953 */ 954 bool 955 BBitmap::IsLocked() const 956 { 957 return fWindow != NULL ? fWindow->IsLocked() : false; 958 } 959 960 961 BBitmap& 962 BBitmap::operator=(const BBitmap& source) 963 { 964 _CleanUp(); 965 fInitError = B_NO_INIT; 966 967 if (!source.IsValid()) 968 return *this; 969 970 _InitObject(source.Bounds(), source.ColorSpace(), source.Flags(), 971 source.BytesPerRow(), B_MAIN_SCREEN_ID); 972 if (InitCheck() == B_OK) 973 memcpy(Bits(), source.Bits(), min_c(BitsLength(), source.BitsLength())); 974 975 return *this; 976 } 977 978 979 status_t 980 BBitmap::Perform(perform_code d, void* arg) 981 { 982 return BArchivable::Perform(d, arg); 983 } 984 985 // FBC 986 void BBitmap::_ReservedBitmap1() {} 987 void BBitmap::_ReservedBitmap2() {} 988 void BBitmap::_ReservedBitmap3() {} 989 990 991 #if 0 992 // get_shared_pointer 993 /*! \brief ??? 994 */ 995 char* 996 BBitmap::get_shared_pointer() const 997 { 998 return NULL; // not implemented 999 } 1000 #endif 1001 1002 int32 1003 BBitmap::_ServerToken() const 1004 { 1005 return fServerToken; 1006 } 1007 1008 1009 /*! \brief Initializes the bitmap. 1010 \param bounds The bitmap dimensions. 1011 \param colorSpace The bitmap's color space. 1012 \param flags Creation flags. 1013 \param bytesPerRow The number of bytes per row the bitmap should use. 1014 \c B_ANY_BYTES_PER_ROW to let the constructor choose an appropriate 1015 value. 1016 \param screenID ??? 1017 */ 1018 void 1019 BBitmap::_InitObject(BRect bounds, color_space colorSpace, uint32 flags, 1020 int32 bytesPerRow, screen_id screenID) 1021 { 1022 //printf("BBitmap::InitObject(bounds: BRect(%.1f, %.1f, %.1f, %.1f), format: %ld, flags: %ld, bpr: %ld\n", 1023 // bounds.left, bounds.top, bounds.right, bounds.bottom, colorSpace, flags, bytesPerRow); 1024 1025 // TODO: Should we handle rounding of the "bounds" here? How does R5 behave? 1026 1027 status_t error = B_OK; 1028 1029 #ifdef RUN_WITHOUT_APP_SERVER 1030 flags |= B_BITMAP_NO_SERVER_LINK; 1031 #endif // RUN_WITHOUT_APP_SERVER 1032 1033 _CleanUp(); 1034 1035 // check params 1036 if (!bounds.IsValid() || !bitmaps_support_space(colorSpace, NULL)) { 1037 error = B_BAD_VALUE; 1038 } else { 1039 // bounds is in floats and might be valid but much larger than what we 1040 // can handle the size could not be expressed in int32 1041 double realSize = bounds.Width() * bounds.Height(); 1042 if (realSize > (double)(INT_MAX / 4)) { 1043 fprintf(stderr, "bitmap bounds is much too large: " 1044 "BRect(%.1f, %.1f, %.1f, %.1f)\n", 1045 bounds.left, bounds.top, bounds.right, bounds.bottom); 1046 error = B_BAD_VALUE; 1047 } 1048 } 1049 if (error == B_OK) { 1050 int32 bpr = get_bytes_per_row(colorSpace, bounds.IntegerWidth() + 1); 1051 if (bytesPerRow < 0) 1052 bytesPerRow = bpr; 1053 else if (bytesPerRow < bpr) 1054 // NOTE: How does R5 behave? 1055 error = B_BAD_VALUE; 1056 } 1057 // allocate the bitmap buffer 1058 if (error == B_OK) { 1059 // TODO: Let the app_server return the size when it allocated the bitmap 1060 int32 size = bytesPerRow * (bounds.IntegerHeight() + 1); 1061 1062 if ((flags & B_BITMAP_NO_SERVER_LINK) != 0) { 1063 fBasePointer = (uint8*)malloc(size); 1064 if (fBasePointer) { 1065 fSize = size; 1066 fColorSpace = colorSpace; 1067 fBounds = bounds; 1068 fBytesPerRow = bytesPerRow; 1069 fFlags = flags; 1070 } else 1071 error = B_NO_MEMORY; 1072 } else { 1073 // Ask the server (via our owning application) to create a bitmap. 1074 BPrivate::AppServerLink link; 1075 1076 // Attach Data: 1077 // 1) BRect bounds 1078 // 2) color_space space 1079 // 3) int32 bitmap_flags 1080 // 4) int32 bytes_per_row 1081 // 5) int32 screen_id::id 1082 link.StartMessage(AS_CREATE_BITMAP); 1083 link.Attach<BRect>(bounds); 1084 link.Attach<color_space>(colorSpace); 1085 link.Attach<uint32>(flags); 1086 link.Attach<int32>(bytesPerRow); 1087 link.Attach<int32>(screenID.id); 1088 1089 if (link.FlushWithReply(error) == B_OK && error == B_OK) { 1090 // server side success 1091 // Get token 1092 link.Read<int32>(&fServerToken); 1093 1094 uint8 allocationFlags; 1095 link.Read<uint8>(&allocationFlags); 1096 link.Read<area_id>(&fServerArea); 1097 link.Read<int32>(&fAreaOffset); 1098 1099 BPrivate::ServerMemoryAllocator* allocator 1100 = BApplication::Private::ServerAllocator(); 1101 1102 if ((allocationFlags & kNewAllocatorArea) != 0) { 1103 error = allocator->AddArea(fServerArea, fArea, 1104 fBasePointer, size); 1105 } else { 1106 error = allocator->AreaAndBaseFor(fServerArea, fArea, 1107 fBasePointer); 1108 if (error == B_OK) 1109 fBasePointer += fAreaOffset; 1110 } 1111 1112 if ((allocationFlags & kFramebuffer) != 0) { 1113 // The base pointer will now point to an overlay_client_data 1114 // structure bytes per row might be modified to match 1115 // hardware constraints 1116 link.Read<int32>(&bytesPerRow); 1117 size = bytesPerRow * (bounds.IntegerHeight() + 1); 1118 } 1119 1120 if (fServerArea >= B_OK) { 1121 fSize = size; 1122 fColorSpace = colorSpace; 1123 fBounds = bounds; 1124 fBytesPerRow = bytesPerRow; 1125 fFlags = flags; 1126 } else 1127 error = fServerArea; 1128 } 1129 1130 if (error < B_OK) { 1131 fBasePointer = NULL; 1132 fServerToken = -1; 1133 fArea = -1; 1134 fServerArea = -1; 1135 fAreaOffset = -1; 1136 // NOTE: why not "0" in case of error? 1137 fFlags = flags; 1138 } else { 1139 BAutolock _(sBitmapListLock); 1140 sBitmapList.AddItem(this); 1141 } 1142 } 1143 fWindow = NULL; 1144 } 1145 1146 fInitError = error; 1147 1148 if (fInitError == B_OK) { 1149 // clear to white if the flags say so. 1150 if (flags & (B_BITMAP_CLEAR_TO_WHITE | B_BITMAP_ACCEPTS_VIEWS)) { 1151 if (fColorSpace == B_CMAP8) { 1152 // "255" is the "transparent magic" index for B_CMAP8 bitmaps 1153 // use the correct index for "white" 1154 memset(fBasePointer, 65, fSize); 1155 } else { 1156 // should work for most colorspaces 1157 memset(fBasePointer, 0xff, fSize); 1158 } 1159 } 1160 // TODO: Creating an offscreen window with a non32 bit bitmap 1161 // copies the current content of the bitmap to a back buffer. 1162 // So at this point the bitmap has to be already cleared to white. 1163 // Better move the above code to the server so the problem looks more 1164 // clear. 1165 if (flags & B_BITMAP_ACCEPTS_VIEWS) { 1166 fWindow = new(std::nothrow) BWindow(Bounds(), fServerToken); 1167 if (fWindow) { 1168 // A BWindow starts life locked and is unlocked 1169 // in Show(), but this window is never shown and 1170 // it's message loop is never started. 1171 fWindow->Unlock(); 1172 } else 1173 fInitError = B_NO_MEMORY; 1174 } 1175 } 1176 } 1177 1178 1179 /*! \brief Cleans up any memory allocated by the bitmap and 1180 informs the server to do so as well (if needed). 1181 */ 1182 void 1183 BBitmap::_CleanUp() 1184 { 1185 if (fWindow != NULL) { 1186 if (fWindow->Lock()) 1187 delete fWindow; 1188 fWindow = NULL; 1189 // this will leak fWindow if it couldn't be locked 1190 } 1191 1192 if (fBasePointer == NULL) 1193 return; 1194 1195 if ((fFlags & B_BITMAP_NO_SERVER_LINK) != 0) { 1196 free(fBasePointer); 1197 } else if (fServerToken != -1) { 1198 BPrivate::AppServerLink link; 1199 // AS_DELETE_BITMAP: 1200 // Attached Data: 1201 // 1) int32 server token 1202 link.StartMessage(AS_DELETE_BITMAP); 1203 link.Attach<int32>(fServerToken); 1204 link.Flush(); 1205 1206 // The server areas are deleted via kMsgDeleteServerMemoryArea message 1207 1208 fArea = -1; 1209 fServerToken = -1; 1210 fAreaOffset = -1; 1211 1212 BAutolock _(sBitmapListLock); 1213 sBitmapList.RemoveItem(this); 1214 } 1215 fBasePointer = NULL; 1216 } 1217 1218 1219 void 1220 BBitmap::_AssertPointer() 1221 { 1222 if (fBasePointer == NULL && fServerArea >= B_OK && fAreaOffset == -1) { 1223 // We lazily clone our own areas - if the bitmap is part of the usual 1224 // server memory area, or is a B_BITMAP_NO_SERVER_LINK bitmap, it 1225 // already has its data. 1226 fArea = clone_area("shared bitmap area", (void**)&fBasePointer, 1227 B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA, fServerArea); 1228 } 1229 } 1230 1231 1232 void 1233 BBitmap::_ReconnectToAppServer() 1234 { 1235 BPrivate::AppServerLink link; 1236 1237 link.StartMessage(AS_RECONNECT_BITMAP); 1238 link.Attach<BRect>(fBounds); 1239 link.Attach<color_space>(fColorSpace); 1240 link.Attach<uint32>(fFlags); 1241 link.Attach<int32>(fBytesPerRow); 1242 link.Attach<int32>(0); 1243 link.Attach<int32>(fArea); 1244 link.Attach<int32>(fAreaOffset); 1245 1246 status_t error; 1247 if (link.FlushWithReply(error) == B_OK && error == B_OK) { 1248 // server side success 1249 // Get token 1250 link.Read<int32>(&fServerToken); 1251 1252 link.Read<area_id>(&fServerArea); 1253 } 1254 } 1255