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