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