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