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